[PATCH 45/59] Check if linker sets --no-undefined-version by default

Adhemerval Zanella adhemerval.zanella@linaro.org
Fri Oct 17 19:13:20 GMT 2025


Recent lld version default to --no-undefined-version, which triggers
errors when building multiple libraries.  For ld.so it fails with:

ld.lld: error: version script assignment of 'GLIBC_2.4' to symbol '__stack_chk_guard' failed: symbol not defined
ld.lld: error: version script assignment of 'GLIBC_PRIVATE' to symbol '__nptl_set_robust_list_avail' failed: symbol not defined
ld.lld: error: version script assignment of 'GLIBC_PRIVATE' to symbol '__pointer_chk_guard' failed: symbol not defined
ld.lld: error: version script assignment of 'GLIBC_PRIVATE' to symbol '_dl_starting_up' failed: symbol not defined

While for libc.so:

ld.lld: error: version script assignment of 'GLIBC_2.17' to symbol '_IO_clearerr' failed: symbol not defined
ld.lld: error: version script assignment of 'GLIBC_2.17' to symbol '_IO_fgetc' failed: symbol not defined
ld.lld: error: version script assignment of 'GLIBC_2.17' to symbol '_IO_fileno' failed: symbol not defined
ld.lld: error: version script assignment of 'GLIBC_2.17' to symbol '_IO_freopen' failed: symbol not defined
ld.lld: error: version script assignment of 'GLIBC_2.17' to symbol '_IO_fscanf' failed: symbol not defined
ld.lld: error: version script assignment of 'GLIBC_2.17' to symbol '_IO_fseek' failed: symbol not defined
ld.lld: error: version script assignment of 'GLIBC_2.17' to symbol '_IO_peekc_unlocked' failed: symbol not defined
ld.lld: error: version script assignment of 'GLIBC_2.17' to symbol '_IO_stderr_' failed: symbol not defined
ld.lld: error: version script assignment of 'GLIBC_2.17' to symbol '_IO_stdin_' failed: symbol not defined
ld.lld: error: version script assignment of 'GLIBC_2.17' to symbol '_IO_stdout_' failed: symbol not defined
ld.lld: error: version script assignment of 'GLIBC_2.17' to symbol '_IO_pclose' failed: symbol not defined
ld.lld: error: version script assignment of 'GLIBC_2.17' to symbol '_IO_perror' failed: symbol not defined
ld.lld: error: version script assignment of 'GLIBC_2.17' to symbol '_IO_rewind' failed: symbol not defined
ld.lld: error: version script assignment of 'GLIBC_2.17' to symbol '_IO_scanf' failed: symbol not defined
ld.lld: error: version script assignment of 'GLIBC_2.17' to symbol '_IO_setbuf' failed: symbol not defined
ld.lld: error: version script assignment of 'GLIBC_2.17' to symbol '_IO_setlinebuf' failed: symbol not defined
ld.lld: error: version script assignment of 'GLIBC_2.17' to symbol '_IO_wdefault_setbuf' failed: symbol not defined
ld.lld: error: version script assignment of 'GLIBC_2.17' to symbol '_IO_wfile_setbuf' failed: symbol not defined
ld.lld: error: version script assignment of 'GLIBC_2.17' to symbol '__ctype32_tolower' failed: symbol not defined
ld.lld: error: version script assignment of 'GLIBC_2.17' to symbol '__ctype32_toupper' failed: symbol not defined
ld.lld: error: too many errors emitted, stopping now (use --error-limit=0 to see all errors)

The way version script is created with multiple missing symbols is
to simplify the build for multiple ABIs with different symbol
symbols.  For instance, __stack_chk_guard is defined by default to
avoid the need of each ABI to add this symbol on its own version
script depending of which stack protector ABI it uses.

The libc.so warnings does show unused symbol being defined (like
_IO_clearerr), which might trigger potential errors depending of
how symbol are exported.  However, since we do have teh ABI checks
for missing and extra symbol the linker extra checks are not really
required.  So disable them for now.
---
 Makerules    |  2 +-
 configure    | 40 ++++++++++++++++++++++++++++++++++++++++
 configure.ac | 17 +++++++++++++++++
 3 files changed, 58 insertions(+), 1 deletion(-)

diff --git a/Makerules b/Makerules
index 7714888cdc..425bf758a1 100644
--- a/Makerules
+++ b/Makerules
@@ -508,7 +508,7 @@ ifeq ($(build-shared),yes)
 map-file = $(firstword $($(@F:.so=-map)) \
 		       $(addprefix $(common-objpfx), \
 				   $(filter $(@F:.so=.map),$(version-maps))))
-load-map-file = $(map-file:%=-Wl,--version-script=%)
+load-map-file = $(map-file:%=-Wl,--version-script=%) $(undefined-version)
 endif
 
 # Compiler arguments to use to link a shared object with libc and
diff --git a/configure b/configure
index 38e7d820c5..26f6682c1e 100755
--- a/configure
+++ b/configure
@@ -8839,6 +8839,46 @@ fi
 config_vars="$config_vars
 no-time-bits-source = $no_time_bits_source"
 
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the linker sets --no-undefined-version by default" >&5
+printf %s "checking whether the linker sets --no-undefined-version by default... " >&6; }
+if test ${libc_cv_undefined_version+y}
+then :
+  printf %s "(cached) " >&6
+else case e in #(
+  e) cat > conftest.script << EOF
+VERSION_1.0 { global: bar; };
+EOF
+old_LDFLAGS="$LDFLAGS"
+LDFLAGS="-Wl,--version-script=conftest.script -shared"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+extern int und (void);
+int
+main (void)
+{
+int foo (void) { return und (); }
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+  libc_cv_undefined_version=
+else case e in #(
+  e) libc_cv_undefined_version=-Wl,--undefined-version ;;
+esac
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+    conftest$ac_exeext conftest.$ac_ext
+LDFLAGS="$old_LDFLAGS"
+rm conftest.* ;;
+esac
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_cv_undefined_version" >&5
+printf "%s\n" "$libc_cv_undefined_version" >&6; }
+config_vars="$config_vars
+undefined-version = $libc_cv_undefined_version"
+
 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the assembler requires one version per symbol" >&5
 printf %s "checking whether the assembler requires one version per symbol... " >&6; }
 if test ${libc_cv_symver_needs_alias+y}
diff --git a/configure.ac b/configure.ac
index 0a6badeb19..7111d081f2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1853,6 +1853,23 @@ AS_IF([test "$libc_cv_compiler_default_time_bits" = yes],
 AC_SUBST(no_time_bits_source)
 LIBC_CONFIG_VAR([no-time-bits-source], [$no_time_bits_source])
 
+dnl Check if linker sets --no-undefined-version by default
+AC_CACHE_CHECK([whether the linker sets --no-undefined-version by default],
+	       [libc_cv_undefined_version],
+	       [dnl
+cat > conftest.script << EOF
+VERSION_1.0 { global: bar; };
+EOF
+old_LDFLAGS="$LDFLAGS"
+LDFLAGS="-Wl,--version-script=conftest.script -shared"
+AC_LINK_IFELSE([AC_LANG_PROGRAM([[extern int und (void);]],
+                                [[int foo (void) { return und (); }]])],
+                                [libc_cv_undefined_version=],
+                                [libc_cv_undefined_version=-Wl,--undefined-version])
+LDFLAGS="$old_LDFLAGS"
+rm conftest.*])
+LIBC_CONFIG_VAR([undefined-version], [$libc_cv_undefined_version])
+
 dnl Starting with binutils 2.35, GAS can attach multiple symbol versions
 dnl to one symbol (PR 23840).
 AC_CACHE_CHECK(whether the assembler requires one version per symbol,
-- 
2.43.0



More information about the Libc-alpha mailing list