所以我想要做的是在Ubuntu 14.04(x86_64)上,我想根据最新发布的1.1.11版本来设置musl-libc
。
我所做的是:
sudo apt-get --no-install-recommends install gcc-multilib
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
然后为了build立一个静态链接的premake4
,我调用GNU make就像这样在premake4
生成的Makefile
:
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
现在我不明白这一点的部分是,当我build立在musl-libc
的构build步骤中生成的libc.a
(到文件夹$HOME/bin/musl-32-bit/lib/libc
)见上文),它certificate了所有包含的对象似乎都是正确的目标体系结构(全部显示ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
),正如我可以certificate从空发出以下命令时:
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'
事实上,这没有产出。 同样,当使用相同的方法查看构build目录时,我找不到与我的期望不符的任何对象文件。
为了好的措施,我决定还要任务objdump
告诉我更多关于libc.a
的问题,并得出了相同的结果:
objdump -a $HOME/bin/musl-32-bit/lib/libc.a|grep 'file format'|grep -v 'file format elf32-i386'
所以我的问题是双重的:
第一个是我真正感兴趣的,但第二个是我要求分享你的经验,像这样的麻烦。 我错过了哪些validation步骤?
请注意,“本机” premake4
build立得很好:
make -j 8 CC=$HOME/bin/musl-64-bit/bin/musl-gcc ARCH=-m64 LDFLAGS=-static verbose=1
在将-v
标志添加到LDFLAGS
时的输出中,看起来好像目标总是停留在x86_64-linux-gnu
。 但是我还没有想出一个解决这个问题的方法。
简而言之, musl-gcc
包装器脚本设置不适合与-m32
一起使用。 我认为发生的事情是,实际的编译器被默认(64位)模式通过musl-gcc
调用,那么生成的目标文件与(预期的,32位)libc不兼容。
如果你把-m32
放在生成的包装器脚本中,它可能会工作。 如果将-m32
放在$CC
(即CC="gcc -m32"
),而不是将其放在$CFLAGS
,则会在最近的版本中自动发生。
更新:正如讨论中提到的移动聊天中所指出的,添加-Wl,-melf_i386
可能也是需要的(由于musl-gcc
包装器使用的规范文件中的缺陷不支持-m32
支持),但仍然似乎不够。
事实证明,解决方案相当简单。
我们需要告诉链接器和驱动程序使用-m32
…我是那么远。 然而,事实证明,缺少的一块是通过CFLAGS
像这样-Wl,-melf_i386
将链接器选项传递给驱动程序。
我终于能够在支持multilib的64位主机上构建和链接32位可执行文件。
注意:以下信息留给那些想了解我如何调查问题的人。
好的,所以我调查了一下这个问题,一旦你提取了对象文件,输出就会变得更有启发性。 要重现我正在做的事情,你可能必须使用Bash或者类似的shell来允许$(...)
或者你需要相应地调整命令行。
首先,安装gcc-multilib
和好友是非常重要的,以便将-m32
( i386-linux-gnu
这里恰好是i686-linux-gnu
的别名)作为目标。
我有以下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
驱动程序完成的步骤。
这意味着粗略运行(我用~
替换了我的主文件夹的所有出现):
/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
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
所以我从collect2
的命令行中取出了-lc
,并创建了一个文件夹~/bin/musl/lib32/archive
,其中我提取了由我的musl-libc构建尝试生成的整个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')
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
传递给我,试图在链接libc.a
时重现collect2
包装遇到的libc.a
。
为了更多地了解GNU编译器的内部,需要阅读https://gcc.gnu.org/onlinedocs/gccint/
不幸的是关于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
应该放在一个名为syscall.o
的文件中,给定musl-libc中的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
丢失libc.a
。
所以交叉构建的libc.a
是有缺陷的。 回到绘图板。
我希望这个描述可以帮助别人弄清楚类似的问题,并看看GCC的幕后。
我真的很惊讶,看到:
$ 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
看到这两个符号,但是解压后它们就消失了? 奇。
让我们来看看libc.a
中的libc.a
:
$ nm ../libc.a |grep ^syscall syscall.o: syscall_ret.o: syscall.o: syscall_cp.o:
哇? 所以syscall.o
在静态库里面存在两次? 那么看起来这可能只是我们正在寻找的错误原因。 这当然可以解释为什么符号消失。 可能后者syscall.o
覆盖了运行ar x ...
时首先提取的那个。
确认:
$ 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
并在完成32位构建之后查看musl-libc源代码树:
$ 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
将前者复制到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
__udivdi3
__umoddi3
这些名称恰好与GCC列出的整数库例程一致。 这让我想我缺少一个由GCC提供的链接库。 像libgcc
…
我有包lib32gcc-4.8-dev
这意味着我应该有所需的文件:
$ 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
在上一步之后,我决定在Ubuntu 14.04上设置x86_32版本,这个版本基本上处于相同的补丁级别。
然后,我将x86_32机器的libgcc.a
与x86_64机器的libgcc.a
进行比较。 除了几个函数的“符号值”(以nm
)之外,它们几乎是相同的。
此外,由于符号在静态库中,我试图再次链接到静态库。 这只-melf_i386
于链接器( collect2
)命令行上的collect2
。
尝试使用LDFLAGS
并注意到这些也传递给cc1
,我将-Wl,-melf_i386
附加到CFLAGS
,现在它工作。 辉煌。
作为一个侧面说明:我也换了/usr/lib/gcc/x86_64-linux-gnu/4.8/collect2
在命令行中的ld
,其中collect2
应该是一个包装。 错误输出是相同的。