HomePhabricator

[ELF] Only allow the binding of SharedSymbol to change for the first undef ref

Description

[ELF] Only allow the binding of SharedSymbol to change for the first undef ref

Fixes PR42442

t.o has a STB_GLOBAL undef ref to f
t2.so has a STB_WEAK undef ref to f
t1.so defines f

ld.lld t.o t1.so t2.so currently sets the binding of f to STB_WEAK.
This is not correct because there exists a STB_GLOBAL undef ref from a
regular object. The problem is that resolveUndefined() doesn't check
if the undef ref is seen for the first time:

if (isShared() || isLazy() || (isUndefined() && Other.Binding != STB_WEAK))
  Binding = Other.Binding;

The isShared() condition should be isShared() && !Referenced
where Referenced is set to true after an undef ref is seen.

In practice, when linking a pthread program with glibc:

// a.o
#include <pthread.h>
pthread_mutex_t mu = PTHREAD_MUTEX_INITIALIZER;
int main() { pthread_mutex_unlock(&mu); }

{clang,gcc} -fuse-ld=lld a.o -lpthread # libpthread.so is linked before libgcc_s.so.1

The weak undef pthread_mutex_unlock in libgcc_s.so.1 makes the result
weak, which diverges from GNU linkers where STB_DEFAULT is used:

23: 0000000000000000     0 FUNC    WEAK   DEFAULT  UND pthread_mutex_lock

(Note, if -pthread is used instead, libpthread.so will be linked after
libgcc_s.so.1 . lld sets the binding to the expected STB_GLOBAL)

Similar linking sequences (ld.lld t.o t1.so t2.so) appear to be used by
Go, which cause a build error https://github.com/golang/go/issues/31912.

Reviewed By: grimar, ruiu

Differential Revision: https://reviews.llvm.org/D63974

Details

Committed
MaskRayJul 2 2019, 4:37 AM
Reviewer
grimar
Differential Revision
D63974: [ELF] Only allow the binding of SharedSymbol to change for the first undef ref
Branches
Unknown
Tags
Unknown