[PATCH v3] elf: Don't set its DT_VERSYM entry for unversioned symbol

Fangrui Song maskray@sourceware.org
Wed Nov 12 06:54:39 GMT 2025


On Tue, Nov 11, 2025 at 10:43 PM Jan Beulich <jbeulich@suse.com> wrote:
>
> On 12.11.2025 07:37, Fangrui Song wrote:
> > On Tue, Nov 11, 2025 at 3:47 PM H.J. Lu <hjl.tools@gmail.com> wrote:
> >>
> >> On Wed, Nov 12, 2025 at 6:38 AM H.J. Lu <hjl.tools@gmail.com> wrote:
> >>>
> >>> On Tue, Nov 11, 2025 at 6:46 PM Andreas Schwab <schwab@suse.de> wrote:
> >>>>
> >>>> On Okt 31 2025, H.J. Lu wrote:
> >>>>
> >>>>> 1. Referenced symbol without '@' has no version.
> >>>>> 2. Defined symbol without the .symver directive has no version if there
> >>>>> is no linker version script.
> >>>>>
> >>>>> Symbol without version shouldn't have the base version in its DT_VERSYM
> >>>>> entry.  Instead, its DT_VERSYM entry should be all zero to indicate that
> >>>>> the symbol doesn't have a version.
> >>>>
> >>>> This breaks the testsuite of mold:
> >>>>
> >>>
> >>> Why should ld change impact mold tests?
> >>>
> >>>>  38/428 Test  #38: x86_64-arch-x86_64-reloc ..............................***Failed    0.09 sec
> >>>> ++ dirname /home/abuild/rpmbuild/BUILD/mold-2.40.4.60.gad08999-build/mold-2.40.4.60.gad08999/test/arch-x86_64-reloc.sh
> >>>> + . /home/abuild/rpmbuild/BUILD/mold-2.40.4.60.gad08999-build/mold-2.40.4.60.gad08999/test/common.inc
> >>>> ++ export LC_ALL=C
> >>>> ++ LC_ALL=C
> >>>> ++ '[' -z x86_64 ']'
> >>>> ++ '[' -z '' ']'
> >>>> ++ TESTDIR=out/test/x86_64
> >>>> ++ CC=cc
> >>>> ++ CXX=c++
> >>>> ++ GCC=gcc
> >>>> ++ GXX=g++
> >>>> ++ OBJDUMP=objdump
> >>>> ++ OBJCOPY=objcopy
> >>>> ++ STRIP=strip
> >>>> ++ QEMU=
> >>>> +++ basename /home/abuild/rpmbuild/BUILD/mold-2.40.4.60.gad08999-build/mold-2.40.4.60.gad08999/test/arch-x86_64-reloc.sh .sh
> >>>> ++ testname=arch-x86_64-reloc
> >>>> ++ t=out/test/x86_64/arch-x86_64-reloc
> >>>> ++ mkdir -p out/test/x86_64/arch-x86_64-reloc
> >>>> ++ case $MACHINE in
> >>>> ++ tlsdesc_opt=-mtls-dialect=gnu2
> >>>> +++ uname
> >>>> ++ '[' Linux = FreeBSD ']'
> >>>> ++ trap 'on_error $LINENO' ERR
> >>>> ++ trap on_exit EXIT
> >>>> ++ echo -n 'Testing arch-x86_64-reloc ... '
> >>>> Testing arch-x86_64-reloc ... ++ set -o pipefail
> >>>> ++ set -x
> >>>> + cat
> >>>> + cc -fPIC -c -o out/test/x86_64/arch-x86_64-reloc/a.o -x assembler -
> >>>> + cc -fPIC -c -o out/test/x86_64/arch-x86_64-reloc/b.o -xc -
> >>>> + cat
> >>>> + cc -shared -o out/test/x86_64/arch-x86_64-reloc/c.so out/test/x86_64/arch-x86_64-reloc/a.o out/test/x86_64/arch-x86_64-reloc/b.o -Wl,-z,noexecstack
> >>>> + cat
> >>>> + cc -B. -o out/test/x86_64/arch-x86_64-reloc/exe out/test/x86_64/arch-x86_64-reloc/c.so out/test/x86_64/arch-x86_64-reloc/d.s -no-pie
> >>>> mold: error: undefined symbol: print
> >>>>>>> referenced by /tmp/ccfsY4zd.o:(.text)
> >>>>>>>               /tmp/ccfsY4zd.o
> >>>> collect2: error: ld returned 1 exit status
> >>>> ++ on_error 43
> >>>> ++ code=1
> >>>> ++ echo 'command failed: 43: $CC -B. -o $t/exe $t/c.so $t/d.s -no-pie'
> >>>> command failed: 43: $CC -B. -o $t/exe $t/c.so $t/d.s -no-pie
> >>>> ++ trap - EXIT
> >>>> ++ exit 1
> >>>>
> >>>> Is this a bug in mold?
> >>>
> >>> Does
> >>>
> >>> $ cc -o out/test/x86_64/arch-x86_64-reloc/exe
> >>> out/test/x86_64/arch-x86_64-reloc/c.so
> >>> out/test/x86_64/arch-x86_64-reloc/d.s -no-pie
> >>>
> >>> fail with ld?  "print" isn't a function in libc.
> >>>
> >>> 1. Where is it defined?
> >>> 2. What does
> >>> "readelf -DsW" with
> >>>
> >>> commit 2be0f2da2100cc2b5047f5d055cd039ac494d563
> >>> Author: H.J. Lu <hjl.tools@gmail.com>
> >>> Date:   Thu Nov 6 08:20:26 2025 +0800
> >>>
> >>>     readelf: Display the base symbol version as empty string
> >>>
> >>> report on the object where "print" is defined.
> >>> 3.  Which linker is used to generate it?
> >>>
> >>
> >> I opened:
> >>
> >> https://github.com/rui314/mold/issues/1534
> >>
> >> --
> >> H.J.
> >
> > ISTM new code will be needed across all Linux linkers to support this change.
> >
> > I think the old linker behavior, which kept undefined unversioned
> > symbols at version 1, was more sensible.
> >
> > This is because version 0 (VER_NDX_LOCAL) used to be exclusively for
> > defined symbols, but now it can be applied to undefined ones.
> > This change breaks the simple rule that an absent symbol versioning
> > section (like .gnu.version) meant everything was version 1.
>
> Was / is this spelled out like this in the spec? To me, no info means
> no version. I.e. also ...
>
> > Now, a symbol's default version depends on whether it's defined.
>
> ... not exactly this.
>
> Jan

