cmu15213 L7 Machine-Level Programming III: Procedures
ABI (application binary interface)应用程序二进制接口
文章目录

Procedures
Mechanisms





Stack Structure



教授提到他也不知道为啥栈要倒着这样画hhhh,栈的画法是高地址在上,低地址在下,栈顶是低地址,栈从高地址向低地址扩展。

入栈的时候 %rsp 减 8,即栈指针向低地址移动。

执行顺序是先把 %rsp 减 8 ,然后再把要存的书写到 %rsp 对应的地址中。(要先减指针,再写)

popq 的话是先读 %rsp 地址中的数,然后 %rsp 减 8,再把数存到寄存器中。(先读,后增加指针)


Calling Conventions
Passing control

参数依次存放在 %rdi,%rsi,%rdx 中,函数的返回结果存放在 %rax 中。

call,ret 这两个指令并没有完成过程调用与返回的全部任务,只完成了控制部分,而这一部分只是过程调用的三个方面之一。
有时候还会看到 rep;ret ,可以直接忽略掉。


执行 callq 之前,栈顶指针 %rsp=0x120 ,当前执行指令指针 %rip=0x400544
callq 会执行三件事情(-8 是因为地址是 64 位的,并且 push 和 pop 也只支持 64 位操作):
- 减少栈指针(-8),即
%rsp从0x120变为0x118 - 将
callq下面语句的地址(callq下面的mov地址为0x400549)存到%rsp指向的内存中,即栈顶。这个地址即为返回时需要继续执行的地址。 - 将
%rip置成调用函数所在的地址(0x400550,这是call的隐式操作,我们并不能直接操作%rip的值)


retq 则执行和 call 相反的操作:
- 首先读取栈顶的元素,即为返回地址
- 栈顶指针
%rsp加 8 - 将返回地址给
%rip这样就到了原来call之后需要执行的语句了
Passing data


Managing local data


%rbp 是可选的,他不一定被用作栈基指针,一般会当成一个普通的寄存器来用。








这里栈会多分配一点,是为了对齐。

long 是 8 字节,这里用 movl $3000, %esi 实际上只是用了四个字节,并且用的不是 %rsi 而是 %esi,此时 %rsi 的高 32 位会自动置零。编译器喜欢这么干的原因是 movl 的编码比 movq 的编码少一个字节。









这些寄存器是 caller-saved,意思是在调用函数之前要把这些寄存器压栈,调用函数后再恢复这些寄存器,而在被调用的函数中可以随意修改这些寄存器(因为他们已经在调用前被储存了起来)。

这些是 callee-saved ,意思是在被调用的函数中,假如想要使用这些寄存器的话,要先把他们压栈,函数结束后再恢复他们。








Illustration of Recursion

testq a, b 就是测试 a&b





%rbx 是 calle-svaed,所以在使用这个寄存器之前要 push,调用完子函数后要再恢复 %rbx


浙公网安备 33010602011771号