binutils / ld的自定义编译在档案中找不到符号

时间:2014-07-28 03:30:30

标签: arm clang ld binutils

我目前正在尝试为裸机aarch64目标编译Clang / LLVM。编译Clang非常简单 - 实际上我已经编译为针对多种架构,包括arm和aarch64。对于后端我正在使用binutils。由于binutils只针对一个架构我已经构建了aarch64和arm版本。再次建设似乎很简单。我使用:

为aarch64构建了binutils
mkdir build
cd build
../configure --target=aarch64-none-elf
make

来自binutils 2.24的解压缩源包。

我遇到的问题是我无法获得ld的自定义构建来正确处理存档文件。它似乎没有问题地找到并打开存档文件,但在编译最终二进制文件时无法搜索未定义的符号。通过一个例子,这里有一些更具体的细节:

通过编译创建一个简单的main.s文件:

int foo();
int main() { return foo(); } 

使用Clang并使用--target = aarch64 -S,即发出特定于体系结构的程序集文件。

通过编译来创建foo.s:

int foo() { return 0; }

使用binutils中的自定义气体构建将.s文件组装到.o文件。

通过使用ar cr foo.a foo.s和ranlib libfoo.a从binutils运行自定义ar和ranlib构建来创建存档libfoo.a。

尝试使用ld -L将两个文件链接在一起。 -lfoo -o main.elf main.o。

输出显示对foo的未定义引用。

bar.cpp:(.text+0x14): undefined reference to `foo()'

我可以在foo.a上运行readelf,它看起来非常完美。特别是我可以看到foo的公共符号。如果我用--verbose运行ld,那么我看到

attempt to open ./libfoo.a succeeded

但没有迹象表明它有任何符号。

如果我直接链接目标文件,即使用ld -o main.elf foo.o main.o,那么我会得到一个格式正确的精灵文件。此外,如果我从libfoo.a中提取foo.o,那么我也可以成功地链接到提取的foo.o。

有没有人有任何想法可能会发生这种情况?我很确定我的clang构建是可以的,因为发出的汇编文件有效地将问题与clang解耦。我猜也是组装的.o文件很好。所以这只留下ar / ranlib或ld作为罪魁祸首。

为了尝试消除ar / ranlib作为罪魁祸首,我为arm重建了binutils(相同的步骤,但使用--target = arm-none-eabi)。如果我将构建的ar / ranlib二进制文件集成到一个已知良好的arm-eabi-none GCC工具链中,那么它们似乎可以正常工作。因此,我的怀疑现在指向ld。请注意,如果我使用我的Clang构建和binutils的arm构建,我会遇到与上面的main / foo示例相同的问题。

我也尝试将ld的arm版本集成到现有的已知良好的GCC工具链中,但得到了:

this linker was not configured to use sysroots

需要明白这一点。这对我来说仍然有点神秘。它阻止我检查arm ld build的健全性。

我可能正在做一些明显错误的事情,但现在我没有看到它。

注意:

  • 我不得不破解binutils的make脚本来添加几个-Wno-xxx标志。我需要以“正确”的方式做到这一点,但我不认为这种黑客会影响输出。

  • 我正在64位OSX 10.9.4上构建/托管所有工具。

更新

关于sysroots的错误很简单。预先存在的工具链配置了标志:

--with-prefix $SOME_INSTALL_DIR
--with-sysroot $SOME_INSTALL_DIR/arm-none-eabi

如果我用这些重建,那么我可以插入我的ld版本没有问题,它的工作原理。我很兴奋,认为这可能是我的错误。以前我没有运行make install,因为在这个阶段我并不真正关心安装。我想也许我的ld的新版本以某种方式引用了OSX系统库/ exes(虽然我不确定它可以引用什么,除了ar之外,即它运行ar来处理档案) 。但是,即使按照这样配置,我仍然对arm和arrach64版本的binutils都有同样的问题。

1 个答案:

答案 0 :(得分:0)

看起来我是在大力推翻这个问题,也错过了一些我从未意识到的关于ld的事情。问题在于:

 ld -L. -lfoo -o main.elf main.o

我没有意识到ld对目标文件/库的排序很敏感。对foo()的未定义引用在main.o中。在解析 main.o之前,我将库libfoo.a指定为输入。这意味着链接器不会在符号上搜索libfoo.a,因为它已经处理了这个库。 main.o必须在之前指定,例如

ld -L. main.o -lfoo -o main.elf

使用--start-group ... --end-group包装-lfoo也无法修复此问题。

我仍然对此感到有些惊讶。我还没有说服自己这是ld的一个很好的特点。似乎我现在能想到的唯一用例是偷偷地允许重复的符号。

喝杯茶的时间!