update stack

This commit is contained in:
firmianay 2017-08-15 01:18:48 +08:00
parent 9d54f09cdd
commit 4052ac215e

View File

@ -80,55 +80,55 @@ int main() {
}
```
使用 gdb 查看对应的汇编代码:
使用 gdb 查看对应的汇编代码,这里我们给出了详细的注释
```text
gdb-peda$ disassemble main
Dump of assembler code for function main:
0x00000563 <+0>: lea ecx,[esp+0x4]
0x00000567 <+4>: and esp,0xfffffff0
0x0000056a <+7>: push DWORD PTR [ecx-0x4]
0x0000056d <+10>: push ebp
0x0000056e <+11>: mov ebp,esp
0x00000570 <+13>: push ebx
0x00000563 <+0>: lea ecx,[esp+0x4] ;将 esp+0x4 的地址传给 ecx
0x00000567 <+4>: and esp,0xfffffff0 ;栈 16 字节对齐
0x0000056a <+7>: push DWORD PTR [ecx-0x4] ;ecx-0x4即原 esp 强制转换为双字数据后压入栈中
0x0000056d <+10>: push ebp ;保存调用 main() 函数之前的 ebp由于在 _start 中将 ebp 清零了,这里的 ebp=0x0
0x0000056e <+11>: mov ebp,esp ;把调用 main() 之前的 esp 作为当前栈帧的 ebp
0x00000570 <+13>: push ebx ;ebx、ecx 入栈
0x00000571 <+14>: push ecx
0x00000572 <+15>: sub esp,0x10
0x00000575 <+18>: call 0x440 <__x86.get_pc_thunk.bx>
0x0000057a <+23>: add ebx,0x1a86
0x00000580 <+29>: mov DWORD PTR [ebp-0x10],0x1
0x00000587 <+36>: mov DWORD PTR [ebp-0xc],0x2
0x0000058e <+43>: push DWORD PTR [ebp-0xc]
0x00000591 <+46>: push DWORD PTR [ebp-0x10]
0x00000594 <+49>: call 0x53d <add>
0x00000572 <+15>: sub esp,0x10 ;为局部变量 a、b 分配空间并做到 16 字节对齐
0x00000575 <+18>: call 0x440 <__x86.get_pc_thunk.bx> ;调用 <__x86.get_pc_thunk.bx> 函数,将 esp 强制转换为双字数据后保存到 ebx
0x0000057a <+23>: add ebx,0x1a86 ;ebx+0x1a86
0x00000580 <+29>: mov DWORD PTR [ebp-0x10],0x1 ;a 第二个入栈所以保存在 ebp-0x10 的位置,此句即 a=1
0x00000587 <+36>: mov DWORD PTR [ebp-0xc],0x2 ;b 第一个入栈所以保存在 ebp-0xc 的位置,此句即 b=2
0x0000058e <+43>: push DWORD PTR [ebp-0xc] ;将 b 压入栈中
0x00000591 <+46>: push DWORD PTR [ebp-0x10] ;将 a 压入栈中
0x00000594 <+49>: call 0x53d <add> ;调用 add() 函数,返回值保存在 eax 中
0x00000599 <+54>: add esp,0x8
0x0000059c <+57>: sub esp,0x8
0x0000059f <+60>: push eax
0x000005a0 <+61>: lea eax,[ebx-0x19b0]
0x000005a6 <+67>: push eax
0x000005a7 <+68>: call 0x3d0 <printf@plt>
0x000005ac <+73>: add esp,0x10
0x000005af <+76>: mov eax,0x0
0x000005b4 <+81>: lea esp,[ebp-0x8]
0x000005b7 <+84>: pop ecx
0x0000059f <+60>: push eax ;eax 入栈
0x000005a0 <+61>: lea eax,[ebx-0x19b0] ;ebx-0x19b0 的地址保存到 eax该地址处保存字符串 "%d\n"
0x000005a6 <+67>: push eax ;eax 入栈
0x000005a7 <+68>: call 0x3d0 <printf@plt> ;调用 printf() 函数
0x000005ac <+73>: add esp,0x10 ;调整栈顶指针 esp删除 add() 和 printf() 的参数
0x000005af <+76>: mov eax,0x0 ;eax=0x0
0x000005b4 <+81>: lea esp,[ebp-0x8] ;ebp-0x8 的地址保存到 esp
0x000005b7 <+84>: pop ecx ;弹栈恢复 ecx、ebx、ebp
0x000005b8 <+85>: pop ebx
0x000005b9 <+86>: pop ebp
0x000005ba <+87>: lea esp,[ecx-0x4]
0x000005bd <+90>: ret
0x000005ba <+87>: lea esp,[ecx-0x4] ;ecx-0x4 的地址保存到 esp
0x000005bd <+90>: ret ;返回
End of assembler dump.
gdb-peda$ disassemble add
Dump of assembler code for function add:
0x0000053d <+0>: push ebp
0x0000053e <+1>: mov ebp,esp
0x00000540 <+3>: sub esp,0x10
0x00000543 <+6>: call 0x5be <__x86.get_pc_thunk.ax>
0x00000548 <+11>: add eax,0x1ab8
0x0000054d <+16>: mov eax,DWORD PTR [ebp+0x8]
0x00000550 <+19>: mov DWORD PTR [ebp-0x8],eax
0x00000553 <+22>: mov eax,DWORD PTR [ebp+0xc]
0x00000556 <+25>: mov DWORD PTR [ebp-0x4],eax
0x00000559 <+28>: mov edx,DWORD PTR [ebp-0x8]
0x0000055c <+31>: mov eax,DWORD PTR [ebp-0x4]
0x0000055f <+34>: add eax,edx
0x00000561 <+36>: leave
0x0000053d <+0>: push ebp ;保存调用 add() 函数之前的 ebp
0x0000053e <+1>: mov ebp,esp ;把调用 add() 之前的 esp 作为当前栈帧的 ebp
0x00000540 <+3>: sub esp,0x10 ;为局部变量 x、y 分配空间并做到 16 字节对齐
0x00000543 <+6>: call 0x5be <__x86.get_pc_thunk.ax> ;调用 <__x86.get_pc_thunk.ax> 函数,将 esp 强制转换为双字数据后保存到 eax
0x00000548 <+11>: add eax,0x1ab8 ;eax+0x1ab8
0x0000054d <+16>: mov eax,DWORD PTR [ebp+0x8] ;将 ebp+0x8 的数据 0x1 传送到 eaxebp+0x4 为函数返回地址
0x00000550 <+19>: mov DWORD PTR [ebp-0x8],eax ;保存 eax 的值 0x1 到 ebp-0x8 的位置
0x00000553 <+22>: mov eax,DWORD PTR [ebp+0xc] ;将 ebp+0xc 的数据 0x2 传送到 eax
0x00000556 <+25>: mov DWORD PTR [ebp-0x4],eax ;保存 eax 的值 0x2 到 ebp-0x4 的位置
0x00000559 <+28>: mov edx,DWORD PTR [ebp-0x8] ;取出 ebp-0x8 的值 0x1 到 edx
0x0000055c <+31>: mov eax,DWORD PTR [ebp-0x4] ;取出 ebp-0x4 的值 0x2 到 eax
0x0000055f <+34>: add eax,edx ;eax+edx
0x00000561 <+36>: leave ;返回,相当于 mov esp,ebp; pop ebp;
0x00000562 <+37>: ret
End of assembler dump.
```
@ -136,27 +136,27 @@ End of assembler dump.
```text
gdb-peda$ disassemble _start
Dump of assembler code for function _start:
0x00000400 <+0>: xor ebp,ebp
0x00000402 <+2>: pop esi
0x00000403 <+3>: mov ecx,esp
0x00000405 <+5>: and esp,0xfffffff0
0x00000408 <+8>: push eax
0x00000400 <+0>: xor ebp,ebp ;清零 ebp表示下面的 main() 函数栈帧中 ebp 保存的上一级 ebp 为 0x00000000
0x00000402 <+2>: pop esi ;弹栈设置 esi
0x00000403 <+3>: mov ecx,esp ;暂时保存当前的 esp
0x00000405 <+5>: and esp,0xfffffff0 ;栈 16 字节对齐
0x00000408 <+8>: push eax ;eax、esp、edx 入栈
0x00000409 <+9>: push esp
0x0000040a <+10>: push edx
0x0000040b <+11>: call 0x432 <_start+50>
0x00000410 <+16>: add ebx,0x1bf0
0x00000416 <+22>: lea eax,[ebx-0x19d0]
0x0000040b <+11>: call 0x432 <_start+50> ;先将下一条指令地址 0x00000410 压栈,设置 esp 指向它,再调用 0x00000432 处的指令
0x00000410 <+16>: add ebx,0x1bf0 ;ebx+0x1bf0
0x00000416 <+22>: lea eax,[ebx-0x19d0] ;取 <__libc_csu_fini> 地址传给 eax然后压栈
0x0000041c <+28>: push eax
0x0000041d <+29>: lea eax,[ebx-0x1a30]
0x0000041d <+29>: lea eax,[ebx-0x1a30] ;取 <__libc_csu_init> 地址传入 eax然后压栈
0x00000423 <+35>: push eax
0x00000424 <+36>: push ecx
0x00000424 <+36>: push ecx ;ecx、esi 入栈保存
0x00000425 <+37>: push esi
0x00000426 <+38>: push DWORD PTR [ebx-0x8]
0x0000042c <+44>: call 0x3e0 <__libc_start_main@plt>
0x00000431 <+49>: hlt
0x00000432 <+50>: mov ebx,DWORD PTR [esp]
0x00000435 <+53>: ret
0x00000436 <+54>: xchg ax,ax
0x00000426 <+38>: push DWORD PTR [ebx-0x8] ;调用 main() 函数之前保存返回地址,其实就是保存 main() 函数的入口地址
0x0000042c <+44>: call 0x3e0 <__libc_start_main@plt> ;call 指令调用 main() 函数
0x00000431 <+49>: hlt ;hlt 指令使程序停止运行,处理器进入暂停状态,不执行任何操作,不影响标志。当 RESET 线上有复位信号、CPU 响应非屏蔽终端、CPU 响应可屏蔽终端 3 种情况之一时CPU 脱离暂停状态,执行下一条指令
0x00000432 <+50>: mov ebx,DWORD PTR [esp] ;esp 强制转换为双字数据后保存到 ebx
0x00000435 <+53>: ret ;返回
0x00000436 <+54>: xchg ax,ax ;交换 ax 和 ax 的数据,相当于 nop
0x00000438 <+56>: xchg ax,ax
0x0000043a <+58>: xchg ax,ax
0x0000043c <+60>: xchg ax,ax
@ -164,7 +164,21 @@ Dump of assembler code for function _start:
End of assembler dump.
```
#### 调用约定
#### 函数调用约定
函数调用约定是对函数调用时如何传递参数的一种约定。调用函数前要先把参数压入栈然后再传递给函数。
一个调用约定大概有如下的内容:
- 函数参数的传递顺序和方式
- 栈的维护方式
- 名字修饰的策略
主要的函数调用约定如下,其中 cdecl 是 C 语言默认的调用约定:
调用约定 | 出栈方 | 参数传递 | 名字修饰
--- | --- | --- | ---
cdecl | 函数调用方 | 从右到左的顺序压参数入栈 | 下划线+函数名
stdcall | 函数本身 | 从右到左的顺序压参数入栈 | 下划线+函数名+@+参数的字节数
fastcall | 函数本身 | 都两个 DWORD4 字节)类型或者占更少字节的参数被放入寄存器,其他剩下的参数按从右到左的顺序压入栈 | @+函数名+@+参数的字节数
## 堆与内存管理