Index: ELF/Relocations.cpp =================================================================== --- ELF/Relocations.cpp +++ ELF/Relocations.cpp @@ -149,7 +149,7 @@ InputSectionBase &C, uint64_t Offset, int64_t Addend, RelExpr Expr) { // The Dynamic TLS Module Index Relocation for a symbol defined in an - // executable is always 1. If the target Symbol is not preemtible then + // executable is always 1. If the target Symbol is not preemptible then // we know the offset into the TLS block at static link time. bool NeedDynId = Body.isPreemptible() || Config->Shared; bool NeedDynOff = Body.isPreemptible(); @@ -527,6 +527,7 @@ // interpose any aliases. for (SharedSymbol *Sym : getSymbolsAt(SS)) { Sym->CopyRelSec = Sec; + Sym->IsPreemptible = false; Sym->CopyRelSecOff = Off; Sym->symbol()->IsUsedInRegularObj = true; } @@ -612,6 +613,7 @@ // plt. That is identified by special relocation types (R_X86_64_JUMP_SLOT, // R_386_JMP_SLOT, etc). Body.NeedsPltAddr = true; + Body.IsPreemptible = false; return toPlt(Expr); } Index: ELF/Symbols.h =================================================================== --- ELF/Symbols.h +++ ELF/Symbols.h @@ -70,7 +70,7 @@ } bool isLocal() const { return IsLocal; } InputFile *getFile() const; - bool isPreemptible() const; + bool isPreemptible() const { return IsPreemptible; } StringRef getName() const { return Name; } uint8_t getVisibility() const { return StOther & 0x3; } void parseSymbolVersion(); @@ -121,6 +121,8 @@ // True if this symbol is in the Igot sub-section of the .got.plt or .got. unsigned IsInIgot : 1; + unsigned IsPreemptible : 1; + // The following fields have the same meaning as the ELF symbol attributes. uint8_t Type; // symbol type uint8_t StOther; // st_other field value Index: ELF/Symbols.cpp =================================================================== --- ELF/Symbols.cpp +++ ELF/Symbols.cpp @@ -127,7 +127,8 @@ uint8_t Type) : SymbolKind(K), NeedsPltAddr(false), IsLocal(IsLocal), IsInGlobalMipsGot(false), Is32BitMipsGot(false), IsInIplt(false), - IsInIgot(false), Type(Type), StOther(StOther), Name(Name) {} + IsInIgot(false), IsPreemptible(false), Type(Type), StOther(StOther), + Name(Name) {} InputFile *SymbolBody::getFile() const { if (isLocal()) @@ -135,41 +136,6 @@ return symbol()->File; } -// Returns true if a symbol can be replaced at load-time by a symbol -// with the same name defined in other ELF executable or DSO. -bool SymbolBody::isPreemptible() const { - if (isLocal()) - return false; - - // Shared symbols resolve to the definition in the DSO. The exceptions are - // symbols with copy relocations (which resolve to .bss) or preempt plt - // entries (which resolve to that plt entry). - if (auto *SS = dyn_cast(this)) - return !SS->CopyRelSec && !NeedsPltAddr; - - // Only symbols that appear in dynsym can be preempted. - if (!symbol()->includeInDynsym()) - return false; - - // Only default visibility symbols can be preempted. - if (symbol()->Visibility != STV_DEFAULT) - return false; - - // Undefined symbols in non-DSOs are usually just an error, so it - // doesn't matter whether we return true or false here. However, if - // -unresolved-symbols=ignore-all is specified, undefined symbols in - // executables are automatically exported so that the runtime linker - // can try to resolve them. In that case, they is preemptible. So, we - // return true for an undefined symbol in case the option is specified. - if (!Config->Shared) - return isUndefined(); - - // -Bsymbolic means that definitions are not preempted. - if (Config->Bsymbolic || (Config->BsymbolicFunctions && isFunc())) - return !isDefined(); - return true; -} - // Overwrites all attributes with Other's so that this symbol becomes // an alias to Other. This is useful for handling some options such as // --wrap. Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1149,6 +1149,39 @@ } } +// Returns true if a symbol can be replaced at load-time by a symbol +// with the same name defined in other ELF executable or DSO. +static bool computeIsPreemptible(const SymbolBody &B) { + assert(!B.isLocal()); + // Shared symbols resolve to the definition in the DSO. The exceptions are + // symbols with copy relocations (which resolve to .bss) or preempt plt + // entries (which resolve to that plt entry). + if (auto *SS = dyn_cast(&B)) + return !SS->CopyRelSec && !SS->NeedsPltAddr; + + // Only symbols that appear in dynsym can be preempted. + if (!B.symbol()->includeInDynsym()) + return false; + + // Only default visibility symbols can be preempted. + if (B.symbol()->Visibility != STV_DEFAULT) + return false; + + // Undefined symbols in non-DSOs are usually just an error, so it + // doesn't matter whether we return true or false here. However, if + // -unresolved-symbols=ignore-all is specified, undefined symbols in + // executables are automatically exported so that the runtime linker + // can try to resolve them. In that case, they is preemptible. So, we + // return true for an undefined symbol in case the option is specified. + if (!Config->Shared) + return B.isUndefined(); + + // -Bsymbolic means that definitions are not preempted. + if (Config->Bsymbolic || (Config->BsymbolicFunctions && B.isFunc())) + return !B.isDefined(); + return true; +} + // Create output section objects and add them to OutputSections. template void Writer::finalizeSections() { Out::DebugInfo = findSection(".debug_info"); @@ -1182,6 +1215,9 @@ applySynthetic({In::EhFrame}, [](SyntheticSection *SS) { SS->finalizeContents(); }); + for (Symbol *S : Symtab->getSymbols()) + S->body()->IsPreemptible = computeIsPreemptible(*S->body()); + // Scan relocations. This must be done after every symbol is declared so that // we can correctly decide if a dynamic relocation is needed. forEachRelSec(scanRelocations);