[英]Why assembly code is different for simple C program with different gcc version?
我了解汇编和C编程的基础知识。
我用C编译了以下简单程序,
#include <stdio.h>
int main()
{
int a;
int b;
a = 10;
b = 88
return 0;
}
用以下命令编译,
gcc -ggdb -fno-stack-protector test.c -o测试
使用gcc版本4.4.7的上述程序的反汇编代码为:
5 push %ebp
89 e5 mov %esp,%ebp
83 ec 10 sub $0x10,%esp
c7 45 f8 0a 00 00 00 movl $0xa,-0x8(%ebp)
c7 45 fc 58 00 00 00 movl $0x58,-0x4(%ebp)
b8 00 00 00 00 mov $0x0,%eax
c9 leave
c3 ret
90 nop
但是,与gcc版本4.3.3相同的程序的反汇编代码为:
8d 4c 23 04 lea 0x4(%esp), %ecx
83 e4 f0 and $0xfffffff0, %esp
55 push -0x4(%ecx)
89 e5 mov %esp,%ebp
51 push %ecx
83 ec 10 sub $0x10,%esp
c7 45 f4 0a 00 00 00 00 movl $0xa, -0xc(%ebp)
c7 45 f8 58 00 00 00 00 movl $0x58, -0x8(%ebp)
b8 00 00 00 00 mov $0x0, %eax
83 c4 10 add $0x10,%esp
59 pop %ecx
5d pop %ebp
8d 61 fc lea -0x4(%ecx),%esp
c3 ret
为什么汇编代码不同?
在第二个汇编代码中可以看到,为什么将%ecx压入堆栈?
and $0xfffffff0, %esp
含义and $0xfffffff0, %esp
什么?
注意:操作系统相同
编译器不需要为相同的源代码生成相同的汇编代码。 只要可观察的行为相同,C标准就允许编译器按其认为合适的方式优化代码。 因此,不同的编译器可能会生成不同的汇编代码。
对于您的代码,带有-O3
GCC 6.2只会生成:
xor eax, eax
ret
因为您的代码基本上什么都不做。 因此,它简化为简单的return语句。
为了给您一些想法,有多少种方法可以为特定任务创建有效的代码,我认为这个示例可能会有所帮助。
有时会有大小编码竞赛,显然是针对汇编程序员的,因为在此级别上您根本无法与编译器竞争手写汇编。
竞赛任务相当琐碎,可以通过精确的输入和输出规范(最小到单字节或像素完美)来使入门水平和总精力变得合理。
因此,您几乎要完成一些琐碎的精确任务,即人为生成的代码(目前仍胜过琐碎任务的编译器),并以一个简单的规则“最小大小”为目标。
根据您的逻辑,绝对清楚每个竞争对手都应产生相同的结果。
现实世界对此的答案例如:
Hugi尺寸编码比赛系列 -Compo29-随机迷宫生成器
12个条目,代码大小(以字节为单位):122、122、128、135、136、137、147,... 278(!)。
我敢打赌,前两个条目都具有122B可能足够不同(太懒了,无法实际检查它们)。
现在,从高级编程语言和由机器(编译器)产生有效的机器代码要复杂得多。 而且,编译器无法在推理上与人类竞争,大多数“ c ++编译器如何产生良好的代码”源于C ++语言本身的定义非常接近于机器代码(易于编译),并且源于残酷的CPU功能,使编译器能够针对特定的代码路径处理成千上万的变体,主要通过蛮力搜索接近最佳的解决方案。
优化器背后的数字“推理”仍然以他们自己的方式发展到了人类无法触及的地步,但更像是以他们自己的方式,就像人无法在合理的努力下实现编译器的效率一样用于完整的应用程序编译。
在这一点上,一些调试代码在少数帮助序言/结尾说明中有所不同的原因...即使您发现优化代码有所不同,并且这种差异对人类来说是“显而易见的”,但编译器仍然可以在此方面壮大最不重要的是,因为编译器必须在特定代码上应用通用规则,而不真正了解任务的上下文。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.