GCC和Borland的分解C代码的差异? 最近我对DIS汇编C代码(非常简单的C代码)感兴趣,并遵循Borland C++编译器V 5.5(编译C代码很好)的教程,所有的工作都有效。然后我决定尝试自己的C代码,并在DEV C++(使用GCC)中编译它们。在IDA Pro中打开它时,我得到了一个惊喜,gcc的asm与Borland的真的不同。我希望有一些不同,但是C代码非常简单,所以是因为gcc没有进行太多优化,还是因为它们使用了不同的默认编译器设置
C代码GCC和Borland的分解C代码的差异? 最近我对DIS汇编C代码(非常简单的C代码)感兴趣,并遵循Borland C++编译器V 5.5(编译C代码很好)的教程,所有的工作都有效。然后我决定尝试自己的C代码,并在DEV C++(使用GCC)中编译它们。在IDA Pro中打开它时,我得到了一个惊喜,gcc的asm与Borland的真的不同。我希望有一些不同,但是C代码非常简单,所以是因为gcc没有进行太多优化,还是因为它们使用了不同的默认编译器设置,c,assembly,disassembly,C,Assembly,Disassembly,C代码 int main(int argc, char **argv) { int a; a = 1; } 博尔兰ASM酒店 .text:00401150 ; int __cdecl main(int argc,const char **argv,const char *envp) .text:00401150 _main proc near ; DATA XREF: .data:004090D0 .text:00401150 .te
int main(int argc, char **argv)
{
int a;
a = 1;
}
博尔兰ASM酒店
.text:00401150 ; int __cdecl main(int argc,const char **argv,const char *envp)
.text:00401150 _main proc near ; DATA XREF: .data:004090D0
.text:00401150
.text:00401150 argc = dword ptr 8
.text:00401150 argv = dword ptr 0Ch
.text:00401150 envp = dword ptr 10h
.text:00401150
.text:00401150 push ebp
.text:00401151 mov ebp, esp
.text:00401153 pop ebp
.text:00401154 retn
.text:00401154 _main endp
GCC ASM(以下更新)
GCC更新
在遵循JimR的建议后,我去查看sub_401100是什么,然后我将该代码转到另一个代码,这似乎就是代码(我的假设正确吗?如果GCC的所有代码都在主函数中,那么为什么?)
这里最可能发生的情况是,Borland在使用运行时库中的代码初始化所有内容后,从其启动代码调用main
gcc代码在我看来不像main,而是像调用main的生成代码。在sub_401100处反汇编代码,看看它是否与主进程相似。首先,确保至少已将-O2优化标志启用到gcc,否则根本不会得到优化
通过这个小例子,您并不是真正测试优化,而是看到程序初始化是如何工作的,例如,gcc调用通知windows应用程序类型以及其他初始化。e、 g.sub_401100为运行时注册atexit处理程序。Borland可能会事先调用运行时初始化,而gcc会在main()中调用。Borland编译器似乎意识到您从来没有对
a
执行过任何操作,只是为空的主函数提供了等效的程序集。编译器的输出应该是不同的,对于同一个来源,有时会有显著的不同。就像丰田和本田不同一样。当然有四个轮子和一些座椅,但当你看细节时,会发现它们有很多不同
同样地,具有不同编译器选项的同一个编译器可以而且经常会为同一源代码生成截然不同的输出。即使是看似简单的程序
对于您的简单程序,它实际上什么都不做(代码不影响输入、输出,也不影响函数之外的任何内容),一个好的优化编译器只会生成main:返回一些随机数,因为您没有指定返回值。实际上,它应该给出警告或错误。这是我在比较编译器输出时遇到的最大问题,它使一些事情变得足够简单,可以看到它们在做什么,但使一些事情变得足够复杂,编译器不只是预先计算答案并返回它
在x86的例子中,我想这就是你在这里所说的,现在被微代码化了,真的没有好代码和坏代码的答案,每一个处理器家族都改变了他们的胆量,过去快的是慢的,现在快的在旧处理器上是慢的。因此,对于像gcc这样的编译器来说,随着新内核的不断发展,优化既可以是所有x86e的通用优化,也可以是特定于特定系列的优化(尽管进行了最大优化,但仍会产生不同的代码)
随着您对反汇编的新兴趣,您将继续看到它们的相似性和差异,并了解同一代码可以采用多少种不同的编译方式。这些差异是意料之中的,即使是对于一些琐碎的程序也是如此。我鼓励您尝试尽可能多的编译器。即使是在gcc系列2.x、3.x、4.x以及构建它的不同方法中,也会产生不同的代码,这些代码可能被认为是同一个编译器
好的与坏的输出在旁观者的眼中。使用调试器的人希望他们的代码是可步进的,变量是可观察的(以书面代码顺序)。这使得代码非常大、笨重且速度慢(特别是对于x86)。当您为发布版编译时,最终会得到一个完全不同的程序,到目前为止,您没有花任何时间调试它。此外,为了性能优化,您还冒着编译器优化出您希望它执行的操作的风险(在上面的示例中,不会分配任何变量,也不会执行任何代码,即使是轻微的优化)。或者更糟糕的是,您暴露了编译器中的bug,而您的程序根本无法工作(这就是为什么gcc不推荐使用-O3)。这和/或您会发现C标准中有大量地方的解释是由实现定义的
未优化的代码更容易编译,因为它更明显。在您的示例中,期望是在堆栈上分配一个变量,设置某种堆栈指针排列,立即数1最终写入该位置,堆栈被清除,函数返回。编译器更难出错,程序更可能按预期运行。检测和删除死代码是优化和测试的任务
这就是风险所在。风险往往值得回报。但这取决于用户,美丽在于旁观者的眼睛
底线,简短的回答。预期会有差异(甚至是巨大的差异)。默认编译选项因编译器而异。尝试编译/优化选项和不同的编译器,并继续反汇编程序,以便更好地了解您使用的语言和编译器。到目前为止,你在正确的轨道上。在borland输出的情况下,它检测到您的程序什么也不做,没有使用输入变量,没有使用返回变量,也没有与局部变量相关,也没有全局变量或其他外部变量
.text:00401220 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
.text:00401220
.text:00401220 ; Attributes: bp-based frame
.text:00401220
.text:00401220 public start
.text:00401220 start proc near
.text:00401220
.text:00401220 var_14 = dword ptr -14h
.text:00401220 var_8 = dword ptr -8
.text:00401220
.text:00401220 push ebp
.text:00401221 mov ebp, esp
.text:00401223 sub esp, 8
.text:00401226 mov [esp+8+var_8], 1
.text:0040122D call ds:__set_app_type
.text:00401233 call sub_401100
.text:00401238 nop
.text:00401239 lea esi, [esi+0]
.text:00401240 push ebp
.text:00401241 mov ebp, esp
.text:00401243 sub esp, 8
.text:00401246 mov [esp+14h+var_14], 2
.text:0040124D call ds:__set_app_type
.text:00401253 call sub_401100
.text:00401258 nop
.text:00401259 lea esi, [esi+0]
.text:00401259 start endp
.text:00401100 sub_401100 proc near ; CODE XREF: .text:004010F1j
.text:00401100 ; start+13p ...
.text:00401100
.text:00401100 var_28 = dword ptr -28h
.text:00401100 var_24 = dword ptr -24h
.text:00401100 var_20 = dword ptr -20h
.text:00401100 var_1C = dword ptr -1Ch
.text:00401100 var_18 = dword ptr -18h
.text:00401100 var_C = dword ptr -0Ch
.text:00401100 var_8 = dword ptr -8
.text:00401100
.text:00401100 push ebp
.text:00401101 mov ebp, esp
.text:00401103 push ebx
.text:00401104 sub esp, 24h ; lpTopLevelExceptionFilter
.text:00401107 lea ebx, [ebp+var_8]
.text:0040110A mov [esp+28h+var_28], offset sub_401000
.text:00401111 call SetUnhandledExceptionFilter
.text:00401116 sub esp, 4 ; uExitCode
.text:00401119 call sub_4012E0
.text:0040111E mov [ebp+var_8], 0
.text:00401125 mov eax, offset dword_404000
.text:0040112A lea edx, [ebp+var_C]
.text:0040112D mov [esp+28h+var_18], ebx
.text:00401131 mov ecx, dword_402000
.text:00401137 mov [esp+28h+var_24], eax
.text:0040113B mov [esp+28h+var_20], edx
.text:0040113F mov [esp+28h+var_1C], ecx
.text:00401143 mov [esp+28h+var_28], offset dword_404004
.text:0040114A call __getmainargs
.text:0040114F mov eax, ds:dword_404010
.text:00401154 test eax, eax
.text:00401156 jz short loc_4011B0
.text:00401158 mov dword_402010, eax
.text:0040115D mov edx, ds:_iob
.text:00401163 test edx, edx
.text:00401165 jnz loc_4011F6
.text:004012E0 sub_4012E0 proc near ; CODE XREF: sub_401000+C6p
.text:004012E0 ; sub_401100+19p
.text:004012E0 push ebp
.text:004012E1 mov ebp, esp
.text:004012E3 fninit
.text:004012E5 pop ebp
.text:004012E6 retn
.text:004012E6 sub_4012E0 endp
(gdb) set disassembly-flavor intel
(gdb) disassemble
Dump of assembler code for function main:
0x00401350 <+0>: push ebp
0x00401351 <+1>: mov ebp,esp
0x00401353 <+3>: and esp,0xfffffff0
0x00401356 <+6>: call 0x4018aa <__main>
=> 0x0040135b <+11>: xor eax,eax
0x0040135d <+13>: mov esp,ebp
0x0040135f <+15>: pop ebp
0x00401360 <+16>: ret
End of assembler dump.
(gdb) set disassembly-flavor intel
(gdb) disassemble
Dump of assembler code for function main:
0x00401350 <+0>: push ebp
0x00401351 <+1>: mov ebp,esp
0x00401353 <+3>: and esp,0xfffffff0
0x00401356 <+6>: sub esp,0x10
0x00401359 <+9>: call 0x4018aa <__main>
=> 0x0040135e <+14>: mov DWORD PTR [esp+0xc],0x1
0x00401366 <+22>: mov eax,0x0
0x0040136b <+27>: leave
0x0040136c <+28>: ret
End of assembler dump.
void start()
{
... some initialization code here
int result = main();
... some deinitialization code here
ExitProcess(result);
}