使用GCC驱动程序时,是什么导致静态lib"不兼容"?

时间:2015-09-21 13:42:29

标签: c linux gcc musl

所以我要做的是在Ubuntu 14.04(x86_64)上我想根据最新发布的1.1.11版本来设置musl-libc

我做的是:

  1. 为GCC安装multilib支持:sudo apt-get --no-install-recommends install gcc-multilib
  2. 分别为32位和64位配置库,并将它们安装到单独的文件夹中:
    • CFLAGS=-m32 ./configure --prefix=$HOME/bin/musl-32-bit --disable-shared --target=i386-linux-gnu && make && make install
    • CFLAGS=-m64 ./configure --prefix=$HOME/bin/musl-64-bit --disable-shared --target=x86_64-linux-gnu
  3. 然后,为了构建静态链接的premake4,我在Makefile生成的premake4上调用GNU make:

    make -j 8 CC=$HOME/bin/musl-32-bit/bin/musl-gcc ARCH=-m32 LDFLAGS="-v -static" verbose=1
    

    这似乎可以解决链接步骤,该步骤会爆炸:

    Linking Premake4
    $HOME/bin/musl-32-bit/bin/musl-gcc -o bin/release/premake4 intermediate/gmake__/premake.o intermediate/gmake__/os_uuid.o intermediate/gmake__/os_pathsearch.o intermediate/gmake__/os_match.o intermediate/gmake__/os_chdir.o intermediate/gmake__/os_mkdir.o intermediate/gmake__/os_stat.o intermediate/gmake__/os_getversion.o intermediate/gmake__/premake_main.o intermediate/gmake__/os_isdir.o intermediate/gmake__/string_endswith.o intermediate/gmake__/os_isfile.o intermediate/gmake__/scripts.o intermediate/gmake__/path_isabsolute.o intermediate/gmake__/os_rmdir.o intermediate/gmake__/os_getcwd.o intermediate/gmake__/os_is64bit.o intermediate/gmake__/os_copyfile.o intermediate/gmake__/lstate.o intermediate/gmake__/ltable.o intermediate/gmake__/lgc.o intermediate/gmake__/lobject.o intermediate/gmake__/lcode.o intermediate/gmake__/lmathlib.o intermediate/gmake__/lbaselib.o intermediate/gmake__/lmem.o intermediate/gmake__/lfunc.o intermediate/gmake__/lparser.o intermediate/gmake__/ldblib.o intermediate/gmake__/lzio.o intermediate/gmake__/lstrlib.o intermediate/gmake__/lvm.o intermediate/gmake__/lauxlib.o intermediate/gmake__/llex.o intermediate/gmake__/lstring.o intermediate/gmake__/ldump.o intermediate/gmake__/ldebug.o intermediate/gmake__/loadlib.o intermediate/gmake__/lopcodes.o intermediate/gmake__/linit.o intermediate/gmake__/ldo.o intermediate/gmake__/lapi.o intermediate/gmake__/liolib.o intermediate/gmake__/loslib.o intermediate/gmake__/lundump.o intermediate/gmake__/ltm.o intermediate/gmake__/ltablib.o    -v -static -L. -s -rdynamic  -lm -ldl
    Using built-in specs.
    Reading specs from $HOME/bin/musl-32-bit/lib/musl-gcc.specs
    rename spec cpp_options to old_cpp_options
    COLLECT_GCC=gcc
    COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.8/lto-wrapper
    Target: x86_64-linux-gnu
    Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.8.4-2ubuntu1~14.04' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libmudflap --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
    Thread model: posix
    gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04)
    COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/
    LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../lib32/:/lib/../lib32/:/usr/lib/../lib32/:/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../:/lib/:/usr/lib/
    COLLECT_GCC_OPTIONS='-m32' '-o' 'bin/release/premake4' '-v' '-static' '-L.' '-s' '-rdynamic' '-specs=$HOME/bin/musl-32-bit/lib/musl-gcc.specs' '-mtune=generic' '-march=i686'
     /usr/lib/gcc/x86_64-linux-gnu/4.8/collect2 -dynamic-linker /lib/ld-musl-i386.so.1 -nostdlib -static -export-dynamic -z relro -o bin/release/premake4 -s $HOME/bin/musl-32-bit/lib/crt1.o $HOME/bin/musl-32-bit/lib/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.8/crtbegin.o -L. -L$HOME/bin/musl-32-bit/lib -L /usr/lib/gcc/x86_64-linux-gnu/4.8/. intermediate/gmake__/premake.o intermediate/gmake__/os_uuid.o intermediate/gmake__/os_pathsearch.o intermediate/gmake__/os_match.o intermediate/gmake__/os_chdir.o intermediate/gmake__/os_mkdir.o intermediate/gmake__/os_stat.o intermediate/gmake__/os_getversion.o intermediate/gmake__/premake_main.o intermediate/gmake__/os_isdir.o intermediate/gmake__/string_endswith.o intermediate/gmake__/os_isfile.o intermediate/gmake__/scripts.o intermediate/gmake__/path_isabsolute.o intermediate/gmake__/os_rmdir.o intermediate/gmake__/os_getcwd.o intermediate/gmake__/os_is64bit.o intermediate/gmake__/os_copyfile.o intermediate/gmake__/lstate.o intermediate/gmake__/ltable.o intermediate/gmake__/lgc.o intermediate/gmake__/lobject.o intermediate/gmake__/lcode.o intermediate/gmake__/lmathlib.o intermediate/gmake__/lbaselib.o intermediate/gmake__/lmem.o intermediate/gmake__/lfunc.o intermediate/gmake__/lparser.o intermediate/gmake__/ldblib.o intermediate/gmake__/lzio.o intermediate/gmake__/lstrlib.o intermediate/gmake__/lvm.o intermediate/gmake__/lauxlib.o intermediate/gmake__/llex.o intermediate/gmake__/lstring.o intermediate/gmake__/ldump.o intermediate/gmake__/ldebug.o intermediate/gmake__/loadlib.o intermediate/gmake__/lopcodes.o intermediate/gmake__/linit.o intermediate/gmake__/ldo.o intermediate/gmake__/lapi.o intermediate/gmake__/liolib.o intermediate/gmake__/loslib.o intermediate/gmake__/lundump.o intermediate/gmake__/ltm.o intermediate/gmake__/ltablib.o -lm -ldl --start-group /usr/lib/gcc/x86_64-linux-gnu/4.8/libgcc.a /usr/lib/gcc/x86_64-linux-gnu/4.8/libgcc_eh.a -lc --end-group /usr/lib/gcc/x86_64-linux-gnu/4.8/crtend.o $HOME/bin/musl-32-bit/lib/crtn.o
    /usr/bin/ld: skipping incompatible $HOME/bin/musl-32-bit/lib/libc.a when searching for -lc
    /usr/bin/ld: cannot find -lc
    collect2: error: ld returned 1 exit status
    make[1]: *** [bin/release/premake4] Error 1
    make: *** [Premake4] Error 2
    

    相关的一行是:

    /usr/bin/ld: skipping incompatible $HOME/bin/musl-32-bit/lib/libc.a when searching for -lc
    

    现在,我不了解这一点的部分是,ar x libc.a $HOME/bin/musl-32-bit/lib/libc(在musl-libc}的构建步骤中生成的ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped (见上文),它证明所有包含的对象似乎都是正确的目标体系结构(所有显示find $HOME/bin/musl-32-bit/lib -name '*.o' -exec file {} +|grep -v 'ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped' ),因为我可以在发出以下命令时从空白中证明:

    objdump

    事实上,这没有输出。类似地,当使用相同的方法查看构建目录时,我找不到任何与我的期望不符的目标文件。

    为了更好的衡量标准,我决定让libc.a任务告诉我更多有关objdump -a $HOME/bin/musl-32-bit/lib/libc.a|grep 'file format'|grep -v 'file format elf32-i386' 的问题,并得出相同的结果:

    premake4

    所以我的问题有两个:

    1. 什么使静态库失去资格"不兼容"当GCC被要求链接它时?
    2. 我看到的具体问题是什么?
    3. 第一个是我真正感兴趣的东西,但是第二个我要求分享你的麻烦这样的经验。例如,我错过了哪些验证步骤?

      请注意" native" make -j 8 CC=$HOME/bin/musl-64-bit/bin/musl-gcc ARCH=-m64 LDFLAGS=-static verbose=1 可以很好地构建:

      -v

      LDFLAGS标记添加到x86_64-linux-gnu时,从输出中看起来好像目标始终位于null。不过,我还没有找到解决这个问题的方法。

