基指针和栈指针

35

给定以下代码:

       swap:

            push ebp ; back up the base pointer,
            mov ebp, esp
            ; push the context of the registers on the stack

            push eax
            push ebx
            push ecx
            push edx

            mov eax, [ebp+8] ; address of the first parameter
            mov ebx, [ebp+12] ; address of the second parameter
            mov dl, [eax]
            mov cl, [ebx]

            mov [eax], cl

            mov [ebx], dl

            ; restore the context of the registers from the stack

            pop edx
            pop ecx  
            pop ebx
            pop eax
            ; restore the ebp
            pop ebp
            ret

(这只是方法。之前,我们将第一个参数和第二个参数推送到堆栈上。)

我的问题是:为什么要在基指针上加8才能到达第一个参数的地址,然后再加12?

我知道它们都是双字,所以每个参数都是4个字节大小。从ebp + 8到ebp + 12,这样做是有意义的。但为什么第一个参数是ebp + 8?因为如果ESP指向堆栈的顶部,mov ebp,esp表示EBP指向堆栈的顶部。然后,我们在堆栈上推送4个值:eax,ebx,ecx和edx。为什么EBP + 8指向第一个参数?

2个回答

52

当函数被调用时,堆栈看起来像:

+-------------+
| Parameter 2 |
+-------------+
| Parameter 1 |
+-------------+
| Return Addr |  <-- esp
+-------------+    

在“堆栈帧”设置完成后:

+-------------+
| Parameter 2 | <-- [ebp + 12]
+-------------+
| Parameter 1 | <-- [ebp + 8]
+-------------+
| Return Addr |  
+-------------+    
| saved ebp   | <-- ebp
+-------------+ <-- esp

现在上下文已经保存:

+-------------+
| Parameter 2 | <-- [ebp + 12]
+-------------+
| Parameter 1 | <-- [ebp + 8]
+-------------+
| Return Addr |  
+-------------+    
| saved ebp   | <-- ebp
+-------------+ 
| saved eax   |  
+-------------+    
| saved ebx   |  
+-------------+    
| saved ecx   |  
+-------------+    
| saved edx   | <-- esp
+-------------+    

不要忘记,许多系统的堆栈向下增长(这在x86系列中绝对是真的),因此堆栈顶部将具有最低的内存地址。


1
哇,非常简洁!谢谢,这很有帮助!我想关键点是堆栈向下增长!知道这一点很好!你让我的一天变得美好。 - yhcowboy

7

由于栈上还有其他两个项目:在此例程开始时推送的先前ebp以及通过调用该例程放入栈中的返回地址。


我从没想过返回地址会被压入堆栈!非常感谢。 - yhcowboy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接