传递给函数的参数通常被移动到地址空间中,该地址空间是堆栈指针的偏移量。IE。[ESP-12]。
通常在调用之前将参数压入堆栈。
push paramA ; ( some 32bit value, register, whatever )
push paramB
call myFunct
这导致以下堆栈内容:
---------------
| paramA |
---------------
| paramB |
---------------
| return addr | <-- ESP
---------------
由于返回地址(由 推入call
)是 4 个字节,所以函数的参数是 at[ESP+4]
和[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)
---------------
局部变量为 at [EBP-4]
,[EBP-8]
等[EBP-12]
。
返回地址为 at[EBP+4]
注意:如您所见,这是可能的
- 访问
ESP
(然后你不需要帧指针,但是你需要跟踪你推送了多少数据,以“找到”参数和变量)
- 或通过
EBP
(这增加了一些开销)。在许多函数中,根本不需要帧指针,并被编译器优化掉。