Author: windsunil Date: 2026-09-05T09:11:56+02:00 New Revision: bf9e7e8d773b7207b18e1709fa50c2922131335a
URL: https://github.com/llvm/llvm-project/commit/bf9e7e8d773b7207b18e1709fa50c2922131335a DIFF: https://github.com/llvm/llvm-project/commit/bf9e7e8d773b7207b18e1709fa50c2922131335a.diff LOG: [clang][Driver] Link libssp_nonshared.a on musl with stack protector (#219828) While upgrading clang/llvm to 23.1.0 in openembedded-core I hit this link failure on 32-bit x86 musl: ld: undefined reference to `__stack_chk_fail_local' I dug into it. musl's libc has __stack_chk_fail but not __stack_chk_fail_local. GCC emits calls to the _local variant in PIC/PIE code on some targets - I checked with GCC 16: 32-bit x86 does it, x86_64 does not. So on those targets, any GCC-built object linked with clang on musl fails once stack protection is used. Distros already solve this on the GCC side: Alpine and OpenEmbedded ship a tiny libssp_nonshared.a containing just that symbol, and patch GCC to add -lssp_nonshared when stack protection is on. Both carry the same downstream patch for clang too (OpenEmbedded since 2016), and the GCC side is being fixed in parallel (gcc PR driver/127138, v2 on gcc-patches: https://gcc.gnu.org/pipermail/gcc-patches/2026-August/729351.html) This patch makes the clang driver do what those patched GCCs do: on musl, when stack protection is enabled, add -lssp_nonshared - but only if the library is actually present in the toolchain library paths. Toolchains that do not ship it see no change. Tested on i686 musl: a GCC 16 -fPIC -fstack-protector-strong object fails to link with current clang and links fine with this change. Added a driver test; the rest of clang/test/Driver is unaffected. --------- Signed-off-by: Sunil Dora <[email protected]> Co-authored-by: Khem Raj <[email protected]> (cherry picked from commit fd974c4293015388337e2f66f817a23e5873389f) Added: clang/test/Driver/Inputs/musl_ssp_tree/usr/lib/libssp_nonshared.a clang/test/Driver/linux-musl-ssp.c Modified: clang/lib/Driver/ToolChains/Gnu.cpp Removed: ################################################################################ diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index 24076d8814322..2fad9327dd4cf 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -533,6 +533,24 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nolibc)) CmdArgs.push_back("-lc"); + // musl does not provide __stack_chk_fail_local, but GCC emits calls + // to it in PIC/PIE code on some targets (32-bit x86, PowerPC). musl + // distributions ship the symbol in libssp_nonshared.a and make GCC + // link it when stack protection is on; match that if the library + // exists. + if (ToolChain.getTriple().isMusl()) { + bool WantsSSP = ToolChain.GetDefaultStackProtectorLevel( + /*KernelOrKext=*/false) != LangOptions::SSPOff; + if (Arg *A = Args.getLastArg(options::OPT_fno_stack_protector, + options::OPT_fstack_protector, + options::OPT_fstack_protector_all, + options::OPT_fstack_protector_strong)) + WantsSSP = !A->getOption().matches(options::OPT_fno_stack_protector); + if (WantsSSP && + ToolChain.GetFilePath("libssp_nonshared.a") != "libssp_nonshared.a") + CmdArgs.push_back("-lssp_nonshared"); + } + // Add IAMCU specific libs, if needed. if (IsIAMCU) CmdArgs.push_back("-lgloss"); diff --git a/clang/test/Driver/Inputs/musl_ssp_tree/usr/lib/libssp_nonshared.a b/clang/test/Driver/Inputs/musl_ssp_tree/usr/lib/libssp_nonshared.a new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/linux-musl-ssp.c b/clang/test/Driver/linux-musl-ssp.c new file mode 100644 index 0000000000000..4e48a20ea52cc --- /dev/null +++ b/clang/test/Driver/linux-musl-ssp.c @@ -0,0 +1,23 @@ +// Check that on musl the driver links libssp_nonshared.a when stack +// protection is enabled and the sysroot provides the library. + +// RUN: %clang -### --target=i686-unknown-linux-musl --sysroot=%S/Inputs/musl_ssp_tree -fstack-protector-strong %s 2>&1 \ +// RUN: | FileCheck --check-prefix=SSP %s +// SSP: "-lc" "-lssp_nonshared" + +// Not with stack protection disabled (last flag wins). +// RUN: %clang -### --target=i686-unknown-linux-musl --sysroot=%S/Inputs/musl_ssp_tree -fstack-protector-strong -fno-stack-protector %s 2>&1 \ +// RUN: | FileCheck --check-prefix=NOSSP %s +// NOSSP-NOT: "-lssp_nonshared" + +// Not without any stack protector flag. +// RUN: %clang -### --target=i686-unknown-linux-musl --sysroot=%S/Inputs/musl_ssp_tree %s 2>&1 \ +// RUN: | FileCheck --check-prefix=NOSSP %s + +// Not on glibc: libc_nonshared.a is linked via the libc.so linker script. +// RUN: %clang -### --target=i686-unknown-linux-gnu --sysroot=%S/Inputs/musl_ssp_tree -fstack-protector-strong %s 2>&1 \ +// RUN: | FileCheck --check-prefix=NOSSP %s + +// Not when the sysroot does not provide the library. +// RUN: %clang -### --target=i686-unknown-linux-musl --sysroot=%S/Inputs/basic_linux_tree -fstack-protector-strong %s 2>&1 \ +// RUN: | FileCheck --check-prefix=NOSSP %s _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
