call和ret

call和ret
内存的物理地址最低总是从0开始。指针指向的最低应该也是0,所以一个四字节的指针应该是指向地址为0-4

3.7.1-3.7.2
过程:
1.数据(以过程参数和返回值的形式)传递。
2.控制转移
3.分配和释放新过程中的局部变量

函数栈有底(高地址)和顶(低地址,会变化,向下延伸)。

%ebp指向最上面,帧指针(在一个过程执行过程中不变,代表帧开始)
由于帧指针不动,所以大部分信息的访问是针对帧指针的。
%esp指向最下面,栈指针(会随着过程中的指令变化而变化,代表动态变化的栈)

要调用新函数,需要保存上一个函数的返回地址(PC,程序计数器)和%ebp的值
上一个函数的返回地址保存在新函数%ebp+4的位置
上一个函数的%ebp值保存在新函数的%ebp中

和过程调用和返回有关的三个汇编指令
call
leave
ret

考虑一个函数调用过程,必然要改变PC,同时要保存返回地址。
所以call sumaddr的效果是:
1.push %eip+4 将返回地址(紧跟在call后面的那条指令的地址)入栈
2.movl sumaddr, %eip 改变%eip的值,跳转到被调用过程的开始。

接着执行
push %ebp 这个语句是sum过程的第一句
(后面应该还有一句movl %esp, %ebp 设置新的ebp值)

leave的效果是重设栈指针和帧指针:
movl %ebp, %esp 把esp的值设为ebp,连同后面两个pop的目的是为了恢复main的栈指针
popl %ebp 取出被保存的main的ebp值。返回地址在%ebp+4处,所以将返回地址(正好是main的%ebp)存入%ebp

ret的效果是
1.popl %eax 从栈中弹出返回地址,
2.movl %eax, %eip 跳转到这个返回地址

注:call和ret的操作汇编代码只是为了说明做了什么

只有call和ret能改变%eip的值

三对对应操作:
1.调用时用call改变eip的值后面也会用ret改回来
2.保存返回地址和帧指针的push操作最后会由对应的两个pop操作还原
3.leave的movl %ebp, %esp是对sum操作过程加了无数中间局部变量状态的一个还原。应该是和movl %esp, %ebp构成对应关系。

寄存器使用惯例:
调用者保存寄存器:%eax、%edx、%ecx。可以随便覆盖
被调用者保存寄存器:%ebx、%esi、%edi。若使用,必须恢复现场

学了忘,忘了学。。。