汇编调用堆栈 - 术语问题

时间:2017-11-15 12:52:29

标签: assembly x86 stack eip

我对大会全新,并希望确认在以下陈述中我有哪些误解,需要纠正。

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

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

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

一旦某些东西被推入堆栈,它就无法就地更改。即。如果我们PUSH EBP到堆栈,我们正在推送EBP的当前值,而不是某种引用或指向它的指针。然后,我们无法就地更改该值。

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

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

  1. 返回地址被添加到堆栈(紧跟当前EIP之后的地址的内存中,因此我们知道在被调用函数完成后返回的位置
  2. 保存的帧指针被添加到堆栈中,堆栈通常是调用函数的堆栈帧的堆栈指针
  3. 然后我们将进入被调用函数的序言
  4. 感谢。我试图理解这些东西。

2 个答案:

答案 0 :(得分:7)

  

传递给函数的参数通常被移动到地址空间,该地址空间是堆栈指针的偏移量。即。 [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(其中包括一些开销)。在许多函数中,根本不需要帧指针,并且由编译器优化掉。

答案 1 :(得分:4)

  

一旦某些东西被推入堆栈,它就无法就地更改。即。如果我们将EBP推入堆栈,我们正在推动EBP的当前值,而不是某种引用或指向它的指针。 我们无法就地更改该值。

当然可以。堆栈是普通的计算机内存,没有什么特别之处,除了99%的代码需要OriginalSource中的有效(读取+写入访问)内存地址和一些保留空间,因此它可以将一些本地内容推送到它,如需要的。

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 寄存器提供某种引用或指针,它是CPU中的一个寄存器,只有32位(32x 0或1值)并且它没有地址,你可以工作仅在说明中使用其名称ebp,允许在编码中使用它。

ebp时,将这32位(​​并且没有其他信息)复制到存储器中(然后保存那些以其自己的32位= 4字节复制的0/1值)。没有信息记录内存中的值,何时以及通过什么指令只存储值位。