Assembly Code


61 posts   Page 1 of 3   1, 2, 3
by antiloquax » Wed May 09, 2012 3:39 pm
I haven't done any assembly coding before, but I wanted to have a go.

Can anyone offer some help or point me to some good information?

I have found some online tutorials, but when I try to use "as" to assemble to code, I get errors.

Also, I need a simple explanation of how to run the programs.

mark
Posts: 406
Joined: Sun Nov 20, 2011 11:37 am
by jamesh » Wed May 09, 2012 3:58 pm
There is a load of documentation on the Arm website, and I seem to remember finding a good PDF on Arm assembler programming from somewhere on the net. I posted a link to it in the forum, but I have no idea where - try a forum search on Arm Assembler.
Unemployed software engineer currently specialising in camera drivers and frameworks, but can put mind to most embedded tasks. Got a job in N.Cambridge or surroundings? I'm interested!
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 11677
Joined: Sat Jul 30, 2011 7:41 pm
by tufty » Wed May 09, 2012 5:25 pm
Going to the arm website is a good start, getting hold of a copy of the armv7a-arm is essential. You need to understand how the C calling convention works to interop with any C libraries or code. It"s not hard but tricky to get your head around. I"d suggest starting by mixing C with bits of assembler here and there.

For your errors, post them up and I"m sure we can work out the cause.

Simon
Posts: 1367
Joined: Sun Sep 11, 2011 2:32 pm
by cheery » Wed May 09, 2012 5:45 pm
I've done only x86 assembly before, but the ARM assembly isn't probably too hard either.

If you don't want to play with C, I guess you might find software interrupt (SWI) calls somewhere. My guess is that they can be found from /usr/include/asm/unistd.h

Next you'd need to know how to do a linux system call in ARM assembly.

Also, if you have some assembler errors, please paste them somewhere. It'll help a bit to know what you're exactly trying to do, too.
User avatar
Posts: 219
Joined: Wed Jan 25, 2012 9:39 pm
by antiloquax » Wed May 09, 2012 5:59 pm
Thanks for the tips.

I'll investigate the C approach. Basically I just want to do something very simple to start with - just adding some numbers or "hello world"!

I'll post back with how I get on.

mark
Posts: 406
Joined: Sun Nov 20, 2011 11:37 am
by johnbeetem » Wed May 09, 2012 6:11 pm
Here's a useful RasPi forum thread on ARM Assembler, including very helpful links such as one to the tutorial JamesH mentions.

I haven't used the GNU "as" assembler for ARM personally, but I think it may use non-standard ASM notation.  I strongly recommend writing some C and compiling it with the option that saves the generated assembly language so you can see what's up.  Also, run C with the "verbose" option so you can see what options it uses when calling "as".

I don't think you need to do direct systems calls under GNU. You should be able to call normal C Libary functions, once you know which Application Binary Interface conventions to use.  The ARM website has lots of documentation on ABIs, including the ones you don't want to use :-)
User avatar
Posts: 942
Joined: Mon Oct 17, 2011 11:18 pm
Location: The Coast
by tufty » Wed May 09, 2012 6:59 pm
I'm using the following arguments to as:

as -g -mcpu=arm1176jzf-s -I<include path here> -o foo.o foo.s

GNU assembler documentation can be found here : http://sourceware.org/binutils/docs-2.22/as/index.html

Calling conventions are a little convoluted once you get past simple functions with a small number of parameters or anything that passes floats about.  Chapter and verse here : http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042d/IHI0042D_aapcs.pdf

