Categories:
在 Ubuntu 上使用 musl-libc
一个奇怪的 Bug: Linker 可能不支持 musl-libc
一开始使用 musl-gcc
静态编译 Hello World 会直接出现 Segmentation Fault .
摸不着头脑, 看到别人用 strace
追踪系统调用 (从 How the hell-o world?! https://soccasys.com/2018/05/20/how-the-hell-o-world/)
$ strace ./hello
execve("./hello", ["./hello"], 0x7fff219031e0 /* 27 vars */) = 0
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x400040} ---
+++ killed by SIGSEGV (core dumped) +++
Segmentation fault (core dumped)
这时候上网搜了一下才搜到 https://bbs.archlinux.org/viewtopic.php?id=239533
原来是一个 Bug https://bugs.archlinux.org/task/59540
大概原因如下(看不懂)
Details
Description:
Simple static linking is broken with 2.31 ld because it does not put program headers into a load section unless there is some other read only loaded section. Causes applications build with musl-gcc and musl-clang to segfault.
The bug tracker for binutils shows it was fixed on 2018-07-23 and the last comment says "Fixed for 2.32 and on 2.31 branch", Link:
https://sourceware.org/bugzilla/show_bug.cgi?id=23428
I don't know if a back-port is required or just an update on the 2.31 branch.
Additional info:
package: binutils 2.31.1-1
Steps to reproduce:
http://www.openwall.com/lists/musl/2018/07/18/6
using musl-static
然后看了看 binutils 的版本是对的。再看一看 Linker, 发现 Linker 是 lld 13.0。
把 Linker 换回来
sudo update-alternatives --set ld /bin/ld.bfd
然后再编译就奇迹般地没事了。
musl-gcc -static -Os hello.c
这看起来是 lld
的一个 bug 。
可以看 https://sourceware.org/bugzilla/show_bug.cgi?id=23428
在 Ubuntu 使用 musl-lib 编译 OpenSSL 的艰辛之旅
在 Ubuntu 编译 OpenSSL 会遇到一堆问题。
首先是 musl-gcc
是不能链接 Linux Header 的, 你需要自己写一个 musl-clang
去规避这个问题。
- 在 Ubuntu 上安装 Clang https://randoruf.github.io/2022/01/18/llvm-installation.html
- 写一个
musl-clang
(目前还不支持 C++) https://gist.github.com/randoruf/d1aa4e8acb0a852addcd2b84fc003719
如果 musl-libc 和 glic 混用的后果
就是会提示缺失 symbols
It seems that your OpenSSL is not built against musl-libc.
The musl-libc has its own dynamic linker (see https://wiki.musl-libc.org/faq.html), we could create a soft link for the musl dynamic linker. (-syslibdir
is the directory in which the dynamic library, e.g. ld-musl-x86_64.so.1
, is, see https://wiki.musl-libc.org/getting-started.html)
sudo ln -sf <YOUR-MUSL-LIBC-syslibdir/ld-musl-x86_64.so.1> /usr/bin/musl-ldd
Then you could see whether openssl is built against musl-libc. When I build OpenSSL using glibc, it shows the following error
$ musl-ldd <YOUR-OPENSSL-SRC>/libcrypto.so.1.1
musl-ldd (0x7fcd5a749000)
libdl.so.2 => musl-ldd (0x7fcd5a749000)
libpthread.so.0 => musl-ldd (0x7fcd5a749000)
libc.so.6 => musl-ldd (0x7fcd5a749000)
Error relocating ./libcrypto.so.1.1: makecontext: symbol not found
Error relocating ./libcrypto.so.1.1: setcontext: symbol not found
Error relocating ./libcrypto.so.1.1: __register_atfork: symbol not found
Error relocating ./libcrypto.so.1.1: getcontext: symbol not found
And the glib dynamic linker works fine,
$ ldd <YOUR-OPENSSL-SRC>/libcrypto.so.1.1
linux-vdso.so.1 (0x00007ffd395a6000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007ff6e6e64000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007ff6e6e41000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff6e6c4f000)
/lib64/ld-linux-x86-64.so.2 (0x00007ff6e71d7000)
To build OpenSSL using musl-libc, we have to also specify the location of linux headers to avoid errors like <linux/mman.h>
I only have attempted to build OpenSSL using Clang and Musl-libc, here is the clang wrapper I used https://gist.github.com/randoruf/d1aa4e8acb0a852addcd2b84fc003719.
(taken from https://qiita.com/kakinaguru_zo/items/399ab7ea716a56aef50c which is written by kakinaguru_zo)
But there are still a few issues in the clang-wrapper.
This wrapper will link the startfile (e.g. Scrt1.o
) regardless of building libraries or executables. Apparently, only executables need startfile. Hence, if you use this wrapper, you may encounter the following strange error (main
symbol not found):
$ musl-clang mylibrary.c -shared -fPIC -o libmylibrary.so
$ musl-ldd libmylibrary.so
ld-musl-x86_64.so.1 (0x7f49faef7000)
libc.so => ld-musl-x86_64.so.1 (0x7f49faef7000)
Error relocating libmylibrary.so: main: symbol not found
Since the library has the startfile, it may have an entry to main
. This is the reason why the main
symbol is not found.
Another issue is that test_errstr
, test_ca
, test_ssl_new
will not pass. See Why these test case will fail?
The final issue is that this wrapper only supports c language. Another wrapper may be helpful see https://github.com/esjeon/musl-clang/blob/master/musl-clang
About the Test Case in OpenSSL
test_errstr
glic and musl-c have different descriptions for the same error code,
for example, in glibc
define[EADDRINUSE] str[Address already in use]
But in musl-c
E(EADDRINUSE, "Address in use")
If the target system is different (ths operating system is not built against musl-c), these three cases will fail.
This could be found at test/recipes/02-test_errstr.t
my $perr = eval {
# Set $! to the error number...
local $! = $errnum;
# ... and $! will give you the error string back
$!
};
...
ok($oerr[0] eq $perr, "($errnum) '$oerr[0]' == '$perr'");
We can see that the openssl test compares the error code with perl.
test_ca
and test_ssl_new
These two test cases have the following errors:
$ ../../util/shlib_wrap.sh /usr/bin/perl -I ../../util/perl ../generate_ssl_tests.pl ../ssl-tests/01-simple.conf.in > 01-simple.conf.4548.tmp
/usr/bin/perl: error while loading shared libraries: /lib/x86_64-linux-gnu/libc.so: invalid ELF header
We can trace back to shlib_wrap.sh
file, and we can see that
LIBCRYPTOSO="${THERE}/libcrypto.so.1.1"
LIBSSLSO="${THERE}/libssl.so.1.1"
...
LD_LIBRARY_PATH="${THERE}:$LD_LIBRARY_PATH" # Linux, ELF HP-UX
It means the shell script wants to load our musl-openssl as normal .so
file.
To verify this thought, use the ldd
to load the musl-openssl.
$ ldd libcrypto.so.1.1
./libcrypto.so.1.1: error while loading shared libraries: /lib/x86_64-linux-gnu/libc.so: invalid ELF header
This time it gives useful error info.