[PATCH 45/59] Check if linker sets --no-undefined-version by default
Sam James
sam@gentoo.org
Sat Oct 18 06:56:06 GMT 2025
Adhemerval Zanella <adhemerval.zanella@linaro.org> writes:
> 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.
Yes. The warning is helpful as a linter but there's a lot of cases like
this where it ends up being more harm than help.
>
> 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
s/teh/the/
> for missing and extra symbol the linker extra checks are not really
> required. So disable them for now.
Can we just check for -Wl,--no-undefined-version please? I don't expect
us to ever change the default in bfd.
(Or was there a particular reason to check for the default I'm missing?)
> ---
> 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,
More information about the Libc-alpha
mailing list