Simon
Posts: 1367
Joined: Sun Sep 11, 2011 2:32 pm
by antiloquax » Sun May 13, 2012 6:36 am
Thanks again! I found those links and tips useful.
mark
Posts: 406
Joined: Sun Nov 20, 2011 11:37 am
by antiloquax » Fri May 18, 2012 12:11 pm
I haven't made very much progress as yet with Assembly Code, despite looking at a few websites. I thought I'd try getting some output from GCC and having a look at that.
Here's the little C program I used:
Code: Select all
int main(int argc, char *argv[])
{
    int num1;
    int num2;
    int ans;
   
    num1 = 10;
    num2 = 20;

    ans = num1 + num2;

    return 0;


And here's the output I got from running "gcc -S":
Code: Select all
   .cpu arm10tdmi
   .fpu softvfp
   .eabi_attribute 20, 1
   .eabi_attribute 21, 1
   .eabi_attribute 23, 3
   .eabi_attribute 24, 1
   .eabi_attribute 25, 1
   .eabi_attribute 26, 2
   .eabi_attribute 30, 6
   .eabi_attribute 18, 4
   .file   "add.c"
   .text
   .align   2
   .global   main
   .type   main, %function
main:
   @ args = 0, pretend = 0, frame = 24
   @ frame_needed = 1, uses_anonymous_args = 0
   @ link register save eliminated.
   str   fp, [sp, #-4]!
   add   fp, sp, #0
   sub   sp, sp, #28
   str   r0, [fp, #-24]
   str   r1, [fp, #-28]
   mov   r3, #10
   str   r3, [fp, #-8]
   mov   r3, #20
   str   r3, [fp, #-12]
   ldr   r2, [fp, #-8]
   ldr   r3, [fp, #-12]
   add   r3, r2, r3
   str   r3, [fp, #-16]
   mov   r3, #0
   mov   r0, r3
   add   sp, fp, #0
   ldmfd   sp!, {fp}
   bx   lr
   .size   main, .-main
   .ident   "GCC: (GNU) 4.6.3"
   .section   .note.GNU-stack,"",%progbits

I am going to take the time later to go through this and work out how the assembly code works. In the mean-time, if anyone can give me some tips, I'd appreciate the help.
mark
Posts: 406
Joined: Sun Nov 20, 2011 11:37 am
by Gert van Loo » Fri May 18, 2012 12:35 pm
It move the stack pointer to the frame pointer.
The changes the stack pointer to make place on it.
Save registers r0,r1 on the stack.
Then does some tremendously wasteful work by putting constants on the stack, then back in the registers then doing the add them and puts the result back on the stack.
Finally sets the return in R0 (but first waste time putting it in R3), restores the stack from the FP and returns.
I think it can all be done by:
mov r2,#10
mov r3,#20
add r2,r2,r3
mov r0,#0
bx lr
User avatar
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 2036
Joined: Tue Aug 02, 2011 7:27 am
by antiloquax » Fri May 18, 2012 2:18 pm
Thanks Gert. I think I'll be able to make a bit more sense of some of the online tutorials now I can see a bit of assembly code that the compiler has produced.
mark
Posts: 406
Joined: Sun Nov 20, 2011 11:37 am
by Narishma » Fri May 18, 2012 6:58 pm
antiloquax wrote:Thanks Gert. I think I'll be able to make a bit more sense of some of the online tutorials now I can see a bit of assembly code that the compiler has produced.
mark

Here's a nice and free introductory book on the subject.
http://savannah.nongnu.org/projects/pgubook/
It uses x86 assembler but the basics are the same regardless of what variant you're using.
Posts: 151
Joined: Wed Nov 23, 2011 1:29 pm
by Narishma » Fri May 18, 2012 7:00 pm
Gert van Loo wrote:It move the stack pointer to the frame pointer.
The changes the stack pointer to make place on it.
Save registers r0,r1 on the stack.
Then does some tremendously wasteful work by putting constants on the stack, then back in the registers then doing the add them and puts the result back on the stack.
Finally sets the return in R0 (but first waste time putting it in R3), restores the stack from the FP and returns.
I think it can all be done by:
mov r2,#10
mov r3,#20
add r2,r2,r3
mov r0,#0
bx lr

The code produced by GCC is wasteful because by default it doesn't do ANY optimizations until you tell it to. Try compiling it with -O2 or -O3 and see some of the magic it does. I wouldn't be surprised if it removes the whole function in this case.
Posts: 151
Joined: Wed Nov 23, 2011 1:29 pm
by antiloquax » Sat May 19, 2012 6:58 am
Thanks Narishma, I am now reading "Programming from the ground up" and things are making a lot more sense.
I am a teacher in a UK high school and I'm hoping to be teaching Computer Science GCSE next year. This book has lots of very helpful information. I found the explanation of registers really helpful.
mark
Posts: 406
Joined: Sun Nov 20, 2011 11:37 am
by gadgetoid » Sun May 20, 2012 5:23 pm
I've been reading the Programming From The Ground Up book, too, and have had some trouble converting the Assembly syntax into something that works for ARM. I worked most of it out eventually, but got stuck on:
Code: Select all
movl data_items(,%edi,4), %eax

This is used to access data_items, using register %edi with a multiplier? of 4, and place it into %eax. The data_items is expressed thusly:
Code: Select all
data_items:
.long 3,67,34,222,45,75,54,34,44,33,22,11,66,0

As near as I can tell, this loosely translates into:
Code: Select all
mov %r0, data_items(,%r3,4)

Where %r3 is picked at random as my counter, initialised to zero and incremented in the loop.

Unfortunately, this doesn't work!

Does anyone have any idea how this should work in ARM Assembly? Thanks.
Posts: 74
Joined: Wed Mar 07, 2012 9:58 pm
by funnel » Sun May 20, 2012 5:48 pm
I think you need to first load the data_item address to a register. Something like this:

LDR R0, =data_items
LDR R1, [R0,R3,LSL #2]

R3 is your random number from the loop. The data_items is assumed to be 32 bit numbers. You move through the list with nr.<<2 (move by 4 bytes).

An expert should confirm this because I'm still learning too.
Posts: 46
Joined: Sat May 05, 2012 8:00 am
by DexOS » Sun May 20, 2012 6:30 pm
My advice is if you want to code in asm, use a assembler, not a compiler ( yes gcc has got a assembler, as its back end).

You need to keep it simple, make sure the tut your learning from is for the assembler your using.

Best one i have found is Fasm, theres a ver to out put, for the ARM processor.
Called FasmArm
example code:
Code: Select all
        format ELF executable
        entry start

        segment readable executable

start:  mov     r0,0
        add     r1,pc,hello-$-8
        mov     r2,hello_len
        swi     0x900004
        mov     r0,6
        swi     0x900001

hello:  db      'Hello world',10
hello_len=$-hello

        ;dummy section for bss, see http://board.flatassembler.net/topic.php?t=3689
        segment writeable                             

To assemble is simple
FasmArm myfile.asm <enter>

You can get it here: http://arm.flatassembler.net/

As a side note: ASM is very powerful and can be made in to any language you want, which is good for teaching kids etc.

Here is another example of ASM that may be easier for kids to learn
Code: Select all
include 'FBasic_L.inc'
CLS
COLOR  11
LOCATE 2,1
PRINT "This app is written in Macro Basic, for Linux "
COLOR  12
LOCATE 2,2
PRINT "With the ease of Basic and the power of ASM "
COLOR  15
LOCATE 2,3
PRINT "It user's the basic commands:"
PRINT " "
PRINT "    CLS"
PRINT "    SCREEN"
PRINT "    COLOR"
PRINT "    LOCATE"
PRINT "    PRINT"
PRINT "    GOSUB"
PRINT "    RETURN"
PRINT "    SLEEP"
PRINT "    END"
PRINT " "
GOSUB TestSub
SLEEP
END

TestSub:
PRINT "  Press any key to quit."
RETURN                                               

Try doing that in C :shock:
Batteries not included, Some assembly required.
User avatar
Posts: 860
Joined: Wed May 16, 2012 6:32 pm
by gadgetoid » Sun May 20, 2012 6:39 pm
I've been using "as" which is presumably an assembler?

I finally got it working, interestingly the solution I eventually came across was the same as that from funnel (thanks, your suggestion would have saved my poor brain if I hadn't found it by sheer determination alone)

I humbly submit my code for finding the largest number in a list on ARM, hopefully this will be mildly educational to someone:

Code: Select all
.data
    data_items:
    .long 3,67,34,222,45,75,54,34,44,33,22,11,66,0

.text
    .globl _start

_start:
    ldr     %r4,=data_items         @ Load address of data_items into r4
    mov     %r5,$0                  @ Start our r5 counter at 0
    ldr     %r0,[%r4,%r5,LSL $2]    @ Load from data_items r4 with offset r5 and multiplier of 2

start_loop:
    cmp     %r1,$0                  @ Check r1 for end of list 0
    beq     loop_exit

    add     %r5,%r5,$1              @ Increment our loop
    ldr     %r1,[%r4,%r5,LSL $2]    @ Load the next data_items into r1

    cmp     %r1,%r0                 @ Compare
    ble     start_loop              @ Check of less or equal
   
    mov     %r0,%r1                 @ Move r1 to r0 if its greater
   
    b       start_loop

loop_exit:
    mov     %r1,$0
    mov     %r4,$0
    mov     %r5,$0
    mov     %r7,$1
    svc     $0
Posts: 74
Joined: Wed Mar 07, 2012 9:58 pm
by antiloquax » Sun May 20, 2012 7:39 pm
Many thanks to gadgetoid and the others who have offered help on this. I had been playing around with "b" to replace the jump commands, but I was stumped by how to get the numbers from the array into a register.
I certainly know a lot more now than I did this morning! :)
mark
Posts: 406
Joined: Sun Nov 20, 2011 11:37 am
by tufty » Sun May 20, 2012 7:42 pm
gadgetoid wrote:I've been using "as" which is presumably an assembler?

Yep, sure is. It's the GNU assembler.

Comments on your code :
- You don't need the % in front of the register names, and you can use C format (0xdeadc0de) for your hex numbers if you don't like using $.
- You probably want a .code 32 at the start of your text section

Dex - presumably your "teaching assembler through basic by totally removing any traces of recognisable assembler" doesn't require - umm - yknow - a massive include file? No, don't answer that. I could give you examples of half a dozen fully fledged programming languages written in C that are smaller than your x86 include file. I could get 5 garbage collected lisp interpreters into that space, for example ;)
Posts: 1367
Joined: Sun Sep 11, 2011 2:32 pm
by gadgetoid » Sun May 20, 2012 8:31 pm
Oo, would be nice to drop the % and the $, both have been irritating to say the least. The latter because $n is in my vimrc as a shortcut for blocks of parenthesis... so occasionally it'll explode my code if I type too fast.

What would .code 32 do?
Posts: 74
Joined: Wed Mar 07, 2012 9:58 pm
by DexOS » Sun May 20, 2012 8:58 pm
tufty wrote:
gadgetoid wrote:I've been using "as" which is presumably an assembler?

Yep, sure is. It's the GNU assembler.

Comments on your code :
- You don't need the % in front of the register names, and you can use C format (0xdeadc0de) for your hex numbers if you don't like using $.
- You probably want a .code 32 at the start of your text section

Dex - presumably your "teaching assembler through basic by totally removing any traces of recognisable assembler" doesn't require - umm - yknow - a massive include file? No, don't answer that. I could give you examples of half a dozen fully fledged programming languages written in C that are smaller than your x86 include file. I could get 5 garbage collected lisp interpreters into that space, for example ;)


I am afraid you have shown a lack of knowledge of how ASM macros works.
The macro name you place in your asm file is replaced by the assembly code, if you do not use the macro (eg: print) it is not included so you can have a 1000 macro in the include file and the assembled file will be know bigger than the same file written in normal asm (without using macros).

And yes you start them off with the basic like language and them start introducing them to asm code as they learn more.

Remember ASM is your friend learn to use it ;)
Batteries not included, Some assembly required.
User avatar
Posts: 860
Joined: Wed May 16, 2012 6:32 pm
by tufty » Mon May 21, 2012 6:10 am
gadgetoid wrote:What would .code 32 do?

Tells the assembler that you're writing in ARM and not Thumb code.

DexOS wrote:I am afraid you have shown a lack of knowledge of how ASM macros works.

I understand perfectly how assembler macros work, thank you very much. When I said
tufty wrote:doesn't require - umm - yknow - a massive include file?

I was referring to the line in your code as follows
Code: Select all
include 'FBasic_L.inc'

which has a large include file hiding behind it, defining the language. As the one defining your language for x86 is 28.5K long, and ARM code is generally more verbose than x86, I'd suggest that it qualifies as a "massive include file".

As an aside, really large macros are generally best avoided, especially if you're flying without the safety net of compiling to separate chunks of object code and linking afterwards - they can, depending on the assembler, exponentially expand the memory footprint of the assembly stage. Pulling stuff down to separate compilation units is almost always a good idea.

Simon
Posts: 1367
Joined: Sun Sep 11, 2011 2:32 pm
by antiloquax » Mon May 21, 2012 7:11 am
One of the problems that I was having with ASM previously was the fact that gas uses AT&T syntax, whereas most of the tutorial documents I had been looking at use Intel.
I've read (on Wikipedia) that gas will accept Intel syntax if you add the instruction:
Code: Select all
.intel_syntax

I'm going to have another go at writing some ASM code today, if I have any spare time ...
:D
Posts: 406
Joined: Sun Nov 20, 2011 11:37 am
by rurwin » Mon May 21, 2012 8:04 am
DexOS wrote:And yes you start them off with the basic like language and them start introducing them to asm code as they learn more.

Wouldn't it be easier to teach them C with embedded assembler?
Code: Select all
static bool GetSema(int ms, long* pSema)
{
   double   StartTime   = Time;

WaitForSema:
   __asm   push      eax
   __asm   push      edi
   __asm   mov      eax,1
   __asm   mov      edi,pSema      // lock         
   __asm   xchg      0[edi],eax
   __asm   or      eax,eax
   __asm   pop      edi
   __asm   pop      eax
   __asm   jz      UseIt         // got semaphore
   
   sleep(1);
   if ( (Time - StartTime)*1000 > (double)ms )
   {
      return false;
   }
   __asm   jmp      WaitForSema

UseIt:
   return true;   // success
}

(Yes that's x86. I don't have my Pi yet nor any code for it.)
User avatar
Forum Moderator
Forum Moderator
Posts: 2904
Joined: Mon Jan 09, 2012 3:16 pm