0

I compile c code to arm with this site https://godbolt.org/

int F(int a, int b) 
{
    int c=0;
    for(int i=0;i<=10;i++)
    {
        c+=a+b;
    }    
    return c;
}

the result was

F(int, int):
        str     fp, [sp, #-4]!
        add     fp, sp, #0
        sub     sp, sp, #20
        str     r0, [fp, #-16]
        str     r1, [fp, #-20]
        mov     r3, #0
        str     r3, [fp, #-8]
        mov     r3, #0
        str     r3, [fp, #-12]
.L3:
        ldr     r3, [fp, #-12]
        cmp     r3, #10
        bgt     .L2
        ldr     r2, [fp, #-16]
        ldr     r3, [fp, #-20]
        add     r3, r2, r3
        ldr     r2, [fp, #-8]
        add     r3, r2, r3
        str     r3, [fp, #-8]
        ldr     r3, [fp, #-12]
        add     r3, r3, #1
        str     r3, [fp, #-12]
        b       .L3
.L2:
        ldr     r3, [fp, #-8]
        mov     r0, r3
        sub     sp, fp, #0
        ldr     fp, [sp], #4
        bx      lr

I saw here that parameters moved on the stack and not via registers.

I have 3 line that I not understand

add     fp, sp, #0
sub     sp, sp, #20
str     r0, [fp, #-16]
  1. why fp get value= 0? I read about fp but I not sure I eral get it.
  2. why sp get down 20? I know it usualy to save plave for the local var, but why 20?
  3. why str r0, [fp, #-16] I not get it

by the way, why the parameters hers pass in the stack and not on registers? thank you all

6

The parameters are passed in Registers r0 (a) and r1 (b); this is a convention defined in the Procedure Call Standard for the ARM Architecture. However, without enabled optimizations, the compiler always stores parameters and local variables in the local stack frame (remember that the stack grown downwards - i.e., towards smaller addresses - on ARM).

 add     fp, sp, #0

This instruction doesn't set fp to 0, but rather to the current value of sp. fp serves as a reference to local information on the stack that remains constant during the execution of F. The old frame pointer, parameters and local variables are then stored at negative offsets from fp.

 sub     sp, sp, #20

Here, 20 Bytes of space are reserved on the stack, so that subsequent stack operations (e.g. calling another function from inside of F) do not modify the local stack frame of your function F.

 str     r0, [fp, #-16]

This copies r0 (Parameter a) into the local stack frame at address fp-16. The complete stack frame looks like this:

 fp- 4: old fp
 fp- 8: local variable c
 fp-12: local variable i
 fp-16: parameter a
 fp-20: parameter b

Note that sp points to fp-20 (since sp is copied to fp at the beginning of the function and sp is then decremented by 20). This is correct, since on ARM processors, the sp always points to the last used element on the stack, i.e. the next push operation decrements sp first (to fp-24) and writes data to the new sp address.

2

It seems you made a few wrong assumptions, possibly due to unfamiliarity with the ARM instruction set. Let's have a look at the instructions one by one.

add     fp, sp, #0

This is an add, so the operation is fp = sp+0, or fp=sp. An analog on x86 would be mov ebp, esp

sub     sp, sp, #20

This would look like sub esp, 20h on x86. Basically, it allocates 0x20 bytes of stack space for local variables.

str     r0, [fp, #-16]

Unlike most ARM instructions, here the left operand (r0) is not the destination, but source. This instruction stores (str) the value of the register r0 at the location fp-0x16. An x86 analog would look like:

mov [ebp-10h], eax

So, as you can see, it does use the value of r0 as an input and only stores it on the stack as a temporary variables (later it retrieved again to perform the addition). The same happens with the second argument in r1. If you add some optimization flags for the compiler (e.g. -O1 or -O2), it's likely that it will manage to perform the operation without having to store intermediate results on the stack. Here's the result I get for -O1 with GCC 7.2.1:

F(int, int):
  add r1, r0, r1
  add r0, r1, r1, lsl #2
  add r0, r1, r0, lsl #1
  bx lr

As you can see, there is no stack involved anymore, and the compiler even managed to convert a loop of additions into an optimized multiplication-add using shifts.

  • How can I compile it so the compiler will not stores parameters and local variables in the local stack frame? – arm Mar 19 '18 at 10:17
  • use optimization flags as I mentioned, however in complex functions the compiler may run out of free registers and fall back to the stack for temporary storage anyway – Igor Skochinsky Mar 19 '18 at 10:20
  • can you give me the full command line you enter to gcc to compile c code to arm 32 bits, (fast call calling convenction) – arm Mar 19 '18 at 10:53
  • any ARM compiler will give you “fastcall” since the standard ARM ABI uses registers for argument passing. anyway, such question is more suited for Stack Overflow since it’s about programming and not RE. – Igor Skochinsky Mar 19 '18 at 11:43
  • I only want get the command line you run on gcc(on win/linux) to compile it for arm 32 bits, I not think to open it new topic on stackOverFlow – arm Mar 19 '18 at 13:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.