Passing parameters and return values ​​for a subroutine in an assembly

I work with an ARM assembly where I need to write one subroutine for which I follow the ARM calling convention (this should be integrated with some separate higher-level implementation somewhere else) to pass parameters and return values.

Now I'm not quite sure when I work with the assembly.

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

Now here's what I'm confused with. If I have to save the r0 context and pull it out after, then there is no way to return the result, the only way to do this is to spoil the first argument.

Is there any workaround?

+9
source share
3 answers

When you return the return value to r0, the caller expects you to do this. The caller does not expect r0 to still contain the same value as the original first parameter, because r0 is specific where the value is returned.

Typically, an ARM calling convention requires the routine to store from r4 to r11 , not from r0 to r3. So there is no contradiction.

+7
source

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

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

compile object and disassemble

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

and result

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

Two inputs a and b are transmitted using r0 and r1. r0-r4 does not need to be stored, in particular r0, because this return value cannot be saved. Since the C code required two operands to be added together, and since the call requirement requires the result to return to r0. r0 = r0 + r1.

The compiler must comply with the convention, otherwise the code that it creates does not work, so you can simply compile the code and parse it to find out a little about the calling convention for a specific compiler and purpose.

+6
source

If I have to save the r0 context and pull it out after

This sounds like confusion caused by the term “saved subscriber” . This incorrectly implies that the caller must save / restore each such register, instead of simply destroying it with a function call (in which case, replace it with the return value).

I like the terms call-clobbered versus call-preserved: What are saved caller and caller registers?

If you have a value that you want to save when calling a function, just save it in a different register, which is saved in accordance with the calling convention, instead of doing a save / restore for each function call.

0
source

All Articles