首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

[疑惑中]一个c函数的反汇编有关问题

2014-01-06 
[疑惑中]一个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

热点排行