美文网首页
2.3堆栈平衡

2.3堆栈平衡

作者: 记事本的记事本 | 来源:发表于2019-10-31 18:21 被阅读0次

    任何程序在运行过程中都需要使用堆栈,为每一个程序(进程及线程)设置一个堆栈。在使用高级语言编程时,源程序中使用的函数调用、局部变量都要用到堆栈,由编译器来负责生成有关的机器指令。我的理解,堆栈就是维护当前线程中运行状态的一个数据结构,这种状态包括:需要传递的变量,函数的返回地址,局部变量等等。

    与堆栈相关的 3 个寄存器是:SS, ESP, EBP。
    ESP 寄存器中的内容作为堆栈的当前指针。PUSH, POP, CALL, RET 等指令都与堆栈有关,使用 SS:ESP 指向堆栈单元。
    EBP 寄存器中的内容作为堆栈的“基准”指针。SS:EBP 指向的地址作为基准地址。在函数(子程序)内部,可以使用 [EBP+立即数] 的形式来取得主程序传递的参数,使用 [EBP-立即数] 的形式来访问局部变量。
    从上述的描述可以看出,整个堆栈的是一个经典的先入后出的栈结构,在栈中还存在着“栈帧”这样的结构,用来表示当前函数运行的环境,里面存放着当前函数的局部变量,所需的返回地址。栈帧由 EBP 所指出,EBP 和 ESP 之间即为当前函数帧,调用函数和被调用函数的栈帧是相邻存放,这样即可通过 EBP加减固定的数,来获取主调函数所传递的函数参数。
    上述的堆栈结构如下:

    堆栈是经过精心设计的结构,使得编程人员能够方便的设计函数来实现结构化设计,高级语言也得益于这种结构,c 语言基本上就是汇编的一种简单的翻译。这里要强调的是,在用汇编写程序的时候,完全可以不按这种结构来设计,比如参数我们可以放到指定的内存区,被调用的函数到指定的内存区去取出传递给它的参数;也可以让函数参数全部通过寄存器来传送,尤其是在 ARM 这种寄存器特别多,而且每个寄存器的地位都相同的处理器之中。之所以要设计出堆栈,就是为了能够以统一的方式来编写程序。

    对于 c 语言,函数有好几种调用规则。最常见的是两种,cdecl 方式和 stdcall 方式。

    Cdecl 方式
    (1)使用堆栈传递参数
    (2)主程序按从右向左的顺序将参数逐个压栈,最后一个参数先入栈。每一个参数压栈一次。
    (3)在子程序中,使用 [EBP+X] 的方式来访问参数。X=8 代表第 1 个参数;X=12 代表第二个参数,依次类推
    (4)子程序用 RET 指令返回。
    (5)由主程序执行“ADD ESP, n”指令调整 ESP,达到堆栈平衡。
    (6)一般返回值放在 EAX 中

    Stdcall 方式
    与Cdecl的不同是,堆栈的平衡不是由主程序完成,而是由子程序通过调用“RET n”指令主动平衡。

    这些调用规则,都是针对 c 语言来说的,在 c 语言和汇编需要互相调用的情况;c 语言编写的不通的二进制函数库之间,都要注意函数的调用规则。

    下面举一个普通的例子

    1.  AddProc1    proc   ; cdecl方式  
    2.  push    ebp    ; 记下上一个栈帧地址  
    3.  mov     ebp, esp  
    4.  mov     eax, dword ptr [ptr+8]  ; 取第一个参数   
    5.  add     eax, dword ptr [ptr+12] ; 取第二个参数  
    6.  pop     ebp    ; 恢复栈帧为调用者,但这时候堆栈还未平衡  
    7.  ret  
    8.  AddProc1    endp  
    9.  AddProc2    proc   ; stdcall  
    10.  push    ebp  
    11.  mov     ebp, esp  
    12.  mov     eax, dword ptr [ptr+8]  
    13.  add     eax, dword ptr [ptr+12]  
    14.  pop     ebp  
    15.  ret     8    ; 和前面一样,唯一不同是,直接由子程序恢复堆栈,8 正好是两个参数的长度  
    16.  AddProc2    endp  
    17.  start:  
    18.  push    20  
    19.  push    10  
    20.  call    AddProc1  
    21.  add     esp, 8   ; 由主调函数恢复堆栈  
    22.  push    50  
    23.  push    60  
    24.  call    AddProc2  
    25.  ret  
    26.  end start
    

    相关文章

      网友评论

          本文标题:2.3堆栈平衡

          本文链接:https://www.haomeiwen.com/subject/wywtbctx.html