组装调用堆栈

我对议会来说是全新的,并且希望确认在以下声明中,我有什么误解并需要纠正。

堆栈指针ESP )指的是堆栈的顶端(最低内存地址)。

基础指针EBP )用于在构建堆栈帧时临时存储各种存储器地址。 它通常保存当前堆栈帧的最高内存地址。

指令指针EIP )是指内存中文本(代码)段中的一行代码的内存地址

一旦有东西被推入堆栈,它不能在原地进行更改。 即。 如果我们将PUSH EBP压入堆栈,我们推动EBP的当前值,而不是某种参考或指针。 我们现在不能在原地改变这个价值。

传递给函数的参数通常会移入一个地址空间,该地址空间是堆栈指针的偏移量。 即。 [ESP-12]

当调用函数(使用CALL )时,会发生以下情况:

  • 返回地址被添加到堆栈中(紧接在当前EIP之后的地址的存储器,所以我们知道在被调用函数完成之后要返回到哪里
  • 保存的帧指针被添加到堆栈中,堆栈通常是调用函数的堆栈帧的堆栈指针
  • 然后我们将进入被调用函数的序幕
  • 谢谢。 我试图让我的头靠近这个东西。


    传递给函数的参数通常会移入一个地址空间,该地址空间是堆栈指针的偏移量。 即。 [ESP-12]。

    在通话之前 ,参数经常被推入堆栈。

    push paramA  ; ( some 32bit value, register, whatever )
    push paramB
    call myFunct
    

    这导致以下堆栈内容:

    ---------------
    |    paramA   |
    ---------------
    |    paramB   |
    ---------------
    | return addr |   <-- ESP
    --------------- 
    

    由于返回地址(由call推送)是4个字节,因此该函数的参数在[ESP+4][ESP+8]

    如果你的函数添加一个堆栈框架,通常你会这样做

    myFunct:  push EBP
              mov EBP, ESP
    

    现在堆栈看起来像这样:

    ---------------
    |    paramA   |
    ---------------
    |    paramB   |
    ---------------
    | return addr |   
    ---------------     
    |   saved EBP |   <-- EBP, ESP
    --------------- 
    

    并且参数在[EBP+8][EBP+12] ,即使您推送更多值(或为局部变量添加一些位置),因为EBP不再改变:

    myFunct:  push EBP
              mov EBP, ESP
              sub ESP, 12      ; make room for 3 32bit local variables
    
              mov eax, [EBP+8] ; access one of the parameters
              mov [EBP-4], eax ; save it in local variable #1
    
    rel |  rel |
    to  |  to  |
    ESP |  EBP |
    ----|------|--------------
    +24 | +12  |    paramA   |
        |      |--------------
    +20 | +8   |    paramB   |
        |      |--------------
    +16 | +4   | return addr |  
        |      |--------------
    +12 |      |   saved EBP |  <-- EBP   (is fixed here for now)
        |      |--------------- 
    +8  | -4   |    local#1  |
        |      |--------------- 
    +4  | -8   |    local#2  |
        |      | --------------- 
    0   | -12  |    local#3  |  <--- ESP  (keeps growing, by pushing, calling etc)
               --------------- 
    

    局部变量位于[EBP-4][EBP-8][EBP-12]
    返回地址是[EBP+4]

    注意:正如你所看到的,这是可能的

  • 通过访问ESP (那么你并不需要一个帧指针,但你需要跟踪的多少数据推动,“发现”的参数和变量)
  • EBP (这增加了一些开销)。 在许多功能中,帧指针根本不需要,并且由编译器进行优化。

  • 一旦有东西被推入堆栈,它不能在原地进行更改。 即。 如果我们将PUSH EBP压入堆栈,我们推动EBP的当前值,而不是某种参考或指针。 我们现在不能在原地改变这个价值。

    你当然可以。 Stack是普通的计算机内存,除了99%的代码需要在esp和一些保留空间中有效的(读取+写入访问)内存地址之外,没有什么特别之处,所以它可以根据需要将一些本地事物推送到它。

    push  ebp    ; store current value in ebp to stack
    

    几乎相当于:

    sub   esp,4
    mov   [esp],ebp
    

    (但第二个变体也会修改标志,并且它的原子稍微有点小)

    现在你可以用其他任何东西来覆盖它,比如:

    mov [esp],eax ; overwrite the old_ebp value with current_eax value
    

    参考或指针

    那么,没有办法获得某种参考或指向ebp寄存器的指针,它是CPU中的一个寄存器,只有32位(32x 0或1值),并且没有地址,只能通过其名称ebp使用它在说明中,允许在编码中使用它。

    push ebp那些32位(并且没有其他信息)被复制到存储器中(然后将这些0/1值复制到它自己的32位= 4字节中)。 没有关于内存值是从哪里写入的信息,何时和按什么指令,只存储了值位。

    链接地址: http://www.djcxy.com/p/14109.html

    上一篇: Assembly Call Stack

    下一篇: How is the stack set up in a Windows function call?