[PATCH] D80059: [ELF] Parse SHT_GNU_verneed and respect versioned undefined symbols in shared objects

Fangrui Song via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Mon May 18 10:13:35 PDT 2020


MaskRay added a comment.

In D80059#2041478 <https://reviews.llvm.org/D80059#2041478>, @psmith wrote:

> Just thinking if it would be possible to resolve this without having to read the verneed section of shared objects. I've not checked to see if this would make a simpler implementation though.


Thanks for raising the point. We indeed should think whether there are simpler ways to achieve something. See below, I think we need to have parseVerneed.

>> If a versioned symbol referenced by a shared object is defined in the executable, we will fail to export it.
>>  If a versioned symbol referenced by a shared object in another object file, --no-allow-shlib-undefined may spuriously report an "undefined reference to " error. See https://bugs.llvm.org/show_bug.cgi?id=44842 (Linking -lfftw3 -lm on Arch Linux can cause undefined reference to __log_finite)
> 
> Reading through https://www.akkadia.org/drepper/symbol-versioning I'm not sure if a versioned symbol being defined by the application is in the spirit of the specification. As I understand it when linking an undefined reference the static linker only binds against the default version, this is then recorded as the version needed. I'm trying to work out if there is ever a case where we could create a shared object that could depend on a versioned definition in an executable as we wouldn't have the symbols from the executable when we create the shared library to record the version needed. I guess matching versioned definitions in the application could be used to preempt/intercept a version defined by a shared library, but that is about all I can think of. Do other linker's and dynamic loaders support this use case?

GNU ld exports the preempted symbol and respects `-y`. We don't currently have the diagnostics (resolveShared does not check `Symbol::traced`):

  echo 'v1 { f; };' > a.ver
  echo '.globl f_v1; .symver f_v1,f at v1; f_v1: g:' | as - -o a.o
  ld.bfd -shared --version-script a.ver a.o -o a.so
  ld.bfd --version-script a.ver a.o a.so -o a.so -y f at v1
  # ld.bfd: a.o: definition of f at v1
  # ld.bfd: a.so: reference to f at v1   ## we don't have this line
  # ld.bfd: warning: cannot find entry symbol _start; defaulting to 0000000000401000

I have checked that the approach is similar to gold's.

> For a versioned symbol referenced by a shared object, that is defined in another shared object in the link, for the purposes of no-allow-shlib-undefined it could be possible with some loss of accuracy, to resolve it as defined if there were any versioned symbol definitions. This would miss the case where the versions don't match, but this would be diagnosed by the Dynamic Loader, however it wouldn't error for a reference to __log_finite from a shared library to __log_finite at GLIBC_2.15

As the patch shows, the SHT_GNU_verneed parsing complexity is surmountable and we can get three things: (1) proper preemption semantics (arguably preemption may not be the desire of the application but the behavior matches GNU ld and gold) (2) proper --no-allow-shlib-undefined (3) making `-y __log_finite at GLIBC_2.15` work in a separate change. So I am in favor of doing it.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D80059/new/

https://reviews.llvm.org/D80059





More information about the llvm-commits mailing list