如何让编译器生成一个"elf32-x86-64"格式的目标文件?

How to make compiler generate a "elf32-x86-64" format object file?

首先,关于 elf32-x86-64 格式的一些背景信息。

这是一种在强制使用 32 位指针的同时利用 64 位硬件的格式。 Ref1 and Ref2.

问题

我正在尝试将 link Google 测试框架二进制文件添加到我的项目中。

我使用 objdump -f 检查 Google 测试二进制文件和我的二进制文件的格式。

Google 测试格式为 elf64-x86-64。我的 elf32-x86-64。所以他们不能link一起编辑。

然后我将以下内容添加到 google 测试的 internal_utils.cmake 文件中:

set(ZEPHYR_LINK_FLAGS "-Wl,--oformat=elf32-x86-64")
set(CMAKE_EXE_LINKER_FLAGS  "${CMAKE_EXE_LINKER_FLAGS} ${ZEPHYR_LINK_FLAGS}")

希望linker标志可以把输出格式改成elf32-x86-64.

但是 google 测试构建失败并出现以下错误:

/usr/lib/gcc/x86_64-linux-gnu/7/libstdc++.so: error adding symbols: File in wrong format

/usr/lib/gcc/x86_64-linux-gnu/7/libstdc++.so也是一种elf64-x86-64格式。

并且我查看了生成的目标文件,如: ./googletest/CMakeFiles/gtest_main.dir/src/gtest_main.cc.o

还是elf64-x86-64.

因此 linker 标志似乎不影响目标文件格式。

我记得 linker ld 会根据第一次遇到的目标文件来选择输出格式。所以我想我需要告诉 编译器 输出 elf32-x86-64 格式。

如何让编译器输出一个elf32-x86-64目标文件?

添加 1 - 3:29 下午 11/1/2019

我已经通过以下调整将 Google 测试编译为 elf32-x86-64

现在输出二进制文件 libgtest.alibgtest_main.aelf32-x86-64。但它们需要 linked 到 libstdc++.so。到目前为止,它在我的系统上是 elf64-x86-64。我还没有找到 elf32-x86-64。因此出现以下错误:

/usr/lib/gcc/x86_64-linux-gnu/7/libstdc++.so: error adding symbols: File in wrong format

添加 2 - 3:47 2019 年 11 月 1 日下午

安装 sudo apt-get install gcc-multilib g++-multilib (ref) 后,我在以下位置获得了 libstdc++.soelf32-x86-64 版本:

/usr/lib/gcc/x86_64-linux-gnu/7/x32/libstdc++.so

最终指向/usr/libx32/libstdc++.so.6.0.25

现在看来我只需要找到一种方法告诉 link 用户使用它...非常接近!

添加 3 - 2:44 2019 年 11 月 4 日下午

感谢 FlorianEmployedRussian,我更改 Google 测试的 internal_utils.cmake 文件以添加以下 4 行:

set(MY_COMPILE_FLAGS "-mx32")
set(cxx_base_flags "${cxx_base_flags} ${MY_COMPILE_FLAGS}") 
set(MY_LINK_FLAGS "-mx32")
set(CMAKE_EXE_LINKER_FLAGS  "${CMAKE_EXE_LINKER_FLAGS} ${MY_LINK_FLAGS}")

现在生成的可执行文件是 elf32_x86-64 格式。

所以基本上,我将 -mx32 添加到 两个 编译和 link 标志。

并且在生成的 rules.ninja 文件中,link 规则如下:

command = $PRE_LINK && /usr/bin/c++ $FLAGS $LINK_FLAGS $in -o $TARGET_FILE $LINK_PATH $LINK_LIBRARIES && $POST_BUILD

$FLAGS$LINK_FLAGSbuild.ninja文件中定义如下:

FLAGS = -Wall -Wshadow -Werror  -mx32 ...
LINK_FLAGS = -mx32 ...

基本上,$FLAGS $LINK_FLAGS 贡献的 ninja 命令定义中有 2 个 -mx32 选项。

那么为什么我需要指定两次-mx32

而且我不明白为什么我可以为CMAKE_EXE_LINKER_FLAGS指定-mx32

首先,-mx32只是一个编译选项(ref),不是一个linker选项。

其次,根据 link 规则定义,$LINK_FLAGS 被传递给 usr/bin/c++ 而没有 -Wl, 前缀,因此即使是选项也可以被 linker,不会传给linker。

如果您将其作为 gcc -mx32 调用,GCC 将相应地调整链接器命令行。它不仅仅是一个编译器标志。