Bla*_*iev 18
考虑这段代码:
int foo (int a, int b) {
return a + b;
}
int main (void) {
foo(3, 5);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译它gcc foo.c -S给出了程序集输出:
foo:
pushl %ebp
movl %esp, %ebp
movl 12(%ebp), %eax
movl 8(%ebp), %edx
leal (%edx,%eax), %eax
popl %ebp
ret
main:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
movl $5, 4(%esp)
movl $3, (%esp)
call foo
movl $0, %eax
leave
ret
Run Code Online (Sandbox Code Playgroud)
所以基本上调用者(在这种情况下main)首先在堆栈上分配8个字节以容纳两个参数,然后将两个参数放在堆栈上相应的偏移量(4和0),然后call发出指令将控制转移到foo常规.该foo程序堆栈,从相应的偏移读取它的参数,还原它,并把它的返回值的eax寄存器,所以它提供给调用者.
这是特定于平台的,也是"ABI"的一部分.事实上,一些编译器甚至允许您在不同的约定之间进行选择.
例如,Microsoft的Visual Studio提供了__fastcall调用约定,该约定使用寄存器.其他平台或调用约定仅使用堆栈.
变量参数以非常类似的方式工作 - 它们通过寄存器或堆栈传递.在寄存器的情况下,它们通常按照类型的升序排列.如果你有类似的东西(int a,int b,float c,int d),那么PowerPC ABI可能放在ar3,br4,dr5和cfp1中(我忘记了float寄存器开始的地方,但你明白了) .
返回值再次以相同的方式工作.
不幸的是,我没有很多例子,我的大部分程序集都在PowerPC中,你在程序集中看到的只是代码直接用于r3,r4,r5,并将返回值放在r3中.
您的问题比任何人都可以在 SO 帖子中合理尝试回答的问题要多,更不用说它的实现也已定义。但是,如果您对 x86 答案感兴趣,我建议您观看题为“编程范式
”的斯坦福 CS107 讲座,其中您提出的问题的所有答案都将在前 6-8 个讲座中详细(而且非常雄辩地)解释。
| 归档时间: |
|
| 查看次数: |
5067 次 |
| 最近记录: |