- 第一章 CPU 简介
- 第二章 Hello,world!
- 第三章 函数开始和结束
- 第四章 栈
- Chapter 5 printf() 与参数处理
- Chapter 6 scanf()
- CHAPER7 访问传递参数
- Chapter 8 一个或者多个字的返回值
- Chapter 9 指针
- Chapter 10 条件跳转
- 第 11 章 选择结构 switch()/case/default
- 第 12 章 循环结构
- 第 13 章 strlen()
- Chapter 14 Division by 9
- chapter 15 用 FPU 工作
- Chapter 16 数组
- Chapter 17 位域
- 第 18 章 结构体
- 19 章 联合体
- 第二十章 函数指针
- 第 21 章 在 32 位环境中的 64 位值
- 第二十二章 SIMD
- 23 章 64 位化
- 24 章 使用 x64 下的 SIMD 来处理浮点数
- 25 章 温度转换
- 26 章 C99 的限制
- 27 章 内联函数
- 第 28 章 得到不正确反汇编结果
- 第 29 章 花指令
- 第 30 章 16 位 Windows
- 第 31 章 类
- 三十二 ostream
- 34.2.2 MSVC
- 34.2.3 C++ 11 std::forward_list
- 34.3 std::vector
- 34.4 std::map and std::set
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
7.1 X86
7.1.1 MSVC
如下为相应的反汇编代码(MSVC 2010 Express)
Listing 7.2 MSVC 2010 Express
#!bash
_TEXT SEGMENT
_a$ = 8 ; size = 4
_b$ = 12 ; size = 4
_c$ = 16 ; size = 4
_f PROC
push ebp
mov ebp, esp
mov eax, DWORD PTR _a$[ebp]
imul eax, DWORD PTR _b$[ebp]
add eax, DWORD PTR _c$[ebp]
pop ebp
ret 0
_f ENDP
_main PROC
push ebp
mov ebp, esp
push 3 ; 3rd argument
push 2 ; 2nd argument
push 1 ; 1st argument
call _f
add esp, 12
push eax
push OFFSET $SG2463 ; ’%d’, 0aH, 00H
call _printf
add esp, 8
; return 0
xor eax, eax
pop ebp
ret 0
_main ENDP
我们可以看到函数 main() 中 3 个数字被圧栈,然后函数 f(int, int, int) 被调用。函数 f() 内部访问参数时使用了像_ a$=8 的宏,同样,在函数内部访问局部变量也使用了类似的形式,不同的是访问参数时偏移值(为正值)。因此 EBP 寄存器的值加上宏_a$的值指向压栈参数。
_a$[ebp]
的值被存储在寄存器 eax 中,IMUL 指令执行后,eax 的值为 eax 与 _b$[ebp]
的乘积,然后 eax 与 _c$[ebp]
的值相加并将和放入 eax 寄存器中,之后返回 eax 的值。返回值作为 printf() 的参数。
7.1.2 MSVC+OllyDbg
我们在 OllyDbg 中观察,跟踪到函数 f() 使用第一个参数的位置,可以看到寄存器 EBP 指向栈底,图中使用红色箭头标识。栈帧中第一个被保存的是 EBP 的值,第二个是返回地址(RA),第三个是参数 1,接下来是参数 2,以此类推。因此,当我们访问第一个参数时 EBP 应该加 8(2 个 32-bit 字节宽度)。
Figure 7.1: OllyDbg: 函数 f() 内部
7.1.3 GCC
使用 GCC4.4.1 编译后在 IDA 中查看
Listing 7.3: GCC 4.4.1
#!bash
public f
f proc near
arg_0 = dword ptr 8
arg_4 = dword ptr 0Ch
arg_8 = dword ptr 10h
push ebp
mov ebp, esp
mov eax, [ebp+arg_0] ; 1st argument
imul eax, [ebp+arg_4] ; 2nd argument
add eax, [ebp+arg_8] ; 3rd argument
pop ebp
retn
f endp
public main
main proc near
var_10 = dword ptr -10h
var_C = dword ptr -0Ch
var_8 = dword ptr -8
push ebp
mov ebp, esp
and esp, 0FFFFFFF0h
sub esp, 10h
mov [esp+10h+var_8], 3 ; 3rd argument
mov [esp+10h+var_C], 2 ; 2nd argument
mov [esp+10h+var_10], 1 ; 1st argument
call f
mov edx, offset aD ; "%d
"
mov [esp+10h+var_C], eax
mov [esp+10h+var_10], edx
call _printf
mov eax, 0
leave
retn
main endp
几乎相同的结果。
执行两个函数后栈指针 ESP 并没有显示恢复,因为倒数第二个指令 LEAVE(B.6.2)会自动恢复栈指针。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论