[llvm-branch-commits] [clang] bf9e7e8 - [clang][Driver] Link libssp_nonshared.a on musl with stack protector (#219828)
Tobias Hieta via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Sat Sep 5 00:12:26 PDT 2026
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 <sunilkumar.dora at windriver.com>
Co-authored-by: Khem Raj <raj.khem at gmail.com>
(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
More information about the llvm-branch-commits
mailing list