llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-driver
Author: windsunil
<details>
<summary>Changes</summary>
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.
---
Full diff: https://github.com/llvm/llvm-project/pull/219828.diff
4 Files Affected:
- (modified) clang/docs/ReleaseNotes.md (+4)
- (modified) clang/lib/Driver/ToolChains/Gnu.cpp (+18)
- (added) clang/test/Driver/Inputs/musl_ssp_tree/usr/lib/libssp_nonshared.a ()
- (added) clang/test/Driver/linux-musl-ssp.c (+28)
``````````diff
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index bdbabf2cd98d0..47fb498cd5e3f 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -205,6 +205,10 @@ features cannot lower the translation-unit ABI level;
- Clang tools now resolve tool names without a path in compilation databases
through `PATH`.
+- On musl targets, the driver now links ``libssp_nonshared.a`` when stack
+ protection is enabled and the library is present in the toolchain library
+ paths, matching what musl distributions configure GCC to do.
+
- Clang now allows GNU computed `goto` extension in `constexpr` functions,
matching the relaxed
`constexpr` function body rules introduced in C++23.
diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp
b/clang/lib/Driver/ToolChains/Gnu.cpp
index 04f3b8d2200d6..5285f55897732 100644
--- a/clang/lib/Driver/ToolChains/Gnu.cpp
+++ b/clang/lib/Driver/ToolChains/Gnu.cpp
@@ -535,6 +535,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..4e6bc9cc427ce
--- /dev/null
+++ b/clang/test/Driver/linux-musl-ssp.c
@@ -0,0 +1,28 @@
+// 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 \
+// RUN: --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 \
+// RUN: --sysroot=%S/Inputs/musl_ssp_tree -fstack-protector-strong \
+// RUN: -fno-stack-protector %s 2>&1 | FileCheck --check-prefix=NOSSP %s
+// NOSSP-NOT: "-lssp_nonshared"
+
+// Not without any stack protector flag.
+// RUN: %clang -### --target=i686-unknown-linux-musl \
+// RUN: --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 \
+// RUN: --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 \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree -fstack-protector-strong %s \
+// RUN: 2>&1 | FileCheck --check-prefix=NOSSP %s
``````````
</details>
https://github.com/llvm/llvm-project/pull/219828
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits