[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