Index: ELF/InputFiles.h =================================================================== --- ELF/InputFiles.h +++ ELF/InputFiles.h @@ -309,6 +309,8 @@ // data structures in the output file. std::map VerdefMap; + llvm::DenseMap SymVerMap; + // Used for --as-needed bool AsNeeded = false; bool IsUsed = false; Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -95,8 +95,6 @@ // until Writer is initialized. struct Out { static uint8_t First; - static OutputSection *Bss; - static OutputSection *BssRelRo; static OutputSection *Opd; static uint8_t *OpdBuf; static PhdrEntry *TlsPhdr; Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -31,8 +31,6 @@ using namespace lld::elf; uint8_t Out::First; -OutputSection *Out::Bss; -OutputSection *Out::BssRelRo; OutputSection *Out::Opd; uint8_t *Out::OpdBuf; PhdrEntry *Out::TlsPhdr; Index: ELF/Relocations.cpp =================================================================== --- ELF/Relocations.cpp +++ ELF/Relocations.cpp @@ -479,23 +479,20 @@ // See if this symbol is in a read-only segment. If so, preserve the symbol's // memory protection by reserving space in the .bss.rel.ro section. bool IsReadOnly = isReadOnly(SS); - OutputSection *OSec = IsReadOnly ? Out::BssRelRo : Out::Bss; - - // Create a SyntheticSection in Out to hold the .bss and the Copy Reloc. - auto *ISec = - make>(IsReadOnly, SS->getAlignment(), SymSize); - OSec->addSection(ISec); + BssRelSection *RelSec = IsReadOnly ? In::BssRelRo : In::Bss; + uintX_t Off = RelSec->addCopyRelocation(SS->getAlignment(), SymSize); // Look through the DSO's dynamic symbol table for aliases and create a // dynamic symbol for each one. This causes the copy relocation to correctly // interpose any aliases. for (SharedSymbol *Sym : getSymbolsAt(SS)) { - Sym->NeedsCopy = true; - Sym->Section = ISec; Sym->symbol()->IsUsedInRegularObj = true; + replaceBody(Sym->symbol(), Sym->getName(), + /*IsLocal=*/false, Sym->StOther, Sym->Type, Off, + Sym->getSize(), RelSec, Sym->File); } - In::RelaDyn->addReloc({Target->CopyRel, ISec, 0, false, SS, 0}); + In::RelaDyn->addReloc({Target->CopyRel, RelSec, Off, false, SS, 0}); } template @@ -536,14 +533,12 @@ if (Body.isObject()) { // Produce a copy relocation. auto *B = cast(&Body); - if (!B->NeedsCopy) { - if (Config->ZNocopyreloc) - error(S.getLocation(RelOff) + ": unresolvable relocation " + - toString(Type) + " against symbol '" + toString(*B) + - "'; recompile with -fPIC or remove '-z nocopyreloc'"); + if (Config->ZNocopyreloc) + error(S.getLocation(RelOff) + ": unresolvable relocation " + + toString(Type) + " against symbol '" + toString(*B) + + "'; recompile with -fPIC or remove '-z nocopyreloc'"); - addCopyRelSymbol(B); - } + addCopyRelSymbol(B); return Expr; } if (Body.isFunc()) { Index: ELF/SymbolTable.cpp =================================================================== --- ELF/SymbolTable.cpp +++ ELF/SymbolTable.cpp @@ -413,10 +413,10 @@ S->ExportDynamic = true; if (WasInserted || isa(S->body())) { - replaceBody(S, File, Name, Sym.st_other, Sym.getType(), &Sym, - Verdef); + replaceBody(S, File, Name, Sym.st_other, Sym.getType(), &Sym); if (!S->isWeak()) File->IsUsed = true; + File->SymVerMap[S] = Verdef; } } Index: ELF/Symbols.h =================================================================== --- ELF/Symbols.h +++ ELF/Symbols.h @@ -101,10 +101,6 @@ const unsigned SymbolKind : 8; public: - // True if the linker has to generate a copy relocation. - // For SharedSymbol only. - unsigned NeedsCopy : 1; - // True the symbol should point to its PLT entry. // For SharedSymbol only. unsigned NeedsPltAddr : 1; @@ -212,9 +208,9 @@ } SharedSymbol(InputFile *File, StringRef Name, uint8_t StOther, uint8_t Type, - const void *ElfSym, const void *Verdef) + const void *ElfSym) : Defined(SymbolBody::SharedKind, Name, /*IsLocal=*/false, StOther, Type), - Verdef(Verdef), ElfSym(ElfSym) { + ElfSym(ElfSym) { // IFuncs defined in DSOs are treated as functions by the static linker. if (isGnuIFunc()) Type = llvm::ELF::STT_FUNC; @@ -235,12 +231,6 @@ template uint32_t getAlignment() const; - // This field is a pointer to the symbol's version definition. - const void *Verdef; - - // Section is significant only when NeedsCopy is true. - InputSection *Section = nullptr; - private: template const typename ELFT::Sym &getSym() const { return *(const typename ELFT::Sym *)ElfSym; Index: ELF/Symbols.cpp =================================================================== --- ELF/Symbols.cpp +++ ELF/Symbols.cpp @@ -103,14 +103,10 @@ return 0; return In::Common->OutSec->Addr + In::Common->OutSecOff + cast(Body).Offset; - case SymbolBody::SharedKind: { - auto &SS = cast(Body); - if (SS.NeedsCopy) - return SS.Section->OutSec->Addr + SS.Section->OutSecOff; - if (SS.NeedsPltAddr) + case SymbolBody::SharedKind: + if (cast(Body).NeedsPltAddr) return Body.getPltVA(); return 0; - } case SymbolBody::UndefinedKind: return 0; case SymbolBody::LazyArchiveKind: @@ -123,7 +119,7 @@ SymbolBody::SymbolBody(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type) - : SymbolKind(K), NeedsCopy(false), NeedsPltAddr(false), IsLocal(IsLocal), + : SymbolKind(K), NeedsPltAddr(false), IsLocal(IsLocal), IsInGlobalMipsGot(false), Is32BitMipsGot(false), IsInIplt(false), IsInIgot(false), Type(Type), StOther(StOther), Name(Name) {} @@ -134,10 +130,9 @@ 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). + // symbols that needs plt entries (which resolve to that plt entry). if (isShared()) - return !NeedsCopy && !NeedsPltAddr; + return !NeedsPltAddr; // That's all that can be preempted in a non-DSO. if (!Config->Shared) @@ -205,11 +200,8 @@ return nullptr; } - if (auto *S = dyn_cast(this)) { - if (S->NeedsCopy) - return S->Section->OutSec; + if (isa(this)) return nullptr; - } if (isa(this)) { if (Config->DefineCommon) Index: ELF/SyntheticSections.h =================================================================== --- ELF/SyntheticSections.h +++ ELF/SyntheticSections.h @@ -152,14 +152,16 @@ uint8_t *HashBuf; }; -// For each copy relocation, we create an instance of this class to -// reserve space in .bss or .bss.rel.ro. -template class CopyRelSection final : public SyntheticSection { +// Section used for storing copy relocations. We create two sections now, +// .bss.rel.ro for RelRo case and .bss for regular case. +template class BssRelSection final : public SyntheticSection { typedef typename ELFT::uint uintX_t; public: - CopyRelSection(bool ReadOnly, uintX_t AddrAlign, size_t Size); + BssRelSection(bool RelRo); void writeTo(uint8_t *) override {} + bool empty() const override { return getSize() == 0; } + size_t addCopyRelocation(uintX_t AddrAlign, size_t Size); size_t getSize() const override { return Size; } size_t Size; }; @@ -631,7 +633,7 @@ public: VersionNeedSection(); - void addSymbol(SharedSymbol *SS); + void addSymbol(Symbol *Sym); void finalizeContents() override; void writeTo(uint8_t *Buf) override; size_t getSize() const override; @@ -762,6 +764,8 @@ template struct In { static InputSection *ARMAttributes; static BuildIdSection *BuildId; + static BssRelSection *Bss; + static BssRelSection *BssRelRo; static InputSection *Common; static DynamicSection *Dynamic; static StringTableSection *DynStrTab; @@ -791,6 +795,8 @@ }; template InputSection *In::ARMAttributes; +template BssRelSection *In::Bss; +template BssRelSection *In::BssRelRo; template BuildIdSection *In::BuildId; template InputSection *In::Common; template DynamicSection *In::Dynamic; Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -377,10 +377,17 @@ } template -CopyRelSection::CopyRelSection(bool ReadOnly, uintX_t AddrAlign, size_t S) - : SyntheticSection(SHF_ALLOC, SHT_NOBITS, AddrAlign, - ReadOnly ? ".bss.rel.ro" : ".bss"), - Size(S) {} +BssRelSection::BssRelSection(bool RelRo) + : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, 0, + RelRo ? ".bss.rel.ro" : ".bss"), + Size(0) {} + +template +size_t BssRelSection::addCopyRelocation(uintX_t AddrAlign, size_t Size) { + OutSec->updateAlignment(AddrAlign); + this->Size = alignTo(this->Size, AddrAlign) + Size; + return this->Size - Size; +} template void BuildIdSection::writeBuildId(ArrayRef Buf) { @@ -2061,15 +2068,15 @@ } template -void VersionNeedSection::addSymbol(SharedSymbol *SS) { - auto *Ver = reinterpret_cast(SS->Verdef); +void VersionNeedSection::addSymbol(Symbol *Sym) { + auto *File = cast>(Sym->body()->File); + const typename ELFT::Verdef *Ver = File->SymVerMap[Sym]; + if (!Ver) { - SS->symbol()->VersionId = VER_NDX_GLOBAL; + Sym->VersionId = VER_NDX_GLOBAL; return; } - auto *File = cast>(SS->File); - // If we don't already know that we need an Elf_Verneed for this DSO, prepare // to create one by adding it to our needed list and creating a dynstr entry // for the soname. @@ -2084,7 +2091,7 @@ Ver->getAux()->vda_name); NV.Index = NextIndex++; } - SS->symbol()->VersionId = NV.Index; + Sym->VersionId = NV.Index; } template void VersionNeedSection::writeTo(uint8_t *Buf) { @@ -2307,10 +2314,10 @@ template class elf::BuildIdSection; template class elf::BuildIdSection; -template class elf::CopyRelSection; -template class elf::CopyRelSection; -template class elf::CopyRelSection; -template class elf::CopyRelSection; +template class elf::BssRelSection; +template class elf::BssRelSection; +template class elf::BssRelSection; +template class elf::BssRelSection; template class elf::GotSection; template class elf::GotSection; Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -111,8 +111,8 @@ } for (StringRef V : - {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.", - ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.", + {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.rel.ro.", + ".bss.", ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.", ".gcc_except_table.", ".tdata.", ".ARM.exidx."}) { StringRef Prefix = V.drop_back(); if (Name.startswith(V) || Name == Prefix) @@ -309,10 +309,6 @@ auto Add = [](InputSectionBase *Sec) { InputSections.push_back(Sec); }; - // Create singleton output sections. - Out::Bss = make(".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE); - Out::BssRelRo = - make(".bss.rel.ro", SHT_NOBITS, SHF_ALLOC | SHF_WRITE); In::DynStrTab = make>(".dynstr", true); In::Dynamic = make>(); In::RelaDyn = make>( @@ -350,6 +346,11 @@ Add(Common); } + In::Bss = make>(false /*RelRo*/); + Add(In::Bss); + In::BssRelRo = make>(true /*RelRo*/); + Add(In::BssRelRo); + // Add MIPS-specific sections. bool HasDynSymTab = !Symtab::X->getSharedFiles().empty() || Config->pic() || @@ -599,7 +600,7 @@ return true; if (In::Got && Sec == In::Got->OutSec) return true; - if (Sec == Out::BssRelRo) + if (Sec == In::BssRelRo->OutSec) return true; StringRef S = Sec->Name; @@ -1103,9 +1104,10 @@ if (In::DynSymTab && S->includeInDynsym()) { In::DynSymTab->addSymbol(Body); - if (auto *SS = dyn_cast(Body)) - if (cast>(SS->File)->isNeeded()) - In::VerNeed->addSymbol(SS); + if (isa(Body) || isa(Body)) + if (auto *F = dyn_cast_or_null>(Body->File)) + if (F->isNeeded()) + In::VerNeed->addSymbol(S); } } @@ -1144,14 +1146,15 @@ // Dynamic section must be the last one in this list and dynamic // symbol table section (DynSymTab) must be the first one. applySynthetic( - {In::DynSymTab, In::GnuHashTab, In::HashTab, - In::SymTab, In::ShStrTab, In::StrTab, - In::VerDef, In::DynStrTab, In::GdbIndex, - In::Got, In::MipsGot, In::IgotPlt, - In::GotPlt, In::RelaDyn, In::RelaIplt, - In::RelaPlt, In::Plt, In::Iplt, - In::Plt, In::EhFrameHdr, In::VerSym, - In::VerNeed, In::Dynamic}, + {In::DynSymTab, In::Bss, In::BssRelRo, + In::GnuHashTab, In::HashTab, In::SymTab, + In::ShStrTab, In::StrTab, In::VerDef, + In::DynStrTab, In::GdbIndex, In::Got, + In::MipsGot, In::IgotPlt, In::GotPlt, + In::RelaDyn, In::RelaIplt, In::RelaPlt, + In::Plt, In::Iplt, In::Plt, + In::EhFrameHdr, In::VerSym, In::VerNeed, + In::Dynamic}, [](SyntheticSection *SS) { SS->finalizeContents(); }); // Some architectures use small displacements for jump instructions. @@ -1180,16 +1183,6 @@ } template void Writer::addPredefinedSections() { - // Add BSS sections. - auto Add = [=](OutputSection *Sec) { - if (!Sec->Sections.empty()) { - Sec->assignOffsets(); - OutputSections.push_back(Sec); - } - }; - Add(Out::Bss); - Add(Out::BssRelRo); - // ARM ABI requires .ARM.exidx to be terminated by some piece of data. // We have the terminater synthetic section class. Add that at the end. auto *OS = dyn_cast_or_null(findSection(".ARM.exidx")); Index: test/ELF/version-script-copy-rel.s =================================================================== --- test/ELF/version-script-copy-rel.s +++ test/ELF/version-script-copy-rel.s @@ -0,0 +1,24 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/copy-in-shared.s -o %t1.o +# RUN: echo "FOOVER { global: *; };" > %t.script +# RUN: ld.lld --version-script %t.script -shared %t1.o -o %t.so +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t2.o +# RUN: ld.lld %t2.o %t.so -o %tout +# RUN: llvm-readobj -dyn-symbols %tout | FileCheck %s + +# CHECK: DynamicSymbols [ +# CHECK: Symbol { +# CHECK: Name: foo@FOOVER +# CHECK-NEXT: Value: +# CHECK-NEXT: Size: +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: Object +# CHECK-NEXT: Other: +# CHECK-NEXT: Section: .bss.rel.ro +# CHECK-NEXT: } +# CHECK-NEXT: ] + +.text +.global _start +_start: +movl $0, foo