假设你正在使用基于 Debian 的 Linux 发行版,你可以使用如下命令安装 musl:
sudo apt-get install musl-dev
创建一个最简单的 main.c 文件:
#include <stdio.h> int main() { printf("glibc is shit/n"); }
使用如下命令编译:
clang main.c -static -nostdinc -nostdlib -I/usr/include/x86_64-linux-musl -L/usr/lib/x86_64-linux-musl /usr/lib/x86_64-linux-musl/crt1.o /usr/lib/x86_64-linux-musl/crti.o /usr/lib/x86_64-linux-musl/crtn.o -lc
就是这样,这将会生成一个 18.9k 大小的二进制文件,并将打印一句众所皆知的事实。
要让 clang 的 snaitizers 可用,需要修改 LLVM 源。这里有一个补丁和脚本可从头开始克隆和构建 Clang 3.6(要求 Clang、CMake 和 Ninja 构建系统)
musl.patch:
--- a/llvm/projects/compiler-rt/lib/interception/interception_linux.cc +++ b/llvm/projects/compiler-rt/lib/interception/interception_linux.cc @@ -24,7 +24,7 @@ return real == wrapper; } -#if !defined(__ANDROID__) // android does not have dlvsym +#if 0 void *GetFuncAddrVer(const char *func_name, const char *ver) { return dlvsym(RTLD_NEXT, func_name, ver); } --- a/llvm/projects/compiler-rt/lib/lsan/lsan_common.cc +++ b/llvm/projects/compiler-rt/lib/lsan/lsan_common.cc @@ -231,7 +231,7 @@ ForEachExtraStackRange(os_id, ForEachExtraStackRangeCb, frontier); } - if (flags()->use_tls) { + if (0) { LOG_THREADS("TLS at %p-%p./n", tls_begin, tls_end); if (cache_begin == cache_end) { ScanRangeForPointers(tls_begin, tls_end, frontier, "TLS", kReachable); --- a/llvm/projects/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/llvm/projects/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -163,7 +163,7 @@ static uptr g_tls_size; #endif void InitTlsSize() { -#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID +#if 0 typedef void (*get_tls_func)(size_t*, size_t*) DL_INTERNAL_FUNCTION; get_tls_func get_tls; void *get_tls_static_info_ptr = dlsym(RTLD_NEXT, "_dl_get_tls_static_info");
build.sh:
#!/bin/bash cd `dirname $(readlink -f $0)` if [ ! -d llvm ] then git clone --depth 1 -b release_36 https://github.com/llvm-mirror/llvm git clone --depth 1 -b release_36 https://github.com/llvm-mirror/clang llvm/tools/clang git clone --depth 1 -b release_36 https://github.com/llvm-mirror/compiler-rt llvm/projects/compiler-rt fi patch -Np1 -i musl.patch mkdir -p build cd build cmake ../llvm -G Ninja -DCMAKE_BUILD_TYPE=Release -DLLVM_TARGETS_TO_BUILD=X86 -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ ninja
当你搞定了 compiler-rt 补丁并替换系统文件,就可以通过下面命令来编译 main.c 文件,但这次我们启用了 LeakSanitizer :
clang main.c -g -fsanitize=leak -static -nostdinc -nostdlib -I/usr/include/x86_64-linux-musl -L/usr/lib/x86_64-linux-musl -L/usr/lib/gcc/x86_64-linux-gnu/4.8 /usr/lib/x86_64-linux-musl/crt1.o /usr/lib/x86_64-linux-musl/crti.o /usr/lib/x86_64-linux-musl/crtn.o -lgcc_eh -lc
注意其中一个路径指向 GCC 4.8 版本,替换成你本机的版本。