Index: ELF/InputFiles.h =================================================================== --- ELF/InputFiles.h +++ ELF/InputFiles.h @@ -80,13 +80,15 @@ uint32_t getSectionIndex(const Elf_Sym &Sym) const; + enum WhichSymbols { LOCAL_SYMBOLS, GLOBAL_SYMBOLS, ALL_SYMBOLS }; + Elf_Sym_Range getElfSymbols(WhichSymbols); + protected: llvm::object::ELFFile ELFObj; const Elf_Shdr *Symtab = nullptr; ArrayRef SymtabSHNDX; StringRef StringTable; void initStringTable(); - Elf_Sym_Range getElfSymbols(bool OnlyGlobals); }; // .o file. @@ -107,11 +109,11 @@ } ArrayRef getSymbols(); - ArrayRef getLocalSymbols(); ArrayRef getNonLocalSymbols(); explicit ObjectFile(MemoryBufferRef M); - void parse(llvm::DenseSet &ComdatGroups); + void parse(llvm::function_ref Resolve, + llvm::DenseSet &ComdatGroups); ArrayRef *> getSections() const { return Sections; } InputSectionBase *getSection(const Elf_Sym &Sym) const; @@ -133,11 +135,12 @@ private: void initializeSections(llvm::DenseSet &ComdatGroups); - void initializeSymbols(); + void + initializeSymbols(llvm::function_ref Resolve); InputSectionBase *getRelocTarget(const Elf_Shdr &Sec); InputSectionBase *createInputSection(const Elf_Shdr &Sec); - SymbolBody *createSymbolBody(const Elf_Sym *Sym); + std::pair createSymbolBody(const Elf_Sym *Sym); // List of all sections defined by this file. std::vector *> Sections; @@ -176,7 +179,8 @@ public: explicit BitcodeFile(MemoryBufferRef M); static bool classof(const InputFile *F); - void parse(llvm::DenseSet &ComdatGroups); + void parse(llvm::function_ref Resolve, + llvm::DenseSet &ComdatGroups); ArrayRef getSymbols() { return SymbolBodies; } static bool shouldSkip(const llvm::object::BasicSymbolRef &Sym); @@ -184,7 +188,7 @@ std::vector SymbolBodies; llvm::BumpPtrAllocator Alloc; llvm::StringSaver Saver{Alloc}; - SymbolBody * + std::pair createSymbolBody(const llvm::DenseSet &KeptComdats, const llvm::object::IRObjectFile &Obj, const llvm::object::BasicSymbolRef &Sym); @@ -217,7 +221,7 @@ explicit SharedFile(MemoryBufferRef M); void parseSoName(); - void parseRest(); + void parseRest(llvm::function_ref Resolve); // Used for --as-needed bool AsNeeded = false; Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -45,7 +45,7 @@ } template -typename ELFT::SymRange ELFFileBase::getElfSymbols(bool OnlyGlobals) { +typename ELFT::SymRange ELFFileBase::getElfSymbols(WhichSymbols Which) { if (!Symtab) return Elf_Sym_Range(nullptr, nullptr); Elf_Sym_Range Syms = ELFObj.symbols(Symtab); @@ -54,9 +54,14 @@ if (FirstNonLocal > NumSymbols) fatal("invalid sh_info in symbol table"); - if (OnlyGlobals) + switch (Which) { + case LOCAL_SYMBOLS: + return makeArrayRef(Syms.begin() + 1, Syms.begin() + FirstNonLocal); + case GLOBAL_SYMBOLS: return makeArrayRef(Syms.begin() + FirstNonLocal, Syms.end()); - return makeArrayRef(Syms.begin(), Syms.end()); + case ALL_SYMBOLS: + return makeArrayRef(Syms.begin(), Syms.end()); + } } template @@ -88,14 +93,6 @@ } template -ArrayRef elf::ObjectFile::getLocalSymbols() { - if (!this->Symtab) - return this->SymbolBodies; - uint32_t FirstNonLocal = this->Symtab->sh_info; - return makeArrayRef(this->SymbolBodies).slice(1, FirstNonLocal - 1); -} - -template ArrayRef elf::ObjectFile::getSymbols() { if (!this->Symtab) return this->SymbolBodies; @@ -109,10 +106,12 @@ } template -void elf::ObjectFile::parse(DenseSet &ComdatGroups) { +void elf::ObjectFile::parse( + function_ref Resolve, + DenseSet &ComdatGroups) { // Read section and symbol tables. initializeSections(ComdatGroups); - initializeSymbols(); + initializeSymbols(Resolve); } // Sections with SHT_GROUP and comdat bits define comdat section groups. @@ -281,13 +280,20 @@ return new (Alloc) InputSection(this, &Sec); } -template void elf::ObjectFile::initializeSymbols() { +template +void elf::ObjectFile::initializeSymbols( + function_ref Resolve) { this->initStringTable(); - Elf_Sym_Range Syms = this->getElfSymbols(false); + Elf_Sym_Range Syms = this->getElfSymbols(ELFFileBase::ALL_SYMBOLS); uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end()); SymbolBodies.reserve(NumSymbols); - for (const Elf_Sym &Sym : Syms) - SymbolBodies.push_back(createSymbolBody(&Sym)); + for (const Elf_Sym &Sym : Syms) { + auto P = createSymbolBody(&Sym); + SymbolBody *B = P.second; + SymbolBodies.push_back(B); + if (!B->isLocal()) + Resolve(P.first, B); + } } template @@ -305,23 +311,25 @@ } template -SymbolBody *elf::ObjectFile::createSymbolBody(const Elf_Sym *Sym) { - unsigned char Binding = Sym->getBinding(); +std::pair +elf::ObjectFile::createSymbolBody(const Elf_Sym *Sym) { + unsigned char Binding = Sym->getBinding(); InputSectionBase *Sec = getSection(*Sym); if (Binding == STB_LOCAL) { if (Sym->st_shndx == SHN_UNDEF) - return new (Alloc) UndefinedElf(*Sym); - return new (Alloc) DefinedRegular(*Sym, Sec); + return std::make_pair("", new (Alloc) UndefinedElf(*Sym)); + return std::make_pair("", new (Alloc) DefinedRegular(*Sym, Sec)); } StringRef Name = check(Sym->getName(this->StringTable)); switch (Sym->st_shndx) { case SHN_UNDEF: - return new (Alloc) UndefinedElf(Name, *Sym); + return std::make_pair(Name, new (Alloc) UndefinedElf(*Sym)); case SHN_COMMON: - return new (Alloc) DefinedCommon(Name, Sym->st_size, Sym->st_value, Binding, - Sym->st_other, Sym->getType()); + return std::make_pair( + Name, new (Alloc) DefinedCommon(Sym->st_size, Sym->st_value, Binding, + Sym->st_other, Sym->getType())); } switch (Binding) { @@ -331,8 +339,8 @@ case STB_WEAK: case STB_GNU_UNIQUE: if (Sec == &InputSection::Discarded) - return new (Alloc) UndefinedElf(Name, *Sym); - return new (Alloc) DefinedRegular(Name, *Sym, Sec); + return std::make_pair(Name, new (Alloc) UndefinedElf(*Sym)); + return std::make_pair(Name, new (Alloc) DefinedRegular(*Sym, Sec)); } } @@ -420,16 +428,20 @@ } // Fully parse the shared object file. This must be called after parseSoName(). -template void SharedFile::parseRest() { - Elf_Sym_Range Syms = this->getElfSymbols(true); +template +void SharedFile::parseRest( + function_ref Resolve) { + Elf_Sym_Range Syms = this->getElfSymbols(ELFFileBase::GLOBAL_SYMBOLS); uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end()); SymbolBodies.reserve(NumSymbols); for (const Elf_Sym &Sym : Syms) { StringRef Name = check(Sym.getName(this->StringTable)); - if (Sym.isUndefined()) + if (Sym.isUndefined()) { Undefs.push_back(Name); - else - SymbolBodies.emplace_back(this, Name, Sym); + } else { + SymbolBodies.emplace_back(this, Sym); + Resolve(Name, &SymbolBodies.back()); + } } } @@ -451,7 +463,7 @@ llvm_unreachable("unknown visibility"); } -SymbolBody * +std::pair BitcodeFile::createSymbolBody(const DenseSet &KeptComdats, const IRObjectFile &Obj, const BasicSymbolRef &Sym) { @@ -459,7 +471,7 @@ assert(GV); if (const Comdat *C = GV->getComdat()) if (!KeptComdats.count(C)) - return nullptr; + return std::make_pair("", nullptr); uint8_t Visibility = getGvVisibility(GV); @@ -473,19 +485,19 @@ uint32_t Flags = Sym.getFlags(); bool IsWeak = Flags & BasicSymbolRef::SF_Weak; if (Flags & BasicSymbolRef::SF_Undefined) { - Body = new (Alloc) Undefined(NameRef, IsWeak, Visibility, false); + Body = new (Alloc) Undefined(IsWeak, Visibility, false); } else if (Flags & BasicSymbolRef::SF_Common) { const DataLayout &DL = M.getDataLayout(); uint64_t Size = DL.getTypeAllocSize(GV->getValueType()); Body = new (Alloc) - DefinedCommon(NameRef, Size, GV->getAlignment(), - IsWeak ? STB_WEAK : STB_GLOBAL, Visibility, /*Type*/ 0); + DefinedCommon(Size, GV->getAlignment(), IsWeak ? STB_WEAK : STB_GLOBAL, + Visibility, /*Type*/ 0); } else { - Body = new (Alloc) DefinedBitcode(NameRef, IsWeak, Visibility); + Body = new (Alloc) DefinedBitcode(IsWeak, Visibility); } if (GV->isThreadLocal()) Body->Type = STT_TLS; - return Body; + return std::make_pair(NameRef, Body); } bool BitcodeFile::shouldSkip(const BasicSymbolRef &Sym) { @@ -497,7 +509,8 @@ return false; } -void BitcodeFile::parse(DenseSet &ComdatGroups) { +void BitcodeFile::parse(function_ref Resolve, + DenseSet &ComdatGroups) { LLVMContext Context; std::unique_ptr Obj = check(IRObjectFile::create(MB, Context)); const Module &M = Obj->getModule(); @@ -509,9 +522,14 @@ KeptComdats.insert(&P.second); } - for (const BasicSymbolRef &Sym : Obj->symbols()) - if (!shouldSkip(Sym)) - SymbolBodies.push_back(createSymbolBody(KeptComdats, *Obj, Sym)); + for (const BasicSymbolRef &Sym : Obj->symbols()) { + if (shouldSkip(Sym)) + continue; + auto P = createSymbolBody(KeptComdats, *Obj, Sym); + SymbolBodies.push_back(P.second); + if (P.second) + Resolve(P.first, P.second); + } } template Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -215,13 +215,17 @@ void finalize() override; void writeTo(uint8_t *Buf) override; - void addSymbol(SymbolBody *Body); + void addSymbol(StringRef Name, SymbolBody *Body); StringTableSection &getStrTabSec() const { return StrTabSec; } unsigned getNumSymbols() const { return NumLocals + Symbols.size() + 1; } - ArrayRef> getSymbols() const { - return Symbols; - } + struct Sym { + StringRef Name; + SymbolBody *Body; + size_t Offset; + }; + + ArrayRef getSymbols() const { return Symbols; } unsigned NumLocals = 0; StringTableSection &StrTabSec; @@ -235,8 +239,7 @@ SymbolTable &Table; - // A vector of symbols and their string table offsets. - std::vector> Symbols; + std::vector Symbols; }; template @@ -387,7 +390,7 @@ // Adds symbols to the hash table. // Sorts the input to satisfy GNU hash section requirements. - void addSymbols(std::vector> &Symbols); + void addSymbols(std::vector::Sym> &Symbols); private: static unsigned calcNBuckets(unsigned NumHashed); Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -395,12 +395,10 @@ Elf_Word *Buckets = P; Elf_Word *Chains = P + NumSymbols; - for (const std::pair &P : + for (const typename SymbolTableSection::Sym &S : Out::DynSymTab->getSymbols()) { - SymbolBody *Body = P.first; - StringRef Name = Body->getName(); - unsigned I = Body->DynsymIndex; - uint32_t Hash = hashSysv(Name) % NumSymbols; + unsigned I = S.Body->DynsymIndex; + uint32_t Hash = hashSysv(S.Name) % NumSymbols; Chains[I] = Buckets[Hash]; Buckets[Hash] = I; } @@ -533,18 +531,15 @@ // GNU-style hash table places some sorting requirements. template void GnuHashTableSection::addSymbols( - std::vector> &V) { - auto Mid = std::stable_partition(V.begin(), V.end(), - [](std::pair &P) { - return !includeInGnuHashTable(P.first); - }); + std::vector::Sym> &V) { + auto Mid = std::stable_partition( + V.begin(), V.end(), [](typename SymbolTableSection::Sym &P) { + return !includeInGnuHashTable(P.Body); + }); if (Mid == V.end()) return; - for (auto I = Mid, E = V.end(); I != E; ++I) { - SymbolBody *B = I->first; - size_t StrOff = I->second; - Symbols.push_back({B, StrOff, hashGnu(B->getName())}); - } + for (auto I = Mid, E = V.end(); I != E; ++I) + Symbols.push_back({I->Body, I->Offset, hashGnu(I->Name)}); unsigned NBuckets = calcNBuckets(Symbols.size()); std::stable_sort(Symbols.begin(), Symbols.end(), @@ -554,7 +549,8 @@ V.erase(Mid, V.end()); for (const SymbolData &Sym : Symbols) - V.push_back({Sym.Body, Sym.STName}); + // We don't need the name anymore. + V.push_back({"", Sym.Body, Sym.STName}); } template @@ -1360,15 +1356,16 @@ // See "Global Offset Table" in Chapter 5 in the following document // for detailed description: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf -static bool sortMipsSymbols(const std::pair &L, - const std::pair &R) { +template +static bool sortMipsSymbols(const typename SymbolTableSection::Sym &L, + const typename SymbolTableSection::Sym &R) { // Sort entries related to non-local preemptible symbols by GOT indexes. // All other entries go to the first part of GOT in arbitrary order. - bool LIsInLocalGot = !L.first->isInGot() || !L.first->isPreemptible(); - bool RIsInLocalGot = !R.first->isInGot() || !R.first->isPreemptible(); + bool LIsInLocalGot = !L.Body->isInGot() || !L.Body->isPreemptible(); + bool RIsInLocalGot = !R.Body->isInGot() || !R.Body->isPreemptible(); if (LIsInLocalGot || RIsInLocalGot) return !RIsInLocalGot; - return L.first->GotIndex < R.first->GotIndex; + return L.Body->GotIndex < R.Body->GotIndex; } template void SymbolTableSection::finalize() { @@ -1381,33 +1378,33 @@ if (Config->Relocatable) { size_t I = NumLocals; - for (const std::pair &P : Symbols) - P.first->DynsymIndex = ++I; + for (const SymbolTableSection::Sym &S : Symbols) + S.Body->DynsymIndex = ++I; return; } if (!StrTabSec.isDynamic()) { - std::stable_sort(Symbols.begin(), Symbols.end(), - [](const std::pair &L, - const std::pair &R) { - return getSymbolBinding(L.first) == STB_LOCAL && - getSymbolBinding(R.first) != STB_LOCAL; - }); + std::stable_sort( + Symbols.begin(), Symbols.end(), + [](const SymbolTableSection::Sym &L, const SymbolTableSection::Sym &R) { + return getSymbolBinding(L.Body) == STB_LOCAL && + getSymbolBinding(R.Body) != STB_LOCAL; + }); return; } if (Out::GnuHashTab) // NB: It also sorts Symbols to meet the GNU hash table requirements. Out::GnuHashTab->addSymbols(Symbols); else if (Config->EMachine == EM_MIPS) - std::stable_sort(Symbols.begin(), Symbols.end(), sortMipsSymbols); + std::stable_sort(Symbols.begin(), Symbols.end(), sortMipsSymbols); size_t I = 0; - for (const std::pair &P : Symbols) - P.first->DynsymIndex = ++I; + for (const SymbolTableSection::Sym &S : Symbols) + S.Body->DynsymIndex = ++I; } template -void SymbolTableSection::addSymbol(SymbolBody *B) { - Symbols.push_back({B, StrTabSec.addString(B->getName(), false)}); +void SymbolTableSection::addSymbol(StringRef Name, SymbolBody *B) { + Symbols.push_back({Name, B, StrTabSec.addString(Name, false)}); } template void SymbolTableSection::writeTo(uint8_t *Buf) { @@ -1453,16 +1450,15 @@ // Write the internal symbol table contents to the output symbol table // pointed by Buf. auto *ESym = reinterpret_cast(Buf); - for (const std::pair &P : Symbols) { - SymbolBody *Body = P.first; - size_t StrOff = P.second; + for (const Sym &S : Symbols) { + SymbolBody *Body = S.Body; uint8_t Type = Body->Type; uintX_t Size = Body->getSize(); ESym->setBindingAndType(getSymbolBinding(Body), Type); ESym->st_size = Size; - ESym->st_name = StrOff; + ESym->st_name = S.Offset; ESym->setVisibility(Body->getVisibility()); ESym->st_value = Body->getVA(); Index: ELF/SymbolTable.h =================================================================== --- ELF/SymbolTable.h +++ ELF/SymbolTable.h @@ -66,11 +66,11 @@ InputFile *findFile(SymbolBody *B); private: - Symbol *insert(SymbolBody *New); + Symbol *insert(StringRef Name, SymbolBody *New); void addLazy(Lazy *New); void addMemberFile(Undefined *Undef, Lazy *L); - void resolve(SymbolBody *Body); - std::string conflictMsg(SymbolBody *Old, SymbolBody *New); + void resolve(StringRef Name, SymbolBody *Body); + std::string conflictMsg(StringRef Name, SymbolBody *Old, SymbolBody *New); // The order the global symbols are in is not defined. We can use an arbitrary // order, but it has to be reproducible. That is true even when cross linking. Index: ELF/SymbolTable.cpp =================================================================== --- ELF/SymbolTable.cpp +++ ELF/SymbolTable.cpp @@ -69,28 +69,23 @@ return; SharedFiles.emplace_back(cast>(File.release())); - F->parseRest(); - for (SharedSymbol &B : F->getSharedSymbols()) - resolve(&B); + F->parseRest([&](StringRef Name, SymbolBody *B) { resolve(Name, B); }); return; } // LLVM bitcode file. if (auto *F = dyn_cast(FileP)) { BitcodeFiles.emplace_back(cast(File.release())); - F->parse(ComdatGroups); - for (SymbolBody *B : F->getSymbols()) - if (B) - resolve(B); + F->parse([&](StringRef Name, SymbolBody *B) { resolve(Name, B); }, + ComdatGroups); return; } // .o file auto *F = cast>(FileP); ObjectFiles.emplace_back(cast>(File.release())); - F->parse(ComdatGroups); - for (SymbolBody *B : F->getNonLocalSymbols()) - resolve(B); + F->parse([&](StringRef Name, SymbolBody *B) { resolve(Name, B); }, + ComdatGroups); } template void SymbolTable::addCombinedLtoObject() { @@ -106,24 +101,27 @@ // Replace bitcode symbols. llvm::DenseSet DummyGroups; - Obj->parse(DummyGroups); - for (SymbolBody *Body : Obj->getNonLocalSymbols()) { - Symbol *Sym = insert(Body); - Sym->Body->setUsedInRegularObj(); - if (!Sym->Body->isUndefined() && Body->isUndefined()) - continue; - if (Sym->Body->MustBeInDynSym) - Body->MustBeInDynSym = true; - Sym->Body = Body; - } + + Obj->parse( + [&](StringRef Name, SymbolBody *Body) { + Symbol *Sym = insert(Name, Body); + Sym->Body->setUsedInRegularObj(); + if (!Sym->Body->isUndefined() && Body->isUndefined()) + return; + if (Sym->Body->MustBeInDynSym) + Body->MustBeInDynSym = true; + Sym->Body = Body; + }, + DummyGroups); + ObjectFiles.emplace_back(Obj); } // Add an undefined symbol. template SymbolBody *SymbolTable::addUndefined(StringRef Name) { - auto *Sym = new (Alloc) Undefined(Name, false, STV_DEFAULT, false); - resolve(Sym); + auto *Sym = new (Alloc) Undefined(false, STV_DEFAULT, false); + resolve(Name, Sym); return Sym; } @@ -131,8 +129,8 @@ // doesn't have to be resolved, thus "opt" (optional). template SymbolBody *SymbolTable::addUndefinedOpt(StringRef Name) { - auto *Sym = new (Alloc) Undefined(Name, false, STV_HIDDEN, true); - resolve(Sym); + auto *Sym = new (Alloc) Undefined(false, STV_HIDDEN, true); + resolve(Name, Sym); return Sym; } @@ -140,8 +138,8 @@ DefinedRegular *SymbolTable::addAbsolute(StringRef Name, uint8_t Visibility) { // Pass nullptr because absolute symbols have no corresponding input sections. - auto *Sym = new (Alloc) DefinedRegular(Name, STB_GLOBAL, Visibility); - resolve(Sym); + auto *Sym = new (Alloc) DefinedRegular(STB_GLOBAL, Visibility); + resolve(Name, Sym); return Sym; } @@ -149,8 +147,8 @@ SymbolBody *SymbolTable::addSynthetic(StringRef Name, OutputSectionBase &Sec, uintX_t Val, uint8_t Visibility) { - auto *Sym = new (Alloc) DefinedSynthetic(Name, Val, Sec, Visibility); - resolve(Sym); + auto *Sym = new (Alloc) DefinedSynthetic(Val, Sec, Visibility); + resolve(Name, Sym); return Sym; } @@ -205,17 +203,18 @@ // Construct a string in the form of "Sym in File1 and File2". // Used to construct an error message. template -std::string SymbolTable::conflictMsg(SymbolBody *Old, SymbolBody *New) { +std::string SymbolTable::conflictMsg(StringRef Name, SymbolBody *Old, + SymbolBody *New) { InputFile *F1 = findFile(Old); InputFile *F2 = findFile(New); - StringRef Sym = Old->getName(); - return demangle(Sym) + " in " + getFilename(F1) + " and " + getFilename(F2); + return demangle(Name) + " in " + getFilename(F1) + " and " + getFilename(F2); } // This function resolves conflicts if there's an existing symbol with // the same name. Decisions are made based on symbol type. -template void SymbolTable::resolve(SymbolBody *New) { - Symbol *Sym = insert(New); +template +void SymbolTable::resolve(StringRef Name, SymbolBody *New) { + Symbol *Sym = insert(Name, New); if (Sym->Body == New) return; @@ -235,15 +234,16 @@ } if (New->isTls() != Existing->isTls()) { - error("TLS attribute mismatch for symbol: " + conflictMsg(Existing, New)); + error("TLS attribute mismatch for symbol: " + + conflictMsg(Name, Existing, New)); return; } // compare() returns -1, 0, or 1 if the lhs symbol is less preferable, // equivalent (conflicting), or more preferable, respectively. - int Comp = Existing->compare(New); + int Comp = Existing->compare(Name, New); if (Comp == 0) { - std::string S = "duplicate symbol: " + conflictMsg(Existing, New); + std::string S = "duplicate symbol: " + conflictMsg(Name, Existing, New); if (Config->AllowMultipleDefinition) warning(S); else @@ -255,8 +255,8 @@ } // Find an existing symbol or create and insert a new one. -template Symbol *SymbolTable::insert(SymbolBody *New) { - StringRef Name = New->getName(); +template +Symbol *SymbolTable::insert(StringRef Name, SymbolBody *New) { Symbol *&Sym = Symtab[Name]; if (!Sym) Sym = new (Alloc) Symbol{New}; @@ -272,7 +272,7 @@ } template void SymbolTable::addLazy(Lazy *L) { - Symbol *Sym = insert(L); + Symbol *Sym = insert(L->getName(), L); if (Sym->Body == L) return; if (auto *Undef = dyn_cast(Sym->Body)) { Index: ELF/Symbols.h =================================================================== --- ELF/Symbols.h +++ ELF/Symbols.h @@ -74,16 +74,6 @@ bool isUsedInRegularObj() const { return IsUsedInRegularObj; } bool isPreemptible() const; - // Returns the symbol name. - StringRef getName() const { - assert(!isLocal()); - return StringRef(Name.S, Name.Len); - } - uint32_t getNameOffset() const { - assert(isLocal()); - return NameOffset; - } - uint8_t getVisibility() const { return StOther & 0x3; } unsigned DynsymIndex = 0; @@ -121,21 +111,16 @@ // Decides which symbol should "win" in the symbol table, this or // the Other. Returns 1 if this wins, -1 if the Other wins, or 0 if // they are duplicate (conflicting) symbols. - int compare(SymbolBody *Other); + int compare(StringRef Name, SymbolBody *Other); protected: - SymbolBody(Kind K, StringRef Name, uint8_t Binding, uint8_t StOther, - uint8_t Type) + SymbolBody(Kind K, uint8_t Binding, uint8_t StOther, uint8_t Type) : SymbolKind(K), MustBeInDynSym(false), NeedsCopyOrPltAddr(false), - Type(Type), Binding(Binding), StOther(StOther), - Name({Name.data(), Name.size()}) { - assert(!isLocal()); + Type(Type), Binding(Binding), StOther(StOther) { IsUsedInRegularObj = K != SharedKind && K != LazyKind && K != DefinedBitcodeKind; } - SymbolBody(Kind K, uint32_t NameOffset, uint8_t StOther, uint8_t Type); - const unsigned SymbolKind : 8; // True if the symbol was used for linking and thus need to be @@ -166,37 +151,27 @@ void setVisibility(uint8_t V) { StOther = (StOther & ~0x3) | V; } protected: - struct Str { - const char *S; - size_t Len; - }; - union { - Str Name; - uint32_t NameOffset; - }; Symbol *Backref = nullptr; }; // The base class for any defined symbols. class Defined : public SymbolBody { public: - Defined(Kind K, StringRef Name, uint8_t Binding, uint8_t StOther, - uint8_t Type); - Defined(Kind K, uint32_t NameOffset, uint8_t StOther, uint8_t Type); + Defined(Kind K, uint8_t Binding, uint8_t Other, uint8_t Type); static bool classof(const SymbolBody *S) { return S->isDefined(); } }; // The defined symbol in LLVM bitcode files. class DefinedBitcode : public Defined { public: - DefinedBitcode(StringRef Name, bool IsWeak, uint8_t StOther); + DefinedBitcode(bool IsWeak, uint8_t Other); static bool classof(const SymbolBody *S); }; class DefinedCommon : public Defined { public: - DefinedCommon(StringRef N, uint64_t Size, uint64_t Alignment, uint8_t Binding, - uint8_t StOther, uint8_t Type); + DefinedCommon(uint64_t Size, uint64_t Alignment, uint8_t Binding, + uint8_t Other, uint8_t Type); static bool classof(const SymbolBody *S) { return S->kind() == SymbolBody::DefinedCommonKind; @@ -218,23 +193,14 @@ typedef typename ELFT::uint uintX_t; public: - DefinedRegular(StringRef Name, const Elf_Sym &Sym, - InputSectionBase *Section) - : Defined(SymbolBody::DefinedRegularKind, Name, Sym.getBinding(), - Sym.st_other, Sym.getType()), - Value(Sym.st_value), Size(Sym.st_size), - Section(Section ? Section->Repl : NullInputSection) {} - DefinedRegular(const Elf_Sym &Sym, InputSectionBase *Section) - : Defined(SymbolBody::DefinedRegularKind, Sym.st_name, Sym.st_other, + : Defined(SymbolBody::DefinedRegularKind, Sym.getBinding(), Sym.st_other, Sym.getType()), Value(Sym.st_value), Size(Sym.st_size), - Section(Section ? Section->Repl : NullInputSection) { - assert(isLocal()); - } + Section(Section ? Section->Repl : NullInputSection) {} - DefinedRegular(StringRef Name, uint8_t Binding, uint8_t StOther) - : Defined(SymbolBody::DefinedRegularKind, Name, Binding, StOther, + DefinedRegular(uint8_t Binding, uint8_t Other) + : Defined(SymbolBody::DefinedRegularKind, Binding, Other, llvm::ELF::STT_NOTYPE), Value(0), Size(0), Section(NullInputSection) {} @@ -267,8 +233,8 @@ template class DefinedSynthetic : public Defined { public: typedef typename ELFT::uint uintX_t; - DefinedSynthetic(StringRef N, uintX_t Value, OutputSectionBase &Section, - uint8_t StOther); + DefinedSynthetic(uintX_t Value, OutputSectionBase &Section, + uint8_t Other); static bool classof(const SymbolBody *S) { return S->kind() == SymbolBody::DefinedSyntheticKind; @@ -288,12 +254,10 @@ bool CanKeepUndefined; protected: - Undefined(Kind K, StringRef N, uint8_t Binding, uint8_t StOther, - uint8_t Type); - Undefined(Kind K, uint32_t NameOffset, uint8_t StOther, uint8_t Type); + Undefined(Kind K, uint8_t Binding, uint8_t Other, uint8_t Type); public: - Undefined(StringRef N, bool IsWeak, uint8_t StOther, bool CanKeepUndefined); + Undefined(bool IsWeak, uint8_t Other, bool CanKeepUndefined); static bool classof(const SymbolBody *S) { return S->isUndefined(); } @@ -305,7 +269,6 @@ typedef typename ELFT::Sym Elf_Sym; public: - UndefinedElf(StringRef N, const Elf_Sym &Sym); UndefinedElf(const Elf_Sym &Sym); uintX_t Size; @@ -324,8 +287,8 @@ return S->kind() == SymbolBody::SharedKind; } - SharedSymbol(SharedFile *F, StringRef Name, const Elf_Sym &Sym) - : Defined(SymbolBody::SharedKind, Name, Sym.getBinding(), Sym.st_other, + SharedSymbol(SharedFile *F, const Elf_Sym &Sym) + : Defined(SymbolBody::SharedKind, Sym.getBinding(), Sym.st_other, Sym.getType()), File(F), Sym(Sym) {} @@ -346,8 +309,8 @@ class Lazy : public SymbolBody { public: Lazy(ArchiveFile *F, const llvm::object::Archive::Symbol S) - : SymbolBody(LazyKind, S.getName(), llvm::ELF::STB_GLOBAL, - llvm::ELF::STV_DEFAULT, /* Type */ 0), + : SymbolBody(LazyKind, llvm::ELF::STB_GLOBAL, llvm::ELF::STV_DEFAULT, + /* Type */ 0), File(F), Sym(S) {} static bool classof(const SymbolBody *S) { return S->kind() == LazyKind; } @@ -356,6 +319,8 @@ // was already returned. std::unique_ptr getMember(); + StringRef getName() const { return Sym.getName(); } + private: ArchiveFile *File; const llvm::object::Archive::Symbol Sym; Index: ELF/Symbols.cpp =================================================================== --- ELF/Symbols.cpp +++ ELF/Symbols.cpp @@ -87,14 +87,6 @@ llvm_unreachable("invalid symbol kind"); } -SymbolBody::SymbolBody(Kind K, uint32_t NameOffset, uint8_t StOther, - uint8_t Type) - : SymbolKind(K), MustBeInDynSym(false), NeedsCopyOrPltAddr(false), - Type(Type), Binding(STB_LOCAL), StOther(StOther), NameOffset(NameOffset) { - IsUsedInRegularObj = - K != SharedKind && K != LazyKind && K != DefinedBitcodeKind; -} - // 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 { @@ -175,16 +167,16 @@ return std::min(VA, VB); } -static int compareCommons(DefinedCommon *A, DefinedCommon *B) { +static int compareCommons(StringRef Name, DefinedCommon *A, DefinedCommon *B) { if (Config->WarnCommon) - warning("multiple common of " + A->getName()); + warning("multiple common of " + Name); A->Alignment = B->Alignment = std::max(A->Alignment, B->Alignment); return A->Size < B->Size ? -1 : 1; } // Returns 1, 0 or -1 if this symbol should take precedence // over the Other, tie or lose, respectively. -int SymbolBody::compare(SymbolBody *Other) { +int SymbolBody::compare(StringRef Name, SymbolBody *Other) { assert(!isLazy() && !Other->isLazy()); std::tuple L(isDefined(), !isShared(), !isWeak()); std::tuple R(Other->isDefined(), !Other->isShared(), @@ -192,7 +184,7 @@ // Normalize if (L > R) - return -Other->compare(this); + return -Other->compare(Name, this); uint8_t V = getMinVisibility(getVisibility(), Other->getVisibility()); setVisibility(V); @@ -217,68 +209,51 @@ if (!isCommon() && !Other->isCommon()) return 0; if (isCommon() && Other->isCommon()) - return compareCommons(cast(this), + return compareCommons(Name, cast(this), cast(Other)); if (Config->WarnCommon) - warning("common " + this->getName() + " is overridden"); + warning("common " + Name + " is overridden"); return isCommon() ? -1 : 1; } -Defined::Defined(Kind K, StringRef Name, uint8_t Binding, uint8_t Visibility, - uint8_t Type) - : SymbolBody(K, Name, Binding, Visibility, Type) {} - -Defined::Defined(Kind K, uint32_t NameOffset, uint8_t Visibility, uint8_t Type) - : SymbolBody(K, NameOffset, Visibility, Type) {} +Defined::Defined(Kind K, uint8_t Binding, uint8_t Other, uint8_t Type) + : SymbolBody(K, Binding, Other, Type) {} -DefinedBitcode::DefinedBitcode(StringRef Name, bool IsWeak, uint8_t Visibility) - : Defined(DefinedBitcodeKind, Name, IsWeak ? STB_WEAK : STB_GLOBAL, - Visibility, 0 /* Type */) {} +DefinedBitcode::DefinedBitcode(bool IsWeak, uint8_t Other) + : Defined(DefinedBitcodeKind, IsWeak ? STB_WEAK : STB_GLOBAL, Other, + 0 /* Type */) {} bool DefinedBitcode::classof(const SymbolBody *S) { return S->kind() == DefinedBitcodeKind; } -Undefined::Undefined(SymbolBody::Kind K, StringRef N, uint8_t Binding, - uint8_t Other, uint8_t Type) - : SymbolBody(K, N, Binding, Other, Type), CanKeepUndefined(false) {} - -Undefined::Undefined(SymbolBody::Kind K, uint32_t NameOffset, - uint8_t Visibility, uint8_t Type) - : SymbolBody(K, NameOffset, Visibility, Type), CanKeepUndefined(false) {} - -Undefined::Undefined(StringRef N, bool IsWeak, uint8_t Visibility, - bool CanKeepUndefined) - : Undefined(SymbolBody::UndefinedKind, N, IsWeak ? STB_WEAK : STB_GLOBAL, - Visibility, 0 /* Type */) { +Undefined::Undefined(bool IsWeak, uint8_t Other, bool CanKeepUndefined) + : Undefined(SymbolBody::UndefinedKind, IsWeak ? STB_WEAK : STB_GLOBAL, + Other, 0) { this->CanKeepUndefined = CanKeepUndefined; } -template -UndefinedElf::UndefinedElf(StringRef N, const Elf_Sym &Sym) - : Undefined(SymbolBody::UndefinedElfKind, N, Sym.getBinding(), Sym.st_other, - Sym.getType()), - Size(Sym.st_size) {} +Undefined::Undefined(SymbolBody::Kind K, uint8_t Binding, uint8_t Other, + uint8_t Type) + : SymbolBody(K, Binding, Other, Type), CanKeepUndefined(false) {} template UndefinedElf::UndefinedElf(const Elf_Sym &Sym) - : Undefined(SymbolBody::UndefinedElfKind, NameOffset, Sym.st_other, + : Undefined(SymbolBody::UndefinedElfKind, Sym.getBinding(), Sym.st_other, Sym.getType()), - Size(Sym.st_size) { - assert(Sym.getBinding() == STB_LOCAL); -} + Size(Sym.st_size) {} template -DefinedSynthetic::DefinedSynthetic(StringRef N, uintX_t Value, +DefinedSynthetic::DefinedSynthetic(uintX_t Value, OutputSectionBase &Section, uint8_t Visibility) - : Defined(SymbolBody::DefinedSyntheticKind, N, STB_GLOBAL, Visibility, + : Defined(SymbolBody::DefinedSyntheticKind, STB_GLOBAL, Visibility, 0 /* Type */), Value(Value), Section(Section) {} -DefinedCommon::DefinedCommon(StringRef N, uint64_t Size, uint64_t Alignment, - uint8_t Binding, uint8_t Visibility, uint8_t Type) - : Defined(SymbolBody::DefinedCommonKind, N, Binding, Visibility, Type), +DefinedCommon::DefinedCommon(uint64_t Size, uint64_t Alignment, uint8_t Binding, + uint8_t Visibility, uint8_t Type) + : Defined(SymbolBody::DefinedCommonKind, Binding, Visibility, Type), Alignment(Alignment), Size(Size) {} std::unique_ptr Lazy::getMember() { Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -507,11 +507,12 @@ } template -static void reportUndefined(SymbolTable &Symtab, SymbolBody *Sym) { +static void reportUndefined(SymbolTable &Symtab, StringRef Name, + SymbolBody *Sym) { if ((Config->Relocatable || Config->Shared) && !Config->NoUndefined) return; - std::string Msg = "undefined symbol: " + Sym->getName().str(); + std::string Msg = "undefined symbol: " + Name.str(); if (InputFile *File = Symtab.findFile(Sym)) Msg += " in " + File->getName().str(); if (Config->NoinhibitExec) @@ -558,13 +559,18 @@ return; for (const std::unique_ptr> &F : Symtab.getObjectFiles()) { - const char *StrTab = F->getStringTable().data(); - for (SymbolBody *B : F->getLocalSymbols()) { + StringRef StrTab = F->getStringTable(); + ArrayRef Bodies = F->getSymbols(); + unsigned Index = 0; + auto Syms = F->getElfSymbols(ELFFileBase::LOCAL_SYMBOLS); + for (const Elf_Sym &Sym : Syms) { + unsigned Cur = Index++; + SymbolBody *B = Bodies[Cur]; auto *DR = dyn_cast>(B); // No reason to keep local undefined symbol in symtab. if (!DR) continue; - StringRef SymName(StrTab + B->getNameOffset()); + StringRef SymName = check(Sym.getName(StrTab)); InputSectionBase *Sec = DR->Section; if (!shouldKeepInSymtab(Sec, SymName, *B)) continue; @@ -1087,7 +1093,7 @@ SymbolBody *Body = P.second->Body; if (auto *U = dyn_cast(Body)) if (!U->isWeak() && !U->canKeepUndefined()) - reportUndefined(Symtab, Body); + reportUndefined(Symtab, P.first, Body); if (auto *C = dyn_cast(Body)) CommonSymbols.push_back(C); @@ -1095,10 +1101,10 @@ if (!includeInSymtab(*Body)) continue; if (Out::SymTab) - Out::SymTab->addSymbol(Body); + Out::SymTab->addSymbol(P.first, Body); if (isOutputDynamic() && includeInDynsym(*Body)) - Out::DynSymTab->addSymbol(Body); + Out::DynSymTab->addSymbol(P.first, Body); } // Do not proceed if there was an undefined symbol.