2 个答案:

答案 0 :(得分:4)

简而言之,musl-gcc包装器脚本设置不适合与-m32一起使用。我认为正在发生的事情是,musl-gcc在默认(64位)模式下调用实际的编译器,然后生成的目标文件与(预期的,32位)libc不兼容。

如果将-m32放在生成的包装器脚本中,它可能会有效。如果您将-m32放入$CC(即CC="gcc -m32")而不是将其放入$CFLAGS,则会自动使用最新版本。

更新:如移动到聊天的讨论中所述,可能还需要添加-Wl,-melf_i386(由于musl-gcc包装器使用的规范文件中的缺陷未考虑{ {1}}支持)但似乎还不够。

答案 1 :(得分:2)

解决方案

事实证明解决方案很简单。

我们需要告诉链接器和驱动程序使用-m32 ......我就在那之前。但是,事实证明,缺少的部分是通过CFLAGS将链接器选项传递给驱动程序,如-Wl,-melf_i386

我终于能够在支持multilib的64位主机上构建和链接32位可执行文件。

注意:以下信息留给那些想要了解我如何调查此问题的人。

好吧,所以我进一步研究了这个问题,一旦你提取了目标文件,输出就会更有启发性。要重现我正在做的事情,您可能必须使用允许$(...)的Bash或类似的shell,或者您需要相应地调整命令行。

