汇编调用堆栈 - 术语问题

Assembly Call Stack - Terminology Questions

我是 Assembly 的新手,希望确认在以下陈述中我在哪里有误解,需要更正。

栈指针(ESP)指向栈顶(最低内存地址)

base Pointer(EBP)用于构建栈帧时临时存放各种内存地址。它通常保存当前堆栈帧的最高内存地址。

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

一旦将某些内容推入堆栈,就无法就地更改。 IE。如果我们 PUSH EBP 到堆栈,我们推的是 EBP 的当前值,而不是指向它的某种引用或指针。我们无法就地更改该值。

传递给函数的参数通常被移动到地址space,这是堆栈指针的偏移量。 IE。 [ESP-12].

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

  1. return地址被添加到堆栈(紧跟在当前EIP之后的地址的内存,所以我们知道在被调用函数完成后return到哪里
  2. 保存的帧指针入栈,一般为调用函数的栈帧的栈指针
  3. 然后我们将进入被调用函数的序言

谢谢。我正在努力解决这个问题。

Arguments being passed into a function are generally moved into an address space which is an offset of the stack pointer. ie. [ESP-12].

经常将参数压入堆栈,调用之前。

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

这导致以下堆栈内容:

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

由于 return 地址(由 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]
return 地址位于 [EBP+4]

注意:如你所见,是可以的

  • 通过 ESP 访问(然后你 不需要 需要一个帧指针,但是你需要跟踪你推送了多少数据,到 "find" 参数和变量 )
  • EBP(这会增加一些开销)。在许多函数中,根本不需要帧指针,并且被编译器优化掉了。

Once something has been pushed to the stack, it can't be changed in-place. ie. If we PUSH EBP to the stack, we are pushing the current value of EBP, not some kind of reference or pointer to it. We can't then change that value in-place.

当然可以。栈就是普通的计算机内存,没什么特别的,除了99%的代码期望有效(读+写访问)内存地址在esp和一些保留的space,所以它可以压入一些本地的东西根据需要添加。

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

reference or pointer to it

嗯,没有办法对 ebp 寄存器有某种引用或指针,它是 CPU 中的一个寄存器,只有 32 位(32x 0 或 1 值)并且它有没有地址,您只能在指令中使用它的名称 ebp,这允许在它们的编码中使用它。

push ebp 之后,这 32 位(没有其他信息)被复制到内存中(然后内存将这些 0/1 值复制到它自己的 32 位 = 4 字节中)。没有信息从哪里写入内存中的值,何时以及通过什么指令,只存储值位。