Stack Frame
firstly, callee stack save the old caller ‘s stack ‘s ebp
lastly, the argument build means the arguments for calling any other function
pushl $zip2,$zip1 把参数压进栈顶,然后call swap,会把caller的return address压入栈
whole code
set up code
一. push %ebp 把caller的 bast pointer 的数值压栈
二.movl %esp,%ebp (把esp 移动到ebp,即设置ebp = esp,这一步是设置callee的base pointer)
三.%ebx 是swap过程中可能会调用的参数
https://www.cnblogs.com/qq78292959/archive/2012/07/20/2600865.html
附上:EAX 是”累加器”(accumulator), 它是很多加法乘法指令的缺省寄存器。
EBX 是”基地址”(base)寄存器, 在内存寻址时存放基地址。
ECX 是计数器(counter), 是重复(REP)前缀指令和LOOP指令的内定计数器。
EDX 则总是被用来放整数除法产生的余数。
但是对于 %eax,%ecx,%edx 不能像ebx一样,保存在callee中
body code
finish code
- %ebp-4 就是 old %ebx 的地址 ,把-4(%ebp)移到%ebx,相当于把原来的%ebx复原
2.第二是 把 %ebp 移到 %esp,即现在%esp指向%ebp
(第一第二条指令相当于 pop %ebx)
3.popl %ebp
本质上是1
20(%esp),%ebp
%esp +4
这个时候base pointer复原,变回caller stack 的数值
4.ret 根据返回地址返回
其中leave instruction
等价于
mov %ebp,%esp
popl %ebp
register saving convention
yoo当中,我们希望%edx不会因为调用了who函数之后发生改变,问题是,who调用过程中,%edx是可能发生改变的。
因此我们要制定convention,在使用这些寄存器之前先保存他们!
分类如下
%eax save the return address so it is caller saved register
example
1 | 1.pushl %ebp #save the caller's ebp |
两个pushl 相当于把 s_helper函数的两个参数传了进去
&val始终指向val,当函数结束的时候,返回的值就保存在了-4(%ebp)当中
Summary
1.若调用函数有多个参数,stack从下到上,依次为第一个,第二个函数。
2.函数调用的参数在stack的上方,就是在caller准备好参数后再调用callee,就是说argument 是caller saved 的
3.函数结果返回在%eax
4.local variable 是存放在 callee-saved registers那里
x86-64 conventions
在x86 中,由于registers 的数目变多,因此可以把local variable 和argument存储在register当中,那样就可以减少对stack 的使用了
下图是16个 8-byte gpr
黄色的是caller saved
绿色的是 callee saved
specifications
1.用callq 而不用call,因为要返回一个64-bit address,also decrement 8而不是4(8 bytes)
2.因为gpr实现了ebp / rbp 功能,因此不需要使用stack来更新 ,而且rsp能代替实现frame pointer 的功能
3.由于gpr只有6个argument register,所以当函数参数少于六个的时候,不需要用到栈结构
example
q - 8byte - 64bits
l - 4byte - 32bits
w - 2byte - 16bits
b - 1byte - 8bits
prepare for the arguments
1 | movq $1,%rdi |
1 | movswl 28(%rsp),%eax # %eax = x3 |