Index: include/llvm/ObjectYAML/ELFYAML.h =================================================================== --- include/llvm/ObjectYAML/ELFYAML.h +++ include/llvm/ObjectYAML/ELFYAML.h @@ -121,6 +121,7 @@ RawContent, Relocation, NoBits, + Verneed, MipsABIFlags }; SectionKind Kind; @@ -167,6 +168,30 @@ } }; +struct VernauxEntry { + uint32_t Hash; + uint32_t Flags; + uint32_t Other; + StringRef Name; +}; + +struct VerneedEntry { + uint32_t Version; + StringRef File; + std::vector AuxV; +}; + +struct VerneedSection : Section { + std::vector VerneedV; + llvm::yaml::Hex64 Info; + + VerneedSection() : Section(SectionKind::Verneed) {} + + static bool classof(const Section *S) { + return S->Kind == SectionKind::Verneed; + } +}; + struct Group : Section { // Members of a group contain a flag and a list of section indices // that are part of the group. @@ -238,6 +263,8 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::ProgramHeader) LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::Symbol) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::VernauxEntry) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::VerneedEntry) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::Relocation) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::SectionOrType) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::SectionName) @@ -381,6 +408,13 @@ static void mapping(IO &IO, ELFYAML::DynamicEntry &Rel); }; +template <> struct MappingTraits { + static void mapping(IO &IO, ELFYAML::VerneedEntry &E); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, ELFYAML::VernauxEntry &E); +}; template <> struct MappingTraits { static void mapping(IO &IO, ELFYAML::Relocation &Rel); }; Index: lib/ObjectYAML/ELFYAML.cpp =================================================================== --- lib/ObjectYAML/ELFYAML.cpp +++ lib/ObjectYAML/ELFYAML.cpp @@ -872,6 +872,12 @@ IO.mapOptional("Size", Section.Size, Hex64(0)); } +static void sectionMapping(IO &IO, ELFYAML::VerneedSection &Section) { + commonSectionMapping(IO, Section); + IO.mapRequired("Info", Section.Info); + IO.mapRequired("Dependencies", Section.VerneedV); +} + static void sectionMapping(IO &IO, ELFYAML::RelocationSection &Section) { commonSectionMapping(IO, Section); IO.mapOptional("Info", Section.RelocatableSec, StringRef()); @@ -949,6 +955,11 @@ Section.reset(new ELFYAML::MipsABIFlags()); sectionMapping(IO, *cast(Section.get())); break; + case ELF::SHT_GNU_verneed: + if (!IO.outputting()) + Section.reset(new ELFYAML::VerneedSection()); + sectionMapping(IO, *cast(Section.get())); + break; default: if (!IO.outputting()) Section.reset(new ELFYAML::RawContentSection()); @@ -997,6 +1008,27 @@ IO.mapRequired("Value", Rel.Val); } +void MappingTraits::mapping(IO &IO, + ELFYAML::VerneedEntry &E) { + const auto *Object = static_cast(IO.getContext()); + assert(Object && "The IO context is not initialized"); + + IO.mapRequired("Version", E.Version); + IO.mapRequired("File", E.File); + IO.mapRequired("Entries", E.AuxV); +} + +void MappingTraits::mapping(IO &IO, + ELFYAML::VernauxEntry &E) { + const auto *Object = static_cast(IO.getContext()); + assert(Object && "The IO context is not initialized"); + + IO.mapRequired("Name", E.Name); + IO.mapRequired("Hash", E.Hash); + IO.mapRequired("Flags", E.Flags); + IO.mapRequired("Other", E.Other); +} + void MappingTraits::mapping(IO &IO, ELFYAML::Relocation &Rel) { const auto *Object = static_cast(IO.getContext()); Index: test/tools/obj2yaml/verneed-section.yaml =================================================================== --- /dev/null +++ test/tools/obj2yaml/verneed-section.yaml @@ -0,0 +1,69 @@ +# RUN: yaml2obj %s -o %t +# RUN: obj2yaml %t | FileCheck %s + +## Check we are able to yamalize SHT_GNU_verneed section. + +# CHECK: - Name: .gnu.version_r +# CHECK-NEXT: Type: SHT_GNU_verneed +# CHECK-NEXT: Flags: [ SHF_ALLOC ] +# CHECK-NEXT: Address: 0x0000000000200250 +# CHECK-NEXT: Link: .dynstr +# CHECK-NEXT: AddressAlign: 0x0000000000000004 +# CHECK-NEXT: Info: 0x0000000000000002 +# CHECK-NEXT: Dependencies: +# CHECK-NEXT: - Version: 1 +# CHECK-NEXT: File: dso.so.0 +# CHECK-NEXT: Entries: +# CHECK-NEXT: - Name: v1 +# CHECK-NEXT: Hash: 1937 +# CHECK-NEXT: Flags: 10 +# CHECK-NEXT: Other: 3 +# CHECK-NEXT: - Name: v2 +# CHECK-NEXT: Hash: 1938 +# CHECK-NEXT: Flags: 11 +# CHECK-NEXT: Other: 4 +# CHECK-NEXT: - Version: 2 +# CHECK-NEXT: File: dso.so.1 +# CHECK-NEXT: Entries: +# CHECK-NEXT: - Name: v3 +# CHECK-NEXT: Hash: 1939 +# CHECK-NEXT: Flags: 12 +# CHECK-NEXT: Other: 2 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 + Entry: 0x0000000000201000 +Sections: + - Name: .gnu.version_r + Type: SHT_GNU_verneed + Flags: [ SHF_ALLOC ] + Address: 0x200250 + Link: .dynstr + AddressAlign: 4 + Info: 2 + Dependencies: + - Version: 1 + File: dso.so.0 + Entries: + - Name: v1 + Hash: 1937 + Flags: 10 + Other: 3 + - Name: v2 + Hash: 1938 + Flags: 11 + Other: 4 + - Version: 2 + File: dso.so.1 + Entries: + - Name: v3 + Hash: 1939 + Flags: 12 + Other: 2 +DynamicSymbols: + Global: + - Name: f1 Index: test/tools/yaml2obj/verneed-section.yaml =================================================================== --- /dev/null +++ test/tools/yaml2obj/verneed-section.yaml @@ -0,0 +1,73 @@ +# RUN: yaml2obj %s -o %t +# RUN: llvm-readelf -V %t | FileCheck %s + +# Check we are able to handle the SHT_GNU_verneed sections. + +# CHECK: SHT_GNU_verneed { +# CHECK-NEXT: Dependency { +# CHECK-NEXT: Version: 1 +# CHECK-NEXT: Count: 2 +# CHECK-NEXT: FileName: dso.so.0 +# CHECK-NEXT: Entry { +# CHECK-NEXT: Hash: 1937 +# CHECK-NEXT: Flags: 0xA +# CHECK-NEXT: Index: 3 +# CHECK-NEXT: Name: v1 +# CHECK-NEXT: } +# CHECK-NEXT: Entry { +# CHECK-NEXT: Hash: 1938 +# CHECK-NEXT: Flags: 0xB +# CHECK-NEXT: Index: 4 +# CHECK-NEXT: Name: v2 +# CHECK-NEXT: } +# CHECK-NEXT: } +# CHECK-NEXT: Dependency { +# CHECK-NEXT: Version: 2 +# CHECK-NEXT: Count: 1 +# CHECK-NEXT: FileName: dso.so.1 +# CHECK-NEXT: Entry { +# CHECK-NEXT: Hash: 1939 +# CHECK-NEXT: Flags: 0xC +# CHECK-NEXT: Index: 2 +# CHECK-NEXT: Name: v3 +# CHECK-NEXT: } +# CHECK-NEXT: } +# CHECK-NEXT: } + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 + Entry: 0x0000000000201000 +Sections: + - Name: .gnu.version_r + Type: SHT_GNU_verneed + Flags: [ SHF_ALLOC ] + Address: 0x0000000000200250 + Link: .dynstr + AddressAlign: 0x0000000000000004 + Info: 0x0000000000000002 + Dependencies: + - Version: 1 + File: dso.so.0 + Entries: + - Name: v1 + Hash: 1937 + Flags: 10 + Other: 3 + - Name: v2 + Hash: 1938 + Flags: 11 + Other: 4 + - Version: 2 + File: dso.so.1 + Entries: + - Name: v3 + Hash: 1939 + Flags: 12 + Other: 2 +DynamicSymbols: + Global: + - Name: f1 Index: tools/obj2yaml/elf2yaml.cpp =================================================================== --- tools/obj2yaml/elf2yaml.cpp +++ tools/obj2yaml/elf2yaml.cpp @@ -57,6 +57,7 @@ ErrorOr dumpContentSection(const Elf_Shdr *Shdr); ErrorOr dumpNoBitsSection(const Elf_Shdr *Shdr); + ErrorOr dumpVerneedSection(const Elf_Shdr *Shdr); ErrorOr dumpGroup(const Elf_Shdr *Shdr); ErrorOr dumpMipsABIFlags(const Elf_Shdr *Shdr); @@ -184,6 +185,13 @@ Y->Sections.push_back(std::unique_ptr(S.get())); break; } + case ELF::SHT_GNU_verneed: { + ErrorOr S = dumpVerneedSection(&Sec); + if (std::error_code EC = S.getError()) + return EC; + Y->Sections.push_back(std::unique_ptr(S.get())); + break; + } default: { ErrorOr S = dumpContentSection(&Sec); if (std::error_code EC = S.getError()) @@ -443,6 +451,64 @@ return S.release(); } +template +ErrorOr +ELFDumper::dumpVerneedSection(const Elf_Shdr *Shdr) { + typedef typename ELFT::Verneed Elf_Verneed; + typedef typename ELFT::Vernaux Elf_Vernaux; + + auto S = make_unique(); + if (std::error_code EC = dumpCommonSection(Shdr, *S)) + return EC; + + S->Info = Shdr->sh_info; + + auto Contents = Obj.getSectionContents(Shdr); + if (!Contents) + return errorToErrorCode(Contents.takeError()); + + auto StringTableShdrOrErr = Obj.getSection(Shdr->sh_link); + if (!StringTableShdrOrErr) + return errorToErrorCode(StringTableShdrOrErr.takeError()); + + auto StringTableOrErr = Obj.getStringTable(*StringTableShdrOrErr); + if (!StringTableOrErr) + return errorToErrorCode(StringTableOrErr.takeError()); + + llvm::ArrayRef Data = *Contents; + const uint8_t* Buf = Data.data(); + while (Buf) { + S->VerneedV.resize(S->VerneedV.size() + 1); + ELFYAML::VerneedEntry &Entry = S->VerneedV.back(); + + const Elf_Verneed *Verneed = reinterpret_cast(Buf); + Entry.Version = Verneed->vn_version; + Entry.File = + StringRef(StringTableOrErr->drop_front(Verneed->vn_file).data()); + + const uint8_t *BufAux = Buf + Verneed->vn_aux; + while (BufAux) { + const Elf_Vernaux *Vernaux = + reinterpret_cast(BufAux); + Entry.AuxV.resize(Entry.AuxV.size() + 1); + ELFYAML::VernauxEntry &Aux = Entry.AuxV.back(); + + Aux.Hash = Vernaux->vna_hash; + Aux.Flags = Vernaux->vna_flags; + Aux.Other = Vernaux->vna_other; + Aux.Name = + StringRef(StringTableOrErr->drop_front(Vernaux->vna_name).data()); + + BufAux = Vernaux->vna_next ? BufAux + Vernaux->vna_next : nullptr; + } + + // Move to the next Verneed entry. + Buf = Verneed->vn_next ? Buf + Verneed->vn_next : nullptr; + } + + return S.release(); +} + template ErrorOr ELFDumper::dumpGroup(const Elf_Shdr *Shdr) { auto S = make_unique(); Index: tools/yaml2obj/yaml2elf.cpp =================================================================== --- tools/yaml2obj/yaml2elf.cpp +++ tools/yaml2obj/yaml2elf.cpp @@ -156,6 +156,9 @@ ContiguousBlobAccumulator &CBA); bool writeSectionContent(Elf_Shdr &SHeader, const ELFYAML::Group &Group, ContiguousBlobAccumulator &CBA); + bool writeSectionContent(Elf_Shdr &SHeader, + const ELFYAML::VerneedSection &Section, + ContiguousBlobAccumulator &CBA); bool writeSectionContent(Elf_Shdr &SHeader, const ELFYAML::MipsABIFlags &Section, ContiguousBlobAccumulator &CBA); @@ -182,6 +185,9 @@ public: static int writeELF(raw_ostream &OS, const ELFYAML::Object &Doc); + +private: + void finalizeStrings(); }; } // end anonymous namespace @@ -297,6 +303,8 @@ CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign); } else if (auto S = dyn_cast(Sec.get())) { writeSectionContent(SHeader, *S, CBA); + } else if (auto S = dyn_cast(Sec.get())) { + writeSectionContent(SHeader, *S, CBA); } else llvm_unreachable("Unknown section type"); @@ -329,15 +337,6 @@ Syms.push_back(Sym); } - // 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(Symbols.Local, Syms, ELF::STB_LOCAL, Strtab); addSymbols(Symbols.Global, Syms, ELF::STB_GLOBAL, Strtab); addSymbols(Symbols.Weak, Syms, ELF::STB_WEAK, Strtab); @@ -550,6 +549,54 @@ return true; } +template +bool ELFState::writeSectionContent(Elf_Shdr &SHeader, + const ELFYAML::VerneedSection &Section, + ContiguousBlobAccumulator &CBA) { + typedef typename ELFT::Verneed Elf_Verneed; + typedef typename ELFT::Vernaux Elf_Vernaux; + + auto &OS = CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign); + + uint64_t AuxCnt = 0; + for (size_t I = 0; I < Section.VerneedV.size(); ++I) { + const ELFYAML::VerneedEntry &VE = Section.VerneedV[I]; + + Elf_Verneed VerNeed; + VerNeed.vn_version = VE.Version; + VerNeed.vn_file = DotDynstr.getOffset(VE.File); + if (I == Section.VerneedV.size() - 1) + VerNeed.vn_next = 0; + else + VerNeed.vn_next = + sizeof(Elf_Verneed) + VE.AuxV.size() * sizeof(Elf_Vernaux); + VerNeed.vn_cnt = VE.AuxV.size(); + VerNeed.vn_aux = sizeof(Elf_Verneed); + OS.write((const char *)&VerNeed, sizeof(Elf_Verneed)); + + for (size_t J = 0; J < VE.AuxV.size(); ++J, ++AuxCnt) { + const ELFYAML::VernauxEntry &VAuxE = VE.AuxV[J]; + + Elf_Vernaux VernAux; + VernAux.vna_hash = VAuxE.Hash; + VernAux.vna_flags = VAuxE.Flags; + VernAux.vna_other = VAuxE.Other; + VernAux.vna_name = DotDynstr.getOffset(VAuxE.Name); + if (J == VE.AuxV.size() - 1) + VernAux.vna_next = 0; + else + VernAux.vna_next = sizeof(Elf_Vernaux); + OS.write((const char *)&VernAux, sizeof(Elf_Vernaux)); + } + } + + SHeader.sh_size = Section.VerneedV.size() * sizeof(Elf_Verneed) + + AuxCnt * sizeof(Elf_Vernaux); + SHeader.sh_info = Section.Info; + + return true; +} + template bool ELFState::writeSectionContent(Elf_Shdr &SHeader, const ELFYAML::MipsABIFlags &Section, @@ -643,9 +690,52 @@ return true; } +template void ELFState::finalizeStrings() { + auto AddSymbols = [](StringTableBuilder &StrTab, + const ELFYAML::LocalGlobalWeakSymbols &Symbols) { + 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); + }; + + // Add the regular symbol names to .strtab section. + AddSymbols(DotStrtab, Doc.Symbols); + DotStrtab.finalize(); + + if (!hasDynamicSymbols()) + return; + + // Add the dynamic symbol names to .dynstr section. + AddSymbols(DotDynstr, Doc.DynamicSymbols); + + // SHT_GNU_verneed section also adds strings to .dynstr section. + for (const std::unique_ptr &Sec : Doc.Sections) { + auto VerNeed = dyn_cast(Sec.get()); + if (!VerNeed) + continue; + + for (const ELFYAML::VerneedEntry &VE : VerNeed->VerneedV) { + DotDynstr.add(VE.File); + for (const ELFYAML::VernauxEntry &Aux : VE.AuxV) + DotDynstr.add(Aux.Name); + } + } + + DotDynstr.finalize(); +} + template int ELFState::writeELF(raw_ostream &OS, const ELFYAML::Object &Doc) { ELFState State(Doc); + + // Finalize .strtab and .dynstr sections. We do that early because want to + // finalize the string table builders before writing the content of the + // sections that might want to use them. + State.finalizeStrings(); + if (!State.buildSectionIndex()) return 1;