首先要安装gcc-multilib和朋友,以便定位-m32i386-linux-gnu,这里恰好是i686-linux-gnu的别名)

代码和make文件

我有以下make文件:

CC?=$(HOME)/bin/musl/bin64/musl-gcc
BLDARCH?=-m64
CFLAGS+=-v $(BLDARCH)
LDFLAGS+=-v -static $(BLDARCH)

all: helloworld

helloworld: helloworld.c

clean:
    rm -f helloworld

rebuild: clean all

.PHONY: clean rebuild
.NOTPARALLEL: rebuild

以及以下小helloworld.c

#include <stdio.h>

int main(int argc, char** argv)
{
    printf("Hello world!\n");
    return 0;
}

我的32位musl-libc分别安装到$HOME/bin/musl/{bin,include,lib}32。 64位的分别安装到$HOME/bin/musl/{bin,include,lib}64

试图建立:

make CC=$HOME/bin/musl/bin32/musl-gcc BLDARCH=-m32 rebuild

总是以相同的无意义线失败:

/usr/bin/ld: skipping incompatible ~/bin/musl/lib32/libc.a when searching for -lc
/usr/bin/ld: cannot find -lc
collect2: error: ld returned 1 exit status
make: *** [helloworld] Error 1

深入研究细节

因此经过一番思考后,我决定手动重新执行gcc驱动程序完成的步骤。

这意味着大致运行(我用~替换了所有出现的主文件夹):

  • 编译:{{1​​}}
  • 汇编:/usr/lib/gcc/x86_64-linux-gnu/4.8/cc1 -quiet -imultilib 32 -imultiarch i386-linux-gnu helloworld.c -nostdinc -isystem ~/bin/musl/include32 -isystem /usr/lib/gcc/x86_64-linux-gnu/4.8/include -quiet -dumpbase helloworld.c -m32 -mtune=generic -march=i686 -auxbase helloworld -version -fstack-protector -Wformat -Wformat-security -o /tmp/ccGmMuR1.s
  • 链接:as -v -v --32 -o /tmp/ccgRGlqf.o /tmp/ccGmMuR1.s

显然,这还没有改变错误信息:

env COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/ LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.8/32/:/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../lib32/:/lib/../lib32/:/usr/lib/../lib32/:/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../:/lib/:/usr/lib/ COLLECT_GCC_OPTIONS="-v -v -static -m32 -o helloworld -specs=~/bin/musl/lib32/musl-gcc.specs -mtune=generic -march=i686" /usr/lib/gcc/x86_64-linux-gnu/4.8/collect2 -dynamic-linker /lib/ld-musl-i386.so.1 -nostdlib -static -z relro -o helloworld ~/bin/musl/lib32/crt1.o ~/bin/musl/lib32/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.8/32/crtbegin.o -L~/bin/musl/lib32 -L /usr/lib/gcc/x86_64-linux-gnu/4.8/32/. /tmp/ccpL09mJ.o --start-group /usr/lib/gcc/x86_64-linux-gnu/4.8/32/libgcc.a /usr/lib/gcc/x86_64-linux-gnu/4.8/32/libgcc_eh.a -lc --end-group /usr/lib/gcc/x86_64-linux-gnu/4.8/32/crtend.o ~/bin/musl/lib32/crtn.o

所以我从/usr/bin/ld: skipping incompatible ~/bin/musl/lib32/libc.a when searching for -lc /usr/bin/ld: cannot find -lc collect2: error: ld returned 1 exit status 的命令行中取出-lc并创建了一个文件夹collect2,我在其中提取了我的musl-libc构建生成的整个~/bin/musl/lib32/archive尝试。然后我指示libc.a在哪里找到像这样的目标文件:

链接:collect2

这个要点是取出env COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/ LIBRARY_PATH=/usr/lib/gc c/x86_64-linux-gnu/4.8/32/:/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../lib32/:/lib/../lib32/:/usr/lib/../lib32/:/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../:/lib/:/usr/lib/ COLLECT_GCC_OPTIONS="-v -v - static -m32 -o helloworld -specs=~/bin/musl/lib32/musl-gcc.specs -mtune=generic -march=i686" /usr/lib/gcc/x86_64-linux-gnu/4.8/collect2 -dynamic-linker /lib/ld-musl-i386.so.1 -nostdlib -static -z relro -o helloworld $HOME/bin/musl/lib32/crt1.o ~/bin/musl/lib32/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.8/32/crtbegin.o -L~/bin/musl/lib32 -L /usr/lib/gcc/x86_64-linux-gnu/4.8/32/. /tmp/ccpL09mJ.o --start-group /usr/lib/gcc/x86_64-linux-g nu/4.8/32/libgcc.a /usr/lib/gcc/x86_64-linux-gnu/4.8/32/libgcc_eh.a --end-group /usr/lib/gcc/x86_64-linux-gnu/4.8/32/crtend.o ~/bin/musl/lib32/crtn.o $(find ~/bin/musl/lib32/archive -type f -name '*.o')并附加-lc

这给了我一大堆新的但更有意义的错误,类似于以下错误:

$(find ~/bin/musl/lib32/archive -type f -name '*.o')

