程序员的内功修炼——深入理解函数栈帧( 二 )


输入esp
然后F10就能执行汇编代码的第一条 , 也就是刚刚那条 , 就可以看到 , esp的值变小了4 , 就代表在栈顶压入了一个元素 。
画图就是这样:
第二条代码(mov):
00553B41movebp,esp
mov的意思就是将esp的地址赋给ebp
执行代码之前:
执行代码之后:
图形的变化就是:
第三条代码(sub):
00553B43subesp,0E4h
sub的意思就是将esp地址减去一个0E4h , 那0E4h是多少呢?
这张图也是执行代码之前的esp的地址 。
先取消16进制显示在监视中输入0E4h , 可以看到值是228 。
执行代码后esp的变化:
画图可以看到是这样的变化:
其实几条代码就是为了给main函数开辟
第四五六条代码(push):
00553B49pushebx00553B4Apushesi00553B4Bpushedi
三条都是一样的push上个寄存器在上面:
这个跟前面一样 , 我就只画图:
esp的地址变化就是:从---->---->---->
第七八九十条代码(lea指令)
00553B4Cleaedi,[ebp-0E4h]00553B52movecx,39h00553B57moveax,0CCCCCCCCh00553B5Crep stosdword ptr es:[edi]
这几条代码的意思就是将edi开始向下的39h个dword( word , 4个字节)的值改成 。
edi的地址是什么呢?是ebp-0E4h(这个就很棒了) , ebp - 0E4h就是main函数栈帧的栈顶 。
我们直接看图:
一直到ebp的地址才结束:
我们画图:
第十一条代码(mov)
前面这么久都没有进行一条代码 , 接下来才是执行代码 。
int a = 10;00553B5Emovdword ptr [ebp-8],0Ah
就是将0Ah的值放进ebp-8的地址当中 。
画图:
其实就是将ebp的上面上面第二个地址放入了a = 10;
第十二十三条代码(mov)
int b = 20;00553B65movdword ptr [ebp-14h],14hint c = 0;00553B6Cmovdword ptr [ebp-20h],0
和上面一样 , 将b = 20,c = 0 放在ebp - 14h和ebp - 20h的位置 。
这里我们就能知道 , 如果在main函数中变量不初始化就是随机值 , 就是 。
走到这里 , 我们的main函数才结束 。
看图:
Add函数汇编代码的解析
先看代码:
c = Add(a, b);00553B73moveax,dword ptr [ebp-14h]00553B76pusheax00553B77movecx,dword ptr [ebp-8]00553B7Apushecx00553B7Bcall005511E000553B80addesp,800553B83movdword ptr [ebp-20h],eax
第一二三四条代码(mov和push)
00553B73moveax,dword ptr [ebp-14h]00553B76pusheax00553B77movecx,dword ptr [ebp-8]00553B7Apushecx
mov我们也知道了 , 一二条是将ebp - 14h地址的值放入eax寄存器中并将eax压入栈区 , 三四条也是将ebp - 8地址的值放入寄存器ecx中并将其压入栈顶 。这个过程就是函数的传参 。
我们画图:
这里我们就是清晰知道 , 函数形参就是实参的临时的一份拷贝 , 我们知道 , 改变形参不会改变实参 , 这个想法是完全正确的 。
第五条代码(重要 , call指令)
00553B7Bcall005511E0
这个时候就是要讲call下一条指令压栈压入了栈顶 。
画图: