diff --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h index e9f9eb914d96..7ba83967330e 100644 --- a/llvm/include/llvm/ObjectYAML/ELFYAML.h +++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h @@ -207,6 +207,7 @@ struct Object { // top-level key, which automatically ensures that invariants like there // being a single SHT_SYMTAB section are upheld. LocalGlobalWeakSymbols Symbols; + LocalGlobalWeakSymbols DynamicSymbols; }; } // end namespace ELFYAML diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp index 38940376de24..7e7f3d1fdded 100644 --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -933,6 +933,7 @@ void MappingTraits::mapping(IO &IO, ELFYAML::Object &Object) { IO.mapOptional("ProgramHeaders", Object.ProgramHeaders); IO.mapOptional("Sections", Object.Sections); IO.mapOptional("Symbols", Object.Symbols); + IO.mapOptional("DynamicSymbols", Object.DynamicSymbols); IO.setContext(nullptr); } diff --git a/llvm/test/tools/yaml2obj/dynamic-symbols.yaml b/llvm/test/tools/yaml2obj/dynamic-symbols.yaml new file mode 100644 index 000000000000..c77f743e3691 --- /dev/null +++ b/llvm/test/tools/yaml2obj/dynamic-symbols.yaml @@ -0,0 +1,41 @@ +# Ensures that implicitly added sections can be ordered within Sections. +# RUN: yaml2obj %s -o %t +# RUN: llvm-readobj -sections %t | FileCheck %s --check-prefix=SECTION +# RUN: llvm-nm -dynamic %t | FileCheck %s --check-prefix=SYMBOL + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Name: .data + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_WRITE ] +DynamicSymbols: + Global: + - Name: dynglobal + Type: STT_OBJECT + Section: .data + Weak: + - Name: dynweak + Type: STT_OBJECT + Section: .data + Local: + - Name: dynlocal + Type: STT_OBJECT + Section: .data + +# SECTION: Name: .dynsym +# SECTION-NEXT: Type: SHT_DYNSYM +# SECTION-NEXT: Flags +# SECTION-NEXT: SHF_ALLOC +# SECTION: Name: .dynstr +# SECTION-NEXT: Type: SHT_STRTAB +# SECTION-NEXT: Flags +# SECTION-NEXT: SHF_ALLOC + +# SYMBOL-DAG: D dynglobal +# SYMBOL-DAG: V dynweak +# SYMBOL-DAG: d dynlocal diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index 9f56a28d934f..cd107ec91ba1 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -1322,6 +1322,7 @@ ELFDumper::ELFDumper(const ELFFile *Obj, ScopedPrinter &Writer) DynSymRegion = createDRIFrom(&Sec); // This is only used (if Elf_Shdr present)for naming section in GNU style DynSymtabName = unwrapOrError(Obj->getSectionName(&Sec)); + DynamicStringTable = unwrapOrError(Obj->getStringTableForSymtab(Sec)); break; case ELF::SHT_SYMTAB_SHNDX: ShndxTable = unwrapOrError(Obj->getSHNDXTable(Sec)); diff --git a/llvm/tools/obj2yaml/elf2yaml.cpp b/llvm/tools/obj2yaml/elf2yaml.cpp index 8c94843788f6..f6a559c15f21 100644 --- a/llvm/tools/obj2yaml/elf2yaml.cpp +++ b/llvm/tools/obj2yaml/elf2yaml.cpp @@ -42,6 +42,8 @@ class ELFDumper { const object::ELFFile &Obj; ArrayRef ShndxTable; + std::error_code dumpSymbols(const Elf_Shdr *Symtab, + ELFYAML::LocalGlobalWeakSymbols &Symbols); std::error_code dumpSymbol(const Elf_Sym *Sym, const Elf_Shdr *SymTab, StringRef StrTable, ELFYAML::Symbol &S); std::error_code dumpCommonSection(const Elf_Shdr *Shdr, ELFYAML::Section &S); @@ -119,6 +121,7 @@ template ErrorOr ELFDumper::dump() { Y->Header.Entry = Obj.getHeader()->e_entry; const Elf_Shdr *Symtab = nullptr; + const Elf_Shdr *DynSymtab = nullptr; // Dump sections auto SectionsOrErr = Obj.sections(); @@ -129,13 +132,15 @@ template ErrorOr ELFDumper::dump() { for (const Elf_Shdr &Sec : Sections) { switch (Sec.sh_type) { case ELF::SHT_NULL: - case ELF::SHT_DYNSYM: case ELF::SHT_STRTAB: // Do not dump these sections. break; case ELF::SHT_SYMTAB: Symtab = &Sec; break; + case ELF::SHT_DYNSYM: + DynSymtab = &Sec; + break; case ELF::SHT_SYMTAB_SHNDX: { auto TableOrErr = Obj.getSHNDXTable(Sec); if (!TableOrErr) @@ -187,46 +192,57 @@ template ErrorOr ELFDumper::dump() { } } - // Dump symbols + if (auto EC = dumpSymbols(Symtab, Y->Symbols)) + return EC; + if (auto EC = dumpSymbols(DynSymtab, Y->DynamicSymbols)) + return EC; + + return Y.release(); +} + +template +std::error_code +ELFDumper::dumpSymbols(const Elf_Shdr *Symtab, + ELFYAML::LocalGlobalWeakSymbols &Symbols) { if (!Symtab) - return Y.release(); // if the symbol table is missing return early + return std::error_code(); + auto StrTableOrErr = Obj.getStringTableForSymtab(*Symtab); if (!StrTableOrErr) return errorToErrorCode(StrTableOrErr.takeError()); StringRef StrTable = *StrTableOrErr; - bool IsFirstSym = true; auto SymtabOrErr = Obj.symbols(Symtab); if (!SymtabOrErr) return errorToErrorCode(SymtabOrErr.takeError()); - for (const Elf_Sym &Sym : *SymtabOrErr) { + + bool IsFirstSym = true; + for (const auto &Sym : *SymtabOrErr) { if (IsFirstSym) { IsFirstSym = false; continue; } ELFYAML::Symbol S; - if (std::error_code EC = - ELFDumper::dumpSymbol(&Sym, Symtab, StrTable, S)) + if (auto EC = dumpSymbol(&Sym, Symtab, StrTable, S)) return EC; - switch (Sym.getBinding()) - { + switch (Sym.getBinding()) { case ELF::STB_LOCAL: - Y->Symbols.Local.push_back(S); + Symbols.Local.push_back(S); break; case ELF::STB_GLOBAL: - Y->Symbols.Global.push_back(S); + Symbols.Global.push_back(S); break; case ELF::STB_WEAK: - Y->Symbols.Weak.push_back(S); + Symbols.Weak.push_back(S); break; default: llvm_unreachable("Unknown ELF symbol binding"); } } - return Y.release(); + return std::error_code(); } template diff --git a/llvm/tools/yaml2obj/yaml2elf.cpp b/llvm/tools/yaml2obj/yaml2elf.cpp index fce910a093de..21648469654a 100644 --- a/llvm/tools/yaml2obj/yaml2elf.cpp +++ b/llvm/tools/yaml2obj/yaml2elf.cpp @@ -114,12 +114,17 @@ class ELFState { typedef typename object::ELFFile::Elf_Rel Elf_Rel; typedef typename object::ELFFile::Elf_Rela Elf_Rela; + enum class SymtabType { Static, Dynamic }; + /// \brief The future ".strtab" section. StringTableBuilder DotStrtab{StringTableBuilder::ELF}; /// \brief The future ".shstrtab" section. StringTableBuilder DotShStrtab{StringTableBuilder::ELF}; + /// \brief The future ".dynstr" section. + StringTableBuilder DotDynstr{StringTableBuilder::ELF}; + NameToIdxMap SN2I; NameToIdxMap SymN2I; const ELFYAML::Object &Doc; @@ -131,7 +136,7 @@ class ELFState { void initProgramHeaders(std::vector &PHeaders); bool initSectionHeaders(std::vector &SHeaders, ContiguousBlobAccumulator &CBA); - void initSymtabSectionHeader(Elf_Shdr &SHeader, + void initSymtabSectionHeader(Elf_Shdr &SHeader, SymtabType STType, ContiguousBlobAccumulator &CBA); void initStrtabSectionHeader(Elf_Shdr &SHeader, StringRef Name, StringTableBuilder &STB, @@ -139,7 +144,8 @@ class ELFState { void setProgramHeaderLayout(std::vector &PHeaders, std::vector &SHeaders); void addSymbols(const std::vector &Symbols, - std::vector &Syms, unsigned SymbolBinding); + std::vector &Syms, unsigned SymbolBinding, + const StringTableBuilder &Strtab); void writeSectionContent(Elf_Shdr &SHeader, const ELFYAML::RawContentSection &Section, ContiguousBlobAccumulator &CBA); @@ -151,14 +157,20 @@ class ELFState { bool writeSectionContent(Elf_Shdr &SHeader, const ELFYAML::MipsABIFlags &Section, ContiguousBlobAccumulator &CBA); + bool hasDynamicSymbols() const; + SmallVector implicitSectionNames() const; // - SHT_NULL entry (placed first, i.e. 0'th entry) - // - symbol table (.symtab) (defaults to third to last) - // - string table (.strtab) (defaults to second to last) - // - section header string table (.shstrtab) (defaults to last) + // - symbol table (.symtab) (defaults to after last yaml section) + // - string table (.strtab) (defaults to after .symtab) + // - section header string table (.shstrtab) (defaults to after .strtab) + // - dynamic symbol table (.dynsym) (defaults to after .shstrtab) + // - dynamic string table (.dynstr) (defaults to after .dynsym) unsigned getDotSymTabSecNo() const { return SN2I.get(".symtab"); } unsigned getDotStrTabSecNo() const { return SN2I.get(".strtab"); } unsigned getDotShStrTabSecNo() const { return SN2I.get(".shstrtab"); } + unsigned getDotDynSymSecNo() const { return SN2I.get(".dynsym"); } + unsigned getDotDynStrSecNo() const { return SN2I.get(".dynstr"); } unsigned getSectionCount() const { return SN2I.size() + 1; } ELFState(const ELFYAML::Object &D) : Doc(D) {} @@ -166,8 +178,6 @@ class ELFState { public: static int writeELF(raw_ostream &OS, const ELFYAML::Object &Doc); }; - -static const char * const ImplicitSecNames[] = {".symtab", ".strtab", ".shstrtab"}; } // end anonymous namespace template @@ -288,13 +298,17 @@ bool ELFState::initSectionHeaders(std::vector &SHeaders, template void ELFState::initSymtabSectionHeader(Elf_Shdr &SHeader, + SymtabType STType, ContiguousBlobAccumulator &CBA) { zero(SHeader); - SHeader.sh_name = DotShStrtab.getOffset(".symtab"); - SHeader.sh_type = ELF::SHT_SYMTAB; - SHeader.sh_link = getDotStrTabSecNo(); + bool IsStatic = STType == SymtabType::Static; + SHeader.sh_name = DotShStrtab.getOffset(IsStatic ? ".symtab" : ".dynsym"); + SHeader.sh_type = IsStatic ? ELF::SHT_SYMTAB : ELF::SHT_DYNSYM; + SHeader.sh_link = IsStatic ? getDotStrTabSecNo() : getDotDynStrSecNo(); + const auto &Symbols = IsStatic ? Doc.Symbols : Doc.DynamicSymbols; + auto &Strtab = IsStatic ? DotStrtab : DotDynstr; // One greater than symbol table index of the last local symbol. - SHeader.sh_info = Doc.Symbols.Local.size() + 1; + SHeader.sh_info = Symbols.Local.size() + 1; SHeader.sh_entsize = sizeof(Elf_Sym); SHeader.sh_addralign = 8; @@ -306,18 +320,18 @@ void ELFState::initSymtabSectionHeader(Elf_Shdr &SHeader, Syms.push_back(Sym); } - // Add symbol names to .strtab. - for (const auto &Sym : Doc.Symbols.Local) - DotStrtab.add(Sym.Name); - for (const auto &Sym : Doc.Symbols.Global) - DotStrtab.add(Sym.Name); - for (const auto &Sym : Doc.Symbols.Weak) - DotStrtab.add(Sym.Name); - DotStrtab.finalize(); + // Add symbol names to .strtab or .dynstr. + for (const auto &Sym : Symbols.Local) + Strtab.add(Sym.Name); + for (const auto &Sym : Symbols.Global) + Strtab.add(Sym.Name); + for (const auto &Sym : Symbols.Weak) + Strtab.add(Sym.Name); + Strtab.finalize(); - addSymbols(Doc.Symbols.Local, Syms, ELF::STB_LOCAL); - addSymbols(Doc.Symbols.Global, Syms, ELF::STB_GLOBAL); - addSymbols(Doc.Symbols.Weak, Syms, ELF::STB_WEAK); + addSymbols(Symbols.Local, Syms, ELF::STB_LOCAL, Strtab); + addSymbols(Symbols.Global, Syms, ELF::STB_GLOBAL, Strtab); + addSymbols(Symbols.Weak, Syms, ELF::STB_WEAK, Strtab); writeArrayData( CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign), @@ -405,12 +419,13 @@ void ELFState::setProgramHeaderLayout(std::vector &PHeaders, template void ELFState::addSymbols(const std::vector &Symbols, std::vector &Syms, - unsigned SymbolBinding) { + unsigned SymbolBinding, + const StringTableBuilder &Strtab) { for (const auto &Sym : Symbols) { Elf_Sym Symbol; zero(Symbol); if (!Sym.Name.empty()) - Symbol.st_name = DotStrtab.getOffset(Sym.Name); + Symbol.st_name = Strtab.getOffset(Sym.Name); Symbol.setBindingAndType(SymbolBinding, Sym.Type); if (!Sym.Section.empty()) { unsigned Index; @@ -567,7 +582,7 @@ template bool ELFState::buildSectionIndex() { auto SecNo = 1 + Doc.Sections.size(); // Add special sections after input sections, if necessary. - for (const auto &Name : ImplicitSecNames) + for (const auto &Name : implicitSectionNames()) if (!SN2I.addName(Name, SecNo)) { // Account for this section, since it wasn't in the Doc ++SecNo; @@ -626,17 +641,25 @@ int ELFState::writeELF(raw_ostream &OS, const ELFYAML::Object &Doc) { return 1; // Populate SHeaders with implicit sections not present in the Doc - for (const auto &Name : ImplicitSecNames) + for (const auto &Name : State.implicitSectionNames()) if (State.SN2I.get(Name) >= SHeaders.size()) SHeaders.push_back({}); // Initialize the implicit sections auto Index = State.SN2I.get(".symtab"); - State.initSymtabSectionHeader(SHeaders[Index], CBA); + State.initSymtabSectionHeader(SHeaders[Index], SymtabType::Static, CBA); Index = State.SN2I.get(".strtab"); State.initStrtabSectionHeader(SHeaders[Index], ".strtab", State.DotStrtab, CBA); Index = State.SN2I.get(".shstrtab"); State.initStrtabSectionHeader(SHeaders[Index], ".shstrtab", State.DotShStrtab, CBA); + if (State.hasDynamicSymbols()) { + Index = State.SN2I.get(".dynsym"); + State.initSymtabSectionHeader(SHeaders[Index], SymtabType::Dynamic, CBA); + SHeaders[Index].sh_flags |= ELF::SHF_ALLOC; + Index = State.SN2I.get(".dynstr"); + State.initStrtabSectionHeader(SHeaders[Index], ".dynstr", State.DotDynstr, CBA); + SHeaders[Index].sh_flags |= ELF::SHF_ALLOC; + } // Now we can decide segment offsets State.setProgramHeaderLayout(PHeaders, SHeaders); @@ -648,6 +671,18 @@ int ELFState::writeELF(raw_ostream &OS, const ELFYAML::Object &Doc) { return 0; } +template bool ELFState::hasDynamicSymbols() const { + return Doc.DynamicSymbols.Global.size() > 0 || + Doc.DynamicSymbols.Weak.size() > 0 || + Doc.DynamicSymbols.Local.size() > 0; +} + +template SmallVector ELFState::implicitSectionNames() const { + if (!hasDynamicSymbols()) + return {".symtab", ".strtab", ".shstrtab"}; + return {".symtab", ".strtab", ".shstrtab", ".dynsym", ".dynstr"}; +} + static bool is64Bit(const ELFYAML::Object &Doc) { return Doc.Header.Class == ELFYAML::ELF_ELFCLASS(ELF::ELFCLASS64); }