情节变浓。显然/usr/bin/ld: Warning: size of symbol `__init_ssp' changed from 1 in ~/bin/musl/lib32/archive/__libc_start_main.o to 65 in ~/bin/musl/lib32/archive/__stack_chk_fail.o /usr/bin/ld: Warning: size of symbol `__funcs_on_exit' changed from 126 in ~/bin/musl/lib32/archive/atexit.o to 1 in ~/bin/musl/lib32/archive/exit.o # more of those /usr/bin/ld: i386 architecture of input file `~/bin/musl/lib32/crt1.o' is incompatible with i386:x86-64 output /usr/bin/ld: i386 architecture of input file `~/bin/musl/lib32/crti.o' is incompatible with i386:x86-64 output # more of those 命令错误地了解了要构建的内容。考虑到管理环境变量的输出,这很奇怪:

collect2

...在我尝试重现COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/ LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.8/32/:/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../lib32/:/lib/../lib32/:/usr/lib/../lib32/:/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../:/lib/:/usr/lib/ COLLECT_GCC_OPTIONS='-v' '-v' '-static' '-m32' '-o' 'helloworld' '-specs=~/bin/musl/lib32/musl-gcc.specs' '-mtune=generic' '-march=i686' 包装器在链接env时遇到的条件时,我使用collect2传递了这些内容。

为了更多地了解GNU编译器的内部结构,需要阅读https://gcc.gnu.org/onlinedocs/gccint/

不幸的是,关于libc.a的部分对我们没有帮助。但collect2的冗长输出看起来很有希望。

我们怎样才能将命令行选项走私到/usr/lib/gcc/x86_64-linux-gnu/4.8/collect2 --help

现在我打算满足于我可以手动运行的任何东西。所以我试图告诉链接器我期望的输出格式。基于我对collect2感兴趣的支持目标列表。

在前一行的末尾传递elf_i386会产生一个有趣的错误输出。许多引用的函数,例如-melf_386__vsyscall__moddi3未定义。这表明它们根本不存在于来自静态库或任何启动__divdi3文件的目标文件中:

.o

正如我在问题中已经澄清的那样,档案中的目标文件都声明它们是~/bin/musl/lib32/archive/aio.o: In function `cleanup': aio.c:(.text+0x5ad): undefined reference to `__vsyscall' aio.c:(.text+0x5bb): undefined reference to `__vsyscall' aio.c:(.text+0x5e8): undefined reference to `__vsyscall' aio.c:(.text+0x5f6): undefined reference to `__vsyscall' aio.c:(.text+0x61d): undefined reference to `__vsyscall' ~/bin/musl/lib32/archive/aio.o:aio.c:(.text+0x62b): more undefined references to `__vsyscall' follow ~/bin/musl/lib32/archive/cpow.o: In function `cpow': cpow.c:(.text+0x4f): undefined reference to `__mulxc3' ~/bin/musl/lib32/archive/cpowf.o: In function `cpowf': cpowf.c:(.text+0x47): undefined reference to `__mulxc3' ~/bin/musl/lib32/archive/cpowl.o: In function `cpowl': cpowl.c:(.text+0x4c): undefined reference to `__mulxc3' ~/bin/musl/lib32/archive/sysconf.o: In function `sysconf': sysconf.c:(.text+0xcc): undefined reference to `__vsyscall' ~/bin/musl/lib32/archive/__getdents.o: In function `__getdents': __getdents.c:(.text+0x13): undefined reference to `__vsyscall' ~/bin/musl/lib32/archive/opendir.o: In function `opendir': opendir.c:(.text+0x37): undefined reference to `__vsyscall' ~/bin/musl/lib32/archive/readdir.o: In function `readdir': readdir.c:(.text+0x1f): undefined reference to `__vsyscall' ~/bin/musl/lib32/archive/__init_tls.o: In function `__init_tls': __init_tls.c:(.text+0x136): undefined reference to `__vsyscall6' __init_tls.c:(.text+0x16e): undefined reference to `__vsyscall'

函数elf32-i386__vsyscall应该在一个名为__vsyscall6的文件中,给定musl-libc中syscall.o的源文件:i386。让我们先验证一下。由于还有一个文件src/internal/i386/syscall.s,因此名称可能不同。文件名中有四个文件src/misc/syscall.c

  • syscall
  • __syscall_cp.o
  • syscall_cp.o
  • syscall.o

使用syscall_ret.o查询这些文件:

nm

符号类型为$ nm -s $(ls |grep syscall) __syscall_cp.o: 00000000 t sccp U __syscall 00000005 T __syscall_cp 00000000 W __syscall_cp_c syscall_cp.o: U __cancel 00000008 T __cp_begin 00000035 T __cp_cancel 00000030 T __cp_end 00000000 T __syscall_cp_asm syscall.o: 00000000 T syscall U __syscall_ret U __vsyscall6 syscall_ret.o: U __errno_location 00000000 T __syscall_ret 的符号未定义,因此链接器希望符号来自外部(每个目标文件的外部)。

最终U是验证这些符号确实从$ nm --defined-only *.o ../*.o|grep vsyscall中丢失所需的内容。

所以交叉构建的libc.a毕竟是错误的。回到绘图板。

我希望这个描述可以帮助其他人找出类似的问题,并在GCC的幕后看。

传奇继续

我真的很惊讶地看到:

libc.a

但是对于提取的目标文件,相应的命令($ nm --defined-only ../libc.a |grep -B 2 vsyscall syscall.o: 0000004b T __syscall 00000000 T __vsyscall 00000031 T __vsyscall6 )将不会产生任何输出。

所以在nm --defined-only *.o ../*.o|grep -B 2 vsyscall内部libc.a看到两个符号,但在提取它们之后它们会消失?奇

让我们在nm

中寻找syscall.o
libc.a

哇?那么$ nm ../libc.a |grep ^syscall syscall.o: syscall_ret.o: syscall.o: syscall_cp.o: 在静态库中存在两次?好吧,看起来它可能只是我们正在寻找的错误。它确实解释了为什么符号消失了。可能后者syscall.o会覆盖运行syscall.o时首次提取的那个。

确认:

ar x ...

在进行32位构建后查看musl-libc源代码树:

$ nm ../libc.a |grep -A 4 ^syscall\.o
syscall.o:
0000004b T __syscall
         U __sysinfo
00000000 T __vsyscall
00000031 T __vsyscall6
--
syscall.o:
00000000 T syscall
         U __syscall_ret
         U __vsyscall6

将前者复制到$ find . -type f -name 'syscall.o' -exec nm {} + ./src/internal/syscall.o: 0000004b T __syscall U __sysinfo 00000000 T __vsyscall 00000031 T __vsyscall6 ./src/misc/syscall.o: 00000000 T syscall U __syscall_ret U __vsyscall6 目录下的名称不会与现有名称冲突,会给其他函数带来更多错误,这表明其他目标文件也可能在生成的{{1}内部作为重复项存在}。

哪些是重复的?

lib32/archive

这样我们就会看到libc.a$ diff <(nm libc.a|grep ':$'|cut -f 1 -d :|sort) <(nm libc.a|grep ':$'|cut -f 1 -d :|sort -u) --- /dev/fd/63 2015-10-05 23:58:53.683804823 +0000 +++ /dev/fd/62 2015-10-05 23:58:53.683804823 +0000 @@ -131,7 +131,6 @@ clogl.o clog.o clone.o -clone.o closedir.o close.o cnd_broadcast.o @@ -1115,7 +1114,6 @@ __syscall_cp.o syscall_cp.o syscall.o -syscall.o syscall_ret.o sysconf.o sysinfo.o 受到重复影响。这表示某些目标文件从clone.o给定的未定义引用到以下符号完全丢失:

  • syscall.o
  • libc.a
  • __divdi3
  • __moddi3
  • __mulxc3
  • __tls_get_new

这些名称恰好与GCC列出的Integer library routines符合。这让我觉得我错过了GCC提供的一个链接库。喜欢__udivdi3?! ...

我有包__umoddi3,这意味着我应该拥有所需的文件:

libgcc

在上一步之后,我决定在Ubuntu 14.04上设置一个基本上处于相同补丁级别的x86_32版本。

然后我将x86_32计算机中的lib32gcc-4.8-dev与x86_64计算机上的$ apt-file list lib32gcc-4.8-dev|grep -E 'libgcc.*\.a' lib32gcc-4.8-dev: /usr/lib/gcc/x86_64-linux-gnu/4.8/32/libgcc.a lib32gcc-4.8-dev: /usr/lib/gcc/x86_64-linux-gnu/4.8/32/libgcc_eh.a 进行了比较。除了&#34;符号值&#34;它们几乎完全相同。 (在libgcc.a术语中)的一些函数。

此外,由于符号位于静态库中,我尝试再次链接静态库。这仅适用于链接器(nm)命令行上的-melf_i386

在尝试使用collect2并注意到这些内容也传递给LDFLAGS后,我将cc1添加到-Wl,-melf_i386,现在它已经有效了。辉煌。

作为旁注:我还在CFLAGS的命令行中交换了/usr/lib/gcc/x86_64-linux-gnu/4.8/collect2ld应该是一个包装器。错误输出完全相同。