[疑惑中]一个c函数的反汇编问题。我写了一个很小的C函数来观察反汇编的效果。我用VC2012编译release版的程序
[疑惑中]一个c函数的反汇编问题。
我写了一个很小的C函数来观察反汇编的效果。
我用VC2012编译release版的程序,去掉了优化开关,下面的f函数在反汇编窗口显示如下:
void f(){
00FE15F0 push ebp
00FE15F1 mov ebp,esp
printf("abc\n");
00FE15F3 push 0FE31C8h
00FE15F8 call dword ptr ds:[0FE3074h]
00FE15FE add esp,4
}
00FE1601 pop ebp
00FE1602 ret
我的问题是:
(1)对于printf函数的调用,这个push 0FE31C8h是把字符串"abc\n"压入堆栈吗?
(2)call dword ptr ds:[0FE3074h]这句话,如果0FE3074h是printf对应的代码地址,为什么不是在代码段cs里面,而是在数据段ds里面呢?
而且,为什么还要加一个dword ptr来寻址呢,难道ds:[0FE3074h]是一个函数指针的地址,指向printf函数?
(3)函数调用之后为什么还要add esp,4呢,f()的内部并没有变量或者函数调用啊。
求大侠解释,多谢!
[解决办法](1)对于printf函数的调用,这个push 0FE31C8h是把字符串"abc\n"压入堆栈吗?
不是,是存这个字符串的内存地址,也就是说 *(char*)0FE21C8h是'a', *(char*)0FE21C9h='b', ...
(2)call dword ptr ds:[0FE3074h]这句话,如果0FE3074h是printf对应的代码地址,为什么不是在代码段cs里面,而是在数据段ds里面呢?
是间接调用。printf的地址存在ds:blahblah处。
而且,为什么还要加一个dword ptr来寻址呢,难道ds:[0FE3074h]是一个函数指针的地址,指向printf函数?
(3)函数调用之后为什么还要add esp,4呢,f()的内部并没有变量或者函数调用啊。
这个是undo那个push 0FE3074h对堆栈的影响。之后的pop EBP才能正确的还原EBP修改之前的值。
汇编我不懂,哈哈,凑个热闹。
[解决办法]你可以看看VC直接生成的汇编代码
这只需要设置一下就成
大约生成如下代码:
//void f(){
00FE15F0 push ebp
00FE15F1 mov ebp,esp
// printf("abc\n");
00FE15F3 push abc // "abc\n" 把字符串还原成符号,一定有abc 三个字符
//其他都是添加的符号或者替换符号
00FE15F8 call __imp_printf //或者 _printf
00FE15FE add esp,4
00FE1601 pop ebp
00FE1602 ret
//}
[解决办法]函数调用时候有好几个事情要做
保存现场,为形参分配空间,把实参传递给形参,执行函数,返回调用前现场。
对于前两问,1楼已经回答了。
最后一问,就是要返回现场的。返回现场之后,要执行其他的函数,所以那个时候的栈必须与调用函数之前的栈相同,不然栈就坏了。
[解决办法]这个是VC 生成的汇编代码:
//数据 "abc\n" 生成如下代码
$SG-5DB'abc', 0aH, 00H
函数 void f() 生成如下代码:
_fPROC; COMDAT
; 2 : void f(){
pushebp
movebp, esp
; 3 : printf("abc\n");
pushOFFSET $SG-5 //这里传递指针,占用4字节堆栈
callDWORD PTR __imp__printf //调用 printf 函数是个函数指针,因为CRT是在动态库中。
addesp, 4 //清栈恢复调用函数printf之前,没有传递参数前的 esp
; 4 : }
popebp
ret0
_fENDP
VC2010 .exe, 缺省编译为,使用动态库中的CRT库函数。
所以调用的 printf 函数,实际为调用函数指针的代码
正常的.exe 应该使用静态CRT库,生成的代码如下。
EXTRN_printf:PROC
$SG-5DB'abc', 0aH, 00H
_fPROC; COMDAT
; 2 : void f(){
pushebp
movebp, esp
; 3 : printf("abc\n");
pushOFFSET $SG-5 //参数 "abc\n" 的地址(偏移量部分)入栈。
call_printf //C 函数名字前,加下划线;
addesp, 4
; 4 : }
popebp
ret0
_fENDP