使用本机编译器和交叉编译器生成相同的目标文件

时间:2020-09-29 23:34:09

标签: c linux assembly gcc arm

我正在尝试使用在Ubuntu上运行的交叉编译器来编译一些Raspberry Pi代码。我已经测试了可执行文件,并且可以正常工作,但是将该可执行文件与本机编译器(Raspberry Pi上的gcc)生成的可执行文件进行比较,我发现二进制文件之间存在一些差异。

设置

本机编译器gcc (Raspbian 8.3.0-6+rpi1) 8.3.0在Raspbian GNU / Linux 10(破坏程序)上运行。交叉编译器是arm-linux-gnueabihf-gcc-8 (Ubuntu/Linaro 8.4.0-1ubuntu1~18.04) 8.4.0,可在Ubuntu 18.04.4(Bionic Beaver)上运行。

我试图确保交叉编译器使用与Pi默认使用的相同的编译标志:

  • marm生成以ARM状态(而不是Thumb)运行的代码
  • march=armv6
  • mfpu=vfp
  • O0,我关闭了优化功能以确保没有“有趣”的事情发生

我尝试过的

我写了我能想到的最基本的C代码:

int main() {}

,然后使用统一汇编语言语法将其编译为汇编。两种编译器都生成完全相同的程序集(.ident行除外,但是那无关紧要):

    .arch armv6
    .eabi_attribute 28, 1
    .eabi_attribute 20, 1
    .eabi_attribute 21, 1
    .eabi_attribute 23, 3
    .eabi_attribute 24, 1
    .eabi_attribute 25, 1
    .eabi_attribute 26, 2
    .eabi_attribute 30, 6
    .eabi_attribute 34, 1
    .eabi_attribute 18, 4
    .file   "main.c"
    .text
    .align  2
    .global main
    .arch armv6
    .syntax unified
    .arm
    .fpu vfp
    .type   main, %function
main:
    @ args = 0, pretend = 0, frame = 0
    @ frame_needed = 1, uses_anonymous_args = 0
    @ link register save eliminated.
    str fp, [sp, #-4]!
    add fp, sp, #0
    mov r3, #0
    mov r0, r3
    add sp, fp, #0
    @ sp needed
    ldr fp, [sp], #4
    bx  lr
    .size   main, .-main
    .ident  "GCC: (Ubuntu/Linaro 8.4.0-1ubuntu1~18.04) 8.4.0"
    .section    .note.GNU-stack,"",%progbits

然后我尝试了其他方法:在将目标文件链接到任何共享库之前,我只是构建了目标文件,但是即使那样,本机文件和交叉编译的文件之间也会存在差异。因此,这不是Raspbian和Ubuntu之间安装的库不同的问题。

问题

如果我使用本机编译器和交叉编译器编译此汇编代码,即使它们以相同的方式运行,我也将获得不同的可执行文件。

问题

尽管这没什么大不了,因为两个可执行文件都能按预期工作(它们什么也不做,返回0),我想知道:

  • 为什么会这样?
  • 是否使用的gcc版本略有不同(8.3.0与8.4.0)?
  • 或者这些差异是运行编译器的操作系统固有的吗?
  • 是否可以使用交叉编译器来构建与本机编译器完全相同的可执行文件?即使代码很大又很复杂?

2 个答案:

答案 0 :(得分:1)

链接器可以在二进制文件中添加“内部版本ID”。造成虚假的“差异”。

尝试使用 -Wl,--build-id=none 进行编译。

还有.comment部分,其中包含有关编译器版本和运行平台的信息。之后,您可以使用 strip -R .comment your_binary 剥离它。

除了使用临时linker script(可能不实际)之外,我不知道有什么方法可以让gcc不创建该.comment部分:

SECTIONS { /DISCARD/ : { *(.comment) } } INSERT BEFORE .bss

愚蠢的例子:

cc -Wall -o no_comment \
  -include stdio.h -xc - <<<'int main(){printf("test\n");}' \
  -xnone -Wl,-T /dev/fd/7 /dev/fd/7 7<<<'SECTIONS { /DISCARD/ : { *(.comment) } } INSERT BEFORE .bss' \
  -Wl,--build-id=none

答案 1 :(得分:1)

是的,@ user414777是正确的。

还有

.ident行,但没关系

...实际上以二进制结尾: 尝试readelf -p .comment a.out