- IAA32过程调用寄存器的保护规则
-
由于操作系统中的共享性质,所以,寄存器也就成为了各个进程或者过程共享资源的一种。那么发生过程 调用的时候,如果调用者要用到一个寄存器里面的值,但是这个寄存器的内容很可能在被调用者运行过程中修改,那么我们就要在被调用过程执行之前,对该寄存器里面的内容进行保护,以至于不会出错,寄存器的保护规则也是因为程序的不可再现性而存在的。
在IA32上,实行了一个统一的寄存器保护规则。首先,我们要看一下,计算机中有多少个比较重要的寄存器
(偷偷懒我就不写寄存器前面的百分号了O(∩_∩)O)
eax 这个寄存器属于调用者保存寄存器,通常用来存储一些函数的返回值
edx ecx这两个也是属于调用者保存寄存器,并且 属于通用寄存器,可以随意保存数据,没有 什么特定的 限制。
ebx edi esi这三个寄存器属于被调用者保存寄存器。通常来说edi 和 esi可能会保存一些被调用函数的参数。
这里要说明一下一个概念,就是我很疑惑的,什么叫做调用者保存寄存器,什么叫做被调用者保存寄存器。
两者的区别,我觉得可以用下面的图示来说明一下。
上面的图示说明 ,寄存器按照规则被分类了,左面的三个寄存器是调用者负责保存,右边三个寄存器是被调用者负责保存。也就是说,在过程调用的时候,如果被调用者程序会覆盖左边三个寄存器的内容,那么,如果这三个寄存器内容在过程调用结束之后还要用到没调用过程之前的那个数值的话,就要有人在过程调用发生之前保存这个寄存器里面的数值,但是由谁来保存呢?只能由调用者去保存,也就是说,被调用者是不会管你这里面有什么重要的数据的,他拿过来就用,但是调用者如果需要这里面的数据,就要自己提前保存。说的再直白一点,就是寄存器是任何程序都可以随便用的,但是里面数据的保存工作就是有责任人的。左边三个寄存器的责任人是调用者,右边三个寄存器的责任人是被调用者。
我觉得这样理解是正确的,如果我恰好理解反了,还希望大家给我指出来。
还有两个比较重要的寄存器:
esp是栈顶指针的寄存器
ebp是基址寄存器
学过汇编的人会知道,在进行过程调用的时候,主要是用程序栈来支持过程的调用,并且机器也会利用栈来存储一些参数。这样一来,在过程调用中,上面两个寄存器里面的数据就变得相当重要。在一个过程调用的时候,必须要保存旧的ebp里面的数据,并且初始化的时候也需要movl ebp esp这样的指令将两个栈指针初始化一下,之后,esp会随着过程的调用进行扩展增长,在过程调用结束的时候,要有一些指令进行恢复和清理工作,把栈恢复成这次调用之前的样子。那么我们就要进行如下 两个指令 mov ebp esp popl ebp 第一条指令是清理工作,也就是释放栈空间,把栈顶指针移动到基址指针的地方,因为在call指令执行的时候,调用者会把被调用过程完成之后下一条指令的地址压入栈中。所以,在popl将旧的基地址恢复之后,esp也就向栈低移动 到了下一条指令执行的地址那里。这样一来调用完成之后的恢复和清理工作也就结束了。