menu

秋梦无痕

一场秋雨无梦痕,春夜清风冻煞人。冬来冷水寒似铁,夏至京北蟑满城。

Avatar

X86和ARM函数调用中参数传递和返回值

from: http://treezhao.blogchina.com/blog/refer.310145.html

arm属于RISC指令集,而x86则是CISC指令集的代表,编译器生成的结果比较有代表性。其中,参数传递和返回值是汇编/C混合编程比较关注的部分,尤其是在bootloader中编程中非常重要。总的来说,RISC倾向于寄存器穿参数,而x86则是通过堆栈传参数。而返回值则都通过效率最高的寄存器完成,arm中是r0,x86是eax。

以下的示例是通过写一个简单例子,并且反编译objdump来看生成的汇编来了解这些机制,呵呵,比较实验化,可是也只能这样了,编译技术也不是那么简单就能理解得了的。注意,这样,编译选项影响就可能比较大,我的实验仅局限在加/减-O选项,而其他的比较细节的就无能为力了。不过,这个方法对我理解参数和返回值这点来说,还是比较有效的。

1 返回值:
1) X86采用eax作为返回值。
return i; 2d: 89 c0 mov %eax,%eax

2) ARM使用r0作为返回值。
RETURN I; 4C: E1A00003 MOV R0, R3

2 参数传递
1) X86:主要是采用堆栈,除非指定以寄存器传递(通过"regparm (NUMBER)"注:NUMBER<=3指定)。
如果指定寄存器传递参数,则eax为第一个参数,edx为第二个参数, ecx为第三个参数。
int hello(int );
t=hello(13); 9: 6a 0d push $0xd
b: e8 fc ff ff ff call <hello>
2) ARM:寄存器到堆栈,首先将参数赋给r0, r1等,同时,未经优化的代码,在函数的堆栈中,也会为每个参数预留一个参数堆栈。
ARM的参数结构看起来比较奇怪,对其的解释是:出于效率考虑,如果在函数中的寄存器足够分配的话,则经过优化后,它不会进栈,而直接使用寄存器即可。这样的方式可以保证优化只局限于函数内部,实际上一般使用-O优化过的代码最终普遍在函数中不再进栈的。
int hello(int );
t=hello(13);

未优化: 10: e3a0000d mov r0, #13 ; 0xd
14: ebfffffe bl <hello>
... ...
<hello>
......
3c: e50b0010 str r0, [fp, -#16]
优化后:-O选项
4: e3a0000d mov r0, #13 ;
...
bl <hello>
...
1c: e1a0f00e mov pc, lr

评论已关闭