【发布时间】:2014-06-05 20:56:03
【问题描述】:
关于这个将两个数字相加的非常简单的函数,只是几个好奇的问题。这是带注释的反汇编(问题在标有???的代码中)
这里是C函数
int Add(int x , int y)
{
int additionAnswer = 0 ;
additionAnswer = x + y;
return additionAnswer;
}
这是带有我的注释和问题的反汇编(DEBUG BUILD)
int Add(int x , int y)
{
push ebp ; preserve base pointer
mov ebp,esp ; move base pointer to start of stack frame for this function
sub esp,0CCh ; ??? is this preserving space on the stack for local
; variable..204bytes seems execessive!!!
push ebx //??? Why is this preserving ebx, esi and edi
push esi //??? when clearly this function does not use it!
push edi
lea edi,[ebp-0CCh] ; ??? Why is it loading the address of top of stack into edi?
mov ecx,33h ; ??? What is that doing
mov eax,0CCCCCCCCh ; ??? What is that doing
rep stos dword ptr es:[edi] ; ??? What is that doing
mov dword ptr [additionAnswer],0 ;int additionAnswer = 0
mov eax,dword ptr [x] ;eax = x
add eax,dword ptr [y] ;eax = eax + y
mov dword ptr [additionAnswer],eax ;answer = eax
mov eax,dword ptr [additionAnswer] ; return addition in eax
pop edi ;restore edi even though I didn't use it !!!!
pop esi ;restore esi even though I didn't use it !!!!
pop ebx ;restore ebx even though I didn't use it !!!!
mov esp,ebp ; clean up stack frame and restore sp to
;4 bytes above it's original pre-frame value
pop ebp ;restore base pointer back to it's original value
;and at same time this will add 4 to sp hence restoring it
;back to its former pre-frame value, and pointing to return address on stack
ret
我挖了一下,显然在 Win32 中,必须保留以下内容:edi、esi、ebp 和 ebx。 我可以理解调用函数可能会使用源/目标索引寄存器 (esi /edi),但为什么 calling 函数不保留 EBX 本身而不是我的函数做不必要的驴工作,调用者肯定知道它需要保留什么,不需要保留什么! 最后为什么要保留 EBX 而不是 ECX,为什么我的函数有责任保留这些寄存器(甚至是任何寄存器!)。
最后一件事我在发布模式下构建时看不到任何这些寄存器保存代码(没有优化)......这是仅调试概念吗????
【问题讨论】:
-
你用什么选项编译?看起来像调试模式,其中未使用的内存用 0xCC 填充,以帮助您捕获未初始化内存的使用。如果您要评估指令生成的效率,您应该在关闭所有调试选项并打开所有优化的情况下进行编译。 (发布模式)
-
这看起来像是使用调试选项编译的。在发布版本下尝试。
-
是的,线索在最后一句中,我确实说明了在发布模式下不存在寄存器保存代码,因此上面的代码包含寄存器保存,因此不能是发布代码。我将编辑问题。
-
@Dark Falcon。感谢您的回答。我不是试图衡量效率,而是试图理解这里的意图。当您说“未使用的内存被 0xCC 填充以帮助您捕获未初始化内存的使用”时,您的意思是这行代码“mov eax,0CCCCCCCCh”。如果是这样,我不确定将常量移入 eax 是如何做到你所说的,你能给我任何指向网站的指针,以阅读更多关于这个的内容.....
-
哈哈找到了!这个问题的答案之一stackoverflow.com/questions/370195/… 指出“操作码 0xCC 是 int3 操作码,它是软件断点中断。因此,如果您尝试在已填充该填充值的未初始化内存中执行代码,您将立即命中断点,操作系统将允许您附加调试器(或终止进程)。”....这一切都很好地结合在一起