Skip to content

Commit e49c417

Browse files
committed
[ELF] Make binding (weak or non-weak) logic consistent for Undefined and SharedSymbol
This is a case missed by D64136. If %t1.o has a weak reference on foo, and %t2.so has a non-weak reference on foo: ``` 0. ld.lld %t1.o %t2.so # ok; STB_WEAK; accepted since D64136 1. ld.lld %t2.so %t1.o # undefined symbol: foo; STB_GLOBAL 2. gold %t1.o %t2.so # ok; STB_WEAK 3. gold %t2.so %t1.o # undefined reference to 'foo'; STB_GLOBAL 4. ld.bfd %t1.o %t2.so # undefined reference to `foo'; STB_WEAK 5. ld.bfd %t2.so %t1.o # undefined reference to `foo'; STB_WEAK ``` It can be argued that in both cases, the binding of the undefined foo should be set to STB_WEAK, because the binding should not be affected by referenced from shared objects. --allow-shlib-undefined doesn't suppress errors (3,4,5), but -shared or --noinhibit-exec allows ld.bfd/gold to produce a binary: ``` 3. gold -shared %t2.so %t1.o # ok; STB_GLOBAL 4. ld.bfd -shared %t2.so %t1.o # ok; STB_WEAK 5. ld.bfd -shared %t1.o %t1.o # ok; STB_WEAK ``` If %t2.so has DT_NEEDED entries, ld.bfd will load them (lld/gold don't have the behavior). If one of the DSO defines foo and it is in the link-time search path (e.g. DT_NEEDED entry is an absolute path, via -rpath=, via -rpath-link=, etc), `ld.bfd %t1.o %t2.so` and `ld.bfd %t1.o %t2.so` will not error. In this patch, we make Undefined and SharedSymbol share the same binding computing logic. Case 1 will be allowed: ``` 0. ld.lld %t1.o %t2.so # ok; STB_WEAK; accepted since D64136 1. ld.lld %t2.so %t1.o # ok; STB_WEAK; changed by this patch ``` In the future, we can explore the option that turns both (0,1) into errors if --no-allow-shlib-undefined (default when linking an executable) is in action. Reviewed By: ruiu Differential Revision: https://reviews.llvm.org/D65584 llvm-svn: 368038
1 parent 81dc15e commit e49c417

File tree

4 files changed

+20
-19
lines changed

4 files changed

+20
-19
lines changed

lld/ELF/InputFiles.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1098,6 +1098,7 @@ template <class ELFT> void ObjFile<ELFT>::initializeSymbols() {
10981098
// Handle global undefined symbols.
10991099
if (eSym.st_shndx == SHN_UNDEF) {
11001100
this->symbols[i]->resolve(Undefined{this, name, binding, stOther, type});
1101+
this->symbols[i]->referenced = true;
11011102
continue;
11021103
}
11031104

lld/ELF/Symbols.cpp

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -492,17 +492,13 @@ void Symbol::resolveUndefined(const Undefined &other) {
492492
if (dyn_cast_or_null<SharedFile>(other.file))
493493
return;
494494

495-
if (isUndefined()) {
496-
// The binding may "upgrade" from weak to non-weak.
497-
if (other.binding != STB_WEAK)
495+
if (isUndefined() || isShared()) {
496+
// The binding will be weak if there is at least one reference and all are
497+
// weak. The binding has one opportunity to change to weak: if the first
498+
// reference is weak.
499+
if (other.binding != STB_WEAK || !referenced)
498500
binding = other.binding;
499-
} else if (auto *s = dyn_cast<SharedSymbol>(this)) {
500-
// The binding of a SharedSymbol will be weak if there is at least one
501-
// reference and all are weak. The binding has one opportunity to change to
502-
// weak: if the first reference is weak.
503-
if (other.binding != STB_WEAK || !s->referenced)
504-
binding = other.binding;
505-
s->referenced = true;
501+
referenced = true;
506502
}
507503
}
508504

@@ -658,6 +654,6 @@ void Symbol::resolveShared(const SharedSymbol &other) {
658654
uint8_t bind = binding;
659655
replace(other);
660656
binding = bind;
661-
cast<SharedSymbol>(this)->referenced = true;
657+
referenced = true;
662658
}
663659
}

lld/ELF/Symbols.h

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,11 @@ class Symbol {
127127
// doesn't know the final contents of the symbol.
128128
unsigned canInline : 1;
129129

130+
// Used by Undefined and SharedSymbol to track if there has been at least one
131+
// undefined reference to the symbol. The binding may change to STB_WEAK if
132+
// the first undefined reference from a non-shared object is weak.
133+
unsigned referenced : 1;
134+
130135
// True if this symbol is specified by --trace-symbol option.
131136
unsigned traced : 1;
132137

@@ -229,9 +234,9 @@ class Symbol {
229234
type(type), stOther(stOther), symbolKind(k), visibility(stOther & 3),
230235
isUsedInRegularObj(!file || file->kind() == InputFile::ObjKind),
231236
exportDynamic(isExportDynamic(k, visibility)), canInline(false),
232-
traced(false), needsPltAddr(false), isInIplt(false), gotInIgot(false),
233-
isPreemptible(false), used(!config->gcSections), needsTocRestore(false),
234-
scriptDefined(false) {}
237+
referenced(false), traced(false), needsPltAddr(false), isInIplt(false),
238+
gotInIgot(false), isPreemptible(false), used(!config->gcSections),
239+
needsTocRestore(false), scriptDefined(false) {}
235240

236241
public:
237242
// True the symbol should point to its PLT entry.
@@ -367,11 +372,6 @@ class SharedSymbol : public Symbol {
367372
uint64_t value; // st_value
368373
uint64_t size; // st_size
369374
uint32_t alignment;
370-
371-
// This is true if there has been at least one undefined reference to the
372-
// symbol. The binding may change to STB_WEAK if the first undefined reference
373-
// is weak.
374-
bool referenced = false;
375375
};
376376

377377
// LazyArchive and LazyObject represent a symbols that is not yet in the link,
@@ -535,6 +535,7 @@ void Symbol::replace(const Symbol &New) {
535535
isUsedInRegularObj = old.isUsedInRegularObj;
536536
exportDynamic = old.exportDynamic;
537537
canInline = old.canInline;
538+
referenced = old.referenced;
538539
traced = old.traced;
539540
isPreemptible = old.isPreemptible;
540541
scriptDefined = old.scriptDefined;

lld/test/ELF/weak-undef-shared.s

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030
# RUN: ld.lld %t1.o %t2.so -o %t
3131
# RUN: llvm-readelf --dyn-syms %t | FileCheck --check-prefix=WEAK %s
3232

33+
# RUN: ld.lld %t2.so %t1.o -o %t
34+
# RUN: llvm-readelf --dyn-syms %t | FileCheck --check-prefix=WEAK %s
35+
3336
# WEAK: NOTYPE WEAK DEFAULT UND foo
3437
# GLOBAL: NOTYPE GLOBAL DEFAULT UND foo
3538

0 commit comments

Comments
 (0)