在 32 位机器上编译的汇编代码是否与使用 "gcc -m32" 编译的代码不同?

Does assembler code compiled on a 32bit machine differ from code compiled with "gcc -m32"?

我现在正在学习汇编语言。我正在学习的书中的代码示例都是在 x86 32 位机器(我认为)上用 gcc 编译的。为了将我的输出与书中的输出相匹配,我用 "gcc -m32".

编译了我的简单 helloworld.c
#include <stdio.h>

int main(){
    int i;
    for(i=0;i<10;i++){
      printf("Hello World!\n");
    }
    return 0;
}

我从 运行 "objdump -D a32.out | grep -A20 main.:" 得到的输出如下所示:

0000051d <main>:
51d:    8d 4c 24 04             lea    0x4(%esp),%ecx
521:    83 e4 f0                and    [=12=]xfffffff0,%esp
524:    ff 71 fc                pushl  -0x4(%ecx)
527:    55                      push   %ebp
528:    89 e5                   mov    %esp,%ebp
52a:    53                      push   %ebx
52b:    51                      push   %ecx
52c:    83 ec 10                sub    [=12=]x10,%esp
52f:    e8 ec fe ff ff          call   420 <__x86.get_pc_thunk.bx>
534:    81 c3 cc 1a 00 00       add    [=12=]x1acc,%ebx
53a:    c7 45 f4 00 00 00 00    movl   [=12=]x0,-0xc(%ebp)
541:    eb 16                   jmp    559 <main+0x3c>
543:    83 ec 0c                sub    [=12=]xc,%esp
546:    8d 83 f0 e5 ff ff       lea    -0x1a10(%ebx),%eax
54c:    50                      push   %eax
54d:    e8 5e fe ff ff          call   3b0 <puts@plt>
552:    83 c4 10                add    [=12=]x10,%esp
555:    83 45 f4 01             addl   [=12=]x1,-0xc(%ebp)
559:    83 7d f4 09             cmpl   [=12=]x9,-0xc(%ebp)
55d:    7e e4                   jle    543 <main+0x26>

但是在书中是这样的:

它错过了我得到的输出的前三行,除了接下来的两行外,它看起来一点也不像。这是为什么 ?我如何更改我的 compiler/disassembly 设置以使其看起来相似?

您的编译器默认配置为生成与位置无关的二进制文件,这导致与本书存在重大差异。 (这是最近的 GCC 开发)。

如果禁用此功能,您将更接近本书:

gcc -fno-pie -no-pie -m32 hello.c

正如其他人所说,除非您使用完全相同的配置构建完全相同的编译器,否则无法保证您将获得与书中内容相同的代码。

相同版本的 gcc 配置相同,运行 gcc -m32,无论是 运行 在 x86-64 主机还是 i386 主机上都应该是相同的。或者从 ARM 主机交叉编译!

不同之处在于 gcc 版本和默认设置。 (@Employed Russian 指出,主要的是 -fpie 在您的 gcc 中默认打开。相关:32-bit absolute addresses no longer allowed in x86-64 Linux?)对于 32 位代码,PIE 默认打开也有点糟糕,不仅仅是 64,因为在 32 位模式下额外的开销要大得多(没有 RIP 相对寻址。)


除了像 -fno-pie 这样的配置之外,不同版本的 gcc 会产生不同的代码。

无论如何,如果你真的想匹配书中的内容,试试他们使用的相同版本的 gcc。 (希望他们提到这一点?如果没有,请查看它的出版年份以获得粗略的提示)。 您可以在 http://gcc.godbolt.org/.

上尝试每个 gcc 版本,最远可追溯到 4.4

这里是 Godbolt 上的 a link to your sample code,在两个单独的输出窗格中使用编译器 asm 输出和反汇编二进制文件,两者都禁用了优化。

请注意,Matt Godbolt 在没有 default-pie 配置的情况下配置 gcc,但您可以使用 -fpie 获取 asm,就像在桌面上一样。


请注意,对于未优化的代码,与启用优化相比,它更依赖于 gcc 的内部结构。也就是说,-O0 可以让您一窥 gcc "thinks about" 程序的内幕,因为它甚至不尝试优化。 (加上它 spills/reloads 在每个语句之间支持 changing 变量与调试器;这就是为什么它这么慢的部分原因:它故意将一个球和链条绑在你的代码上。所有这种额外的存储/重新加载使其更难阅读;我通常查看 -O2-O3 输出。另请参阅 )