Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -1098,6 +1098,7 @@ // Handle global undefined symbols. if (eSym.st_shndx == SHN_UNDEF) { this->symbols[i]->resolve(Undefined{this, name, binding, stOther, type}); + this->symbols[i]->referenced = true; continue; } Index: ELF/Symbols.h =================================================================== --- ELF/Symbols.h +++ ELF/Symbols.h @@ -127,6 +127,11 @@ // doesn't know the final contents of the symbol. unsigned canInline : 1; + // Used by Undefined and SharedSymbol to track if there has been at least one + // undefined reference to the symbol. The binding may change to STB_WEAK if + // the first undefined reference from a non-shared object is weak. + unsigned referenced : 1; + // True if this symbol is specified by --trace-symbol option. unsigned traced : 1; @@ -229,9 +234,9 @@ type(type), stOther(stOther), symbolKind(k), visibility(stOther & 3), isUsedInRegularObj(!file || file->kind() == InputFile::ObjKind), exportDynamic(isExportDynamic(k, visibility)), canInline(false), - traced(false), needsPltAddr(false), isInIplt(false), gotInIgot(false), - isPreemptible(false), used(!config->gcSections), needsTocRestore(false), - scriptDefined(false) {} + referenced(false), traced(false), needsPltAddr(false), isInIplt(false), + gotInIgot(false), isPreemptible(false), used(!config->gcSections), + needsTocRestore(false), scriptDefined(false) {} public: // True the symbol should point to its PLT entry. @@ -367,11 +372,6 @@ uint64_t value; // st_value uint64_t size; // st_size uint32_t alignment; - - // This is true if there has been at least one undefined reference to the - // symbol. The binding may change to STB_WEAK if the first undefined reference - // is weak. - bool referenced = false; }; // LazyArchive and LazyObject represent a symbols that is not yet in the link, @@ -535,6 +535,7 @@ isUsedInRegularObj = old.isUsedInRegularObj; exportDynamic = old.exportDynamic; canInline = old.canInline; + referenced = old.referenced; traced = old.traced; isPreemptible = old.isPreemptible; scriptDefined = old.scriptDefined; Index: ELF/Symbols.cpp =================================================================== --- ELF/Symbols.cpp +++ ELF/Symbols.cpp @@ -492,17 +492,13 @@ if (dyn_cast_or_null(other.file)) return; - if (isUndefined()) { - // The binding may "upgrade" from weak to non-weak. - if (other.binding != STB_WEAK) + if (isUndefined() || isShared()) { + // The binding will be weak if there is at least one reference and all are + // weak. The binding has one opportunity to change to weak: if the first + // reference is weak. + if (other.binding != STB_WEAK || !referenced) binding = other.binding; - } else if (auto *s = dyn_cast(this)) { - // The binding of a SharedSymbol will be weak if there is at least one - // reference and all are weak. The binding has one opportunity to change to - // weak: if the first reference is weak. - if (other.binding != STB_WEAK || !s->referenced) - binding = other.binding; - s->referenced = true; + referenced = true; } } @@ -658,6 +654,6 @@ uint8_t bind = binding; replace(other); binding = bind; - cast(this)->referenced = true; + referenced = true; } } Index: test/ELF/weak-undef-shared.s =================================================================== --- test/ELF/weak-undef-shared.s +++ test/ELF/weak-undef-shared.s @@ -30,6 +30,9 @@ # RUN: ld.lld %t1.o %t2.so -o %t # RUN: llvm-readelf --dyn-syms %t | FileCheck --check-prefix=WEAK %s +# RUN: ld.lld %t2.so %t1.o -o %t +# RUN: llvm-readelf --dyn-syms %t | FileCheck --check-prefix=WEAK %s + # WEAK: NOTYPE WEAK DEFAULT UND foo # GLOBAL: NOTYPE GLOBAL DEFAULT UND foo