https://sourceware.org/gnu-gabi/program-loading-and-dynamic-linking.txt#:~:text=versioning
specifies

Two values are reserved:

  VER_NDX_LOCAL  0 - The symbol is private, and is not available
outside this object.
  VER_NDX_GLOBAL 1 - The symbol is globally available (ie the base or
default version).

While the older https://akkadia.org/drepper/symbol-versioning specifies

    0   the symbol is local, not available outside the object
    1   the symbol is defined in this object and globally available

(Nevertheless, I have found many details not really specified, so I
maintain my own notes
https://maskray.me/blog/2020-11-26-all-about-symbol-versioning#:~:text=linker%20behavior
)


ISTM VER_NDX_LOCAL should not be used with a global undefined symbol.
Such a symbol should be resolved to some definition in other modules,
so it should not be considered private.

> > The fact that version index 1 in the .gnu.version_d section specifies
> > the library name (SONAME) shouldn't be a reason to default undefined
> > symbols to version 0.
> >
> > Is it worth changing the reasonable behavior for 26+ years?
> > Could the objdump output be updated to stop printing "BASE" for
> > undefined symbols?
> >
> > The comment is also posted at
> > https://sourceware.org/bugzilla/show_bug.cgi?id=33577#c16
>



































More information about the Binutils mailing list