Passing parameters and return values for a subroutine in assembly
Asked Answered
N

3

9

I am working with ARM assembly, where I have to write one subroutine for which I am following the ARM calling convention(this will have to be integrated with some separate higher level implementation somewhere else ) for passing parameters and return values.

Now here is something I am not sure in general when working with assembly.

So from the convention if I understand well the arguments are passed in order starting from registers r0 - r4 and then for other arguments stacks are used. Return values are passed to r0.

Now here is what I am confused with. If I am supposed to save the context of r0 and pop it off after then there is no way to return the result, the only way it can be done is by corrupting the first argument.

Is there a workaround somehow?

Numerate answered 19/9, 2012 at 0:20 Comment(0)
S
7

When you pass back the return value in r0, the caller expects that you will do this. The caller does not expect that r0 will still contain the same value as the original first parameter, because r0 is specifically where the return value is.

Normally the ARM calling convention requires that the subroutine preserves r4 through r11, not r0 through r3. So there is no contradiction anyway.

Simonton answered 19/9, 2012 at 0:23 Comment(2)
So I guess it's caller's responsibility to save the context of r0 before it calls the function.Numerate
From the link you posted: "r0 to r3: used to hold argument values passed to a subroutine, and also hold results returned from a subroutine".Desta
T
6

Why not just try this yourself and see what the compiler does?

unsigned int fun ( unsigned int a, unsigned int b )
{
    return(a+b);
}

compile to object and disassemble

arm-none-eabi-gcc -O2 -c fun.c -o fun.o
arm-none-eabi-objdump -D fun.o 

and the result is

00000000 <fun>:
   0:   e0810000    add r0, r1, r0
   4:   e12fff1e    bx  lr

The two inputs a and b are passed in using r0 and r1. r0-r4 do not have to be preserved, in particular r0 because it is the return value cannot be preserved. So as the C code required the two operands are added together, and as the calling convention requires the result is returned in r0. r0 = r0 + r1.

The compiler has to conform to the convention otherwise the code it produces wont work so you can simply compile code and disassemble to find out quite a bit about the calling convention for a particular compiler and target.

Transported answered 19/9, 2012 at 4:11 Comment(0)
B
0

If I am supposed to save the context of r0 and pop it off after

That sounds like confusion caused by the term "caller-saved". It wrongly implies that the caller actually should save/restore every such register, instead of just letting it be destroyed by a function call (and in this case replaced by the return value).

I like the terms "call-clobbered" vs. "call-preserved": What are callee and caller saved registers?

If you have a value that you want to keep around across the function call, simply keep it in a different register, one that's call-preserved by the calling convention, instead of doing a save/restore around each function call.

Brelje answered 25/9, 2019 at 0:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.