栈可以理解为一块存储空间。而栈帧是栈的一部分,是在栈中专门为一个过程或者说一个函数分配的栈空间。

     栈的功能主要是用来存储过程参数,存储返回信息,保存寄存器,存储本地变量。事实上这四个功能中的前三个主要是为了实现一个目标--函数调用。也就是在一个函数中调用其他函数。例如已有一个函数p,在这个函数中要调用另一个函数q。这个过程需要栈的支持,也就是要实现的几个功能。p称为调用者,而q称为被调用者。

    

void  p()
               {
                     int a=1;
                     int b=2;
                     int c;
                     c=q(a,b);
 
                 }
              void q(int a,int b)
              { 
                  return a+b;
                }

      (1)存储过程参数功能。依然以上面p函数调用q函数为背景。

                    在这个例子中首先栈会专门拿出一块空间作为调用者p的栈帧。而被调用者q的位于p中,因此p的栈帧会存储q的参数,这就是存储过程参数,在调用者的栈帧中存储被调用者的参数。

       (2)保存寄存器。这个功能我认为比较好理解。寄存器只有一套,如果不保存,那么没办法保证每个函数都正常运行。比如p调用q,若不对p的寄存器进行保护,那么q很有可能将寄存器中的值修改,当返回到p时,p没有办法继续正确执行。但是关于如何保存寄存器,有一些规则,书上是这么写的,实际应用的过程中我个人认为只有保护了就行,当然,我汇编的代码写的很少,可能说的不对。规则是寄存器分为调用者保存和被调用者保存。通过名字不难理解,调用者保存寄存器需要有调用者函数来保存和恢复。上例中,也就是需要p过程来保存和恢复。被调用者自然就是需要被调用者函数来保存和恢复,也就是q来保存和恢复。eax,edx,ecx为调用者保存寄存器,ebx,esi,edi为被调用者保存寄存器。

        (3)存储返回信息。存储返回信息时为了在被调用者函数返回时依然可以回到调用者函数继续执行。返回信息实际上就是返回地址。例如在p函数中调用q函数。当call指令完成对q的调用时,需要首先将返回地址入栈,返回地址就是call指令的下一条指令的地址。当q程序ret指令返回时会把返回地址弹出。

call next
         next :
         pop eax

         这个语句最终完成的是把程序计数器的地址存入eax寄存器。call next指令的会把下一条指令的地址入栈,而下一条指令就是pop eax,因此pop eax指令的地址被入栈,然后执行pop eax指令。将栈顶弹出,存入到eax。而指令地址是有程序计数器去决定的。事实上这个例子我只理解到eax中存的是pop eax指令的地址,至于说是程序计数器的值我并不是特别理解。