组装调用堆栈
我对议会来说是全新的,并且希望确认在以下声明中,我有什么误解并需要纠正。
堆栈指针 ( 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字节中)。 没有关于内存值是从哪里写入的信息,何时和按什么指令,只存储了值位。
上一篇: Assembly Call Stack