传递给函数的参数通常被移动到地址空间中,该地址空间是堆栈指针的偏移量。 IE。 [ESP-12]。
通常参数被压入堆栈,before的电话。
push paramA ; ( some 32bit value, register, whatever )
push paramB
call myFunct
这导致以下堆栈内容:
---------------
| paramA |
---------------
| paramB |
---------------
| return addr | <-- ESP
---------------
由于返回地址(由call
) 为 4 个字节,该函数的参数位于[ESP+4]
and [ESP+8]
.
如果你的函数添加了一个堆栈帧,通常你会这样做
myFunct: push EBP
mov EBP, ESP
现在堆栈看起来像这样:
---------------
| paramA |
---------------
| paramB |
---------------
| return addr |
---------------
| saved EBP | <-- EBP, ESP
---------------
参数位于[EBP+8]
and [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]
etc.
退货地址位于[EBP+4]
注意:正如你所看到的,这是可能的
- 通过访问
ESP
(然后你做not需要一个帧指针,但是您需要跟踪您推送了多少数据,以“查找”参数和变量)
- or by
EBP
(ofc 增加了一些开销)。在许多函数中,根本不需要帧指针,并且由编译器优化掉。