Index: include/llvm/ObjectYAML/ELFYAML.h =================================================================== --- include/llvm/ObjectYAML/ELFYAML.h +++ include/llvm/ObjectYAML/ELFYAML.h @@ -121,6 +121,7 @@ RawContent, Relocation, NoBits, + Verdef, Verneed, Symver, MipsABIFlags @@ -203,6 +204,25 @@ } }; +struct VerdefEntry { + uint16_t Version; + uint16_t Flags; + uint16_t VersionNdx; + uint32_t Hash; + std::vector VerNames; +}; + +struct VerdefSection : Section { + std::vector Entries; + llvm::yaml::Hex64 Info; + + VerdefSection() : Section(SectionKind::Verdef) {} + + static bool classof(const Section *S) { + return S->Kind == SectionKind::Verdef; + } +}; + struct Group : Section { // Members of a group contain a flag and a list of section indices // that are part of the group. @@ -274,6 +294,7 @@ 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::VerdefEntry) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::VernauxEntry) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::VerneedEntry) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::Relocation) @@ -419,6 +440,10 @@ static void mapping(IO &IO, ELFYAML::DynamicEntry &Rel); }; +template <> struct MappingTraits { + static void mapping(IO &IO, ELFYAML::VerdefEntry &E); +}; + template <> struct MappingTraits { static void mapping(IO &IO, ELFYAML::VerneedEntry &E); }; Index: lib/ObjectYAML/ELFYAML.cpp =================================================================== --- lib/ObjectYAML/ELFYAML.cpp +++ lib/ObjectYAML/ELFYAML.cpp @@ -870,6 +870,12 @@ IO.mapOptional("Size", Section.Size, Hex64(0)); } +static void sectionMapping(IO &IO, ELFYAML::VerdefSection &Section) { + commonSectionMapping(IO, Section); + IO.mapRequired("Info", Section.Info); + IO.mapRequired("Entries", Section.Entries); +} + static void sectionMapping(IO &IO, ELFYAML::SymverSection &Section) { commonSectionMapping(IO, Section); IO.mapRequired("Entries", Section.Entries); @@ -958,6 +964,11 @@ Section.reset(new ELFYAML::MipsABIFlags()); sectionMapping(IO, *cast(Section.get())); break; + case ELF::SHT_GNU_verdef: + if (!IO.outputting()) + Section.reset(new ELFYAML::VerdefSection()); + sectionMapping(IO, *cast(Section.get())); + break; case ELF::SHT_GNU_versym: if (!IO.outputting()) Section.reset(new ELFYAML::SymverSection()); @@ -1016,6 +1027,17 @@ IO.mapRequired("Value", Rel.Val); } +void MappingTraits::mapping(IO &IO, + ELFYAML::VerdefEntry &E) { + assert(IO.getContext() && "The IO context is not initialized"); + + IO.mapRequired("Version", E.Version); + IO.mapRequired("Flags", E.Flags); + IO.mapRequired("VersionNdx", E.VersionNdx); + IO.mapRequired("Hash", E.Hash); + IO.mapRequired("Names", E.VerNames); +} + void MappingTraits::mapping(IO &IO, ELFYAML::VerneedEntry &E) { assert(IO.getContext() && "The IO context is not initialized"); Index: test/tools/obj2yaml/verdef-section.yaml =================================================================== --- /dev/null +++ test/tools/obj2yaml/verdef-section.yaml @@ -0,0 +1,72 @@ +# RUN: yaml2obj %s -o %t +# RUN: obj2yaml %t | FileCheck %s + +## Check we are able to yamalize SHT_GNU_verdef section. + +# CHECK: - Name: .gnu.version_d +# CHECK-NEXT: Type: SHT_GNU_verdef +# CHECK-NEXT: Flags: [ SHF_ALLOC ] +# CHECK-NEXT: Address: 0x0000000000000230 +# CHECK-NEXT: Link: .dynstr +# CHECK-NEXT: AddressAlign: 0x0000000000000004 +# CHECK-NEXT: Info: 0x0000000000000004 +# CHECK-NEXT: Entries: +# CHECK-NEXT: - Version: 1 +# CHECK-NEXT: Flags: 1 +# CHECK-NEXT: VersionNdx: 1 +# CHECK-NEXT: Hash: 170240160 +# CHECK-NEXT: Names: +# CHECK-NEXT: - dso.so.0 +# CHECK-NEXT: - Version: 1 +# CHECK-NEXT: Flags: 2 +# CHECK-NEXT: VersionNdx: 2 +# CHECK-NEXT: Hash: 108387921 +# CHECK-NEXT: Names: +# CHECK-NEXT: - VERSION_1 +# CHECK-NEXT: - Version: 1 +# CHECK-NEXT: Flags: 3 +# CHECK-NEXT: VersionNdx: 3 +# CHECK-NEXT: Hash: 108387922 +# CHECK-NEXT: Names: +# CHECK-NEXT: - VERSION_2 +# CHECK-NEXT: - VERSION_3 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 + Entry: 0x0000000000001000 +Sections: + - Name: .gnu.version_d + Type: SHT_GNU_verdef + Flags: [ SHF_ALLOC ] + Address: 0x0000000000000230 + Link: .dynstr + AddressAlign: 0x0000000000000004 + Info: 0x0000000000000004 + Entries: + - Version: 1 + Flags: 1 + VersionNdx: 1 + Hash: 170240160 + Names: + - dso.so.0 + - Version: 1 + Flags: 2 + VersionNdx: 2 + Hash: 108387921 + Names: + - VERSION_1 + - Version: 1 + Flags: 3 + VersionNdx: 3 + Hash: 108387922 + Names: + - VERSION_2 + - VERSION_3 +DynamicSymbols: + Global: + - Name: foo +... Index: test/tools/yaml2obj/verdef-section.yaml =================================================================== --- /dev/null +++ test/tools/yaml2obj/verdef-section.yaml @@ -0,0 +1,69 @@ +# RUN: yaml2obj %s -o %t +# RUN: llvm-readelf -V %t | FileCheck %s + +# Check we are able to handle the SHT_GNU_verdef sections. + +# CHECK: SHT_GNU_verdef { +# CHECK-NEXT: Definition { +# CHECK-NEXT: Version: 1 +# CHECK-NEXT: Flags: Base +# CHECK-NEXT: Index: 1 +# CHECK-NEXT: Hash: 170240160 +# CHECK-NEXT: Name: dso.so.0 +# CHECK-NEXT: } +# CHECK-NEXT: Definition { +# CHECK-NEXT: Version: 1 +# CHECK-NEXT: Flags: Weak +# CHECK-NEXT: Index: 2 +# CHECK-NEXT: Hash: 108387921 +# CHECK-NEXT: Name: VERSION_1 +# CHECK-NEXT: } +# CHECK-NEXT: Definition { +# CHECK-NEXT: Version: 1 +# CHECK-NEXT: Flags: 0x3 +# CHECK-NEXT: Index: 3 +# CHECK-NEXT: Hash: 108387922 +# CHECK-NEXT: Name: VERSION_2 +# CHECK-NEXT: Predecessor: VERSION_3 +# CHECK-NEXT: } +# CHECK-NEXT: } + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 + Entry: 0x0000000000001000 +Sections: + - Name: .gnu.version_d + Type: SHT_GNU_verdef + Flags: [ SHF_ALLOC ] + Address: 0x0000000000000230 + Link: .dynstr + AddressAlign: 0x0000000000000004 + Info: 0x0000000000000003 + Entries: + - Version: 1 + Flags: 1 + VersionNdx: 1 + Hash: 170240160 + Names: + - dso.so.0 + - Version: 1 + Flags: 2 + VersionNdx: 2 + Hash: 108387921 + Names: + - VERSION_1 + - Version: 1 + Flags: 3 + VersionNdx: 3 + Hash: 108387922 + Names: + - VERSION_2 + - VERSION_3 +DynamicSymbols: + Global: + - Name: foo +... 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 dumpVerdefSection(const Elf_Shdr *Shdr); ErrorOr dumpSymverSection(const Elf_Shdr *Shdr); ErrorOr dumpVerneedSection(const Elf_Shdr *Shdr); ErrorOr dumpGroup(const Elf_Shdr *Shdr); @@ -186,6 +187,13 @@ Y->Sections.push_back(std::unique_ptr(S.get())); break; } + case ELF::SHT_GNU_verdef: { + ErrorOr S = dumpVerdefSection(&Sec); + if (std::error_code EC = S.getError()) + return EC; + Y->Sections.push_back(std::unique_ptr(S.get())); + break; + } case ELF::SHT_GNU_versym: { ErrorOr S = dumpSymverSection(&Sec); if (std::error_code EC = S.getError()) @@ -459,6 +467,56 @@ return S.release(); } +template +ErrorOr +ELFDumper::dumpVerdefSection(const Elf_Shdr *Shdr) { + typedef typename ELFT::Verdef Elf_Verdef; + typedef typename ELFT::Verdaux Elf_Verdaux; + + auto S = make_unique(); + if (std::error_code EC = dumpCommonSection(Shdr, *S)) + return EC; + + S->Info = Shdr->sh_info; + + auto StringTableShdrOrErr = Obj.getSection(Shdr->sh_link); + if (!StringTableShdrOrErr) + return errorToErrorCode(StringTableShdrOrErr.takeError()); + + auto StringTableOrErr = Obj.getStringTable(*StringTableShdrOrErr); + if (!StringTableOrErr) + return errorToErrorCode(StringTableOrErr.takeError()); + + auto Contents = Obj.getSectionContents(Shdr); + if (!Contents) + return errorToErrorCode(Contents.takeError()); + + llvm::ArrayRef Data = *Contents; + const uint8_t *Buf = Data.data(); + while (Buf) { + const Elf_Verdef *Verdef = reinterpret_cast(Buf); + ELFYAML::VerdefEntry Entry; + Entry.Version = Verdef->vd_version; + Entry.Flags = Verdef->vd_flags; + Entry.VersionNdx = Verdef->vd_ndx; + Entry.Hash = Verdef->vd_hash; + + const uint8_t *BufAux = Buf + Verdef->vd_aux; + while (BufAux) { + const Elf_Verdaux *Verdaux = + reinterpret_cast(BufAux); + Entry.VerNames.push_back( + StringTableOrErr->drop_front(Verdaux->vda_name).data()); + BufAux = Verdaux->vda_next ? BufAux + Verdaux->vda_next : nullptr; + } + + S->Entries.push_back(Entry); + Buf = Verdef->vd_next ? Buf + Verdef->vd_next : nullptr; + } + + return S.release(); +} + template ErrorOr ELFDumper::dumpSymverSection(const Elf_Shdr *Shdr) { Index: tools/yaml2obj/yaml2elf.cpp =================================================================== --- tools/yaml2obj/yaml2elf.cpp +++ tools/yaml2obj/yaml2elf.cpp @@ -162,6 +162,9 @@ bool writeSectionContent(Elf_Shdr &SHeader, const ELFYAML::VerneedSection &Section, ContiguousBlobAccumulator &CBA); + bool writeSectionContent(Elf_Shdr &SHeader, + const ELFYAML::VerdefSection &Section, + ContiguousBlobAccumulator &CBA); bool writeSectionContent(Elf_Shdr &SHeader, const ELFYAML::MipsABIFlags &Section, ContiguousBlobAccumulator &CBA); @@ -310,6 +313,8 @@ writeSectionContent(SHeader, *S, CBA); } 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"); @@ -590,6 +595,51 @@ return true; } +template +bool ELFState::writeSectionContent(Elf_Shdr &SHeader, + const ELFYAML::VerdefSection &Section, + ContiguousBlobAccumulator &CBA) { + typedef typename ELFT::Verdef Elf_Verdef; + typedef typename ELFT::Verdaux Elf_Verdaux; + raw_ostream &OS = + CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign); + + uint64_t AuxCnt = 0; + for (size_t I = 0; I < Section.Entries.size(); ++I) { + const ELFYAML::VerdefEntry &E = Section.Entries[I]; + + Elf_Verdef VerDef; + VerDef.vd_version = E.Version; + VerDef.vd_flags = E.Flags; + VerDef.vd_ndx = E.VersionNdx; + VerDef.vd_hash = E.Hash; + VerDef.vd_aux = sizeof(Elf_Verdef); + VerDef.vd_cnt = E.VerNames.size(); + if (I == Section.Entries.size() - 1) + VerDef.vd_next = 0; + else + VerDef.vd_next = + sizeof(Elf_Verdef) + E.VerNames.size() * sizeof(Elf_Verdaux); + OS.write((const char *)&VerDef, sizeof(Elf_Verdef)); + + for (size_t J = 0; J < E.VerNames.size(); ++J, ++AuxCnt) { + Elf_Verdaux VernAux; + VernAux.vda_name = DotDynstr.getOffset(E.VerNames[J]); + if (J == E.VerNames.size() - 1) + VernAux.vda_next = 0; + else + VernAux.vda_next = sizeof(Elf_Verdaux); + OS.write((const char *)&VernAux, sizeof(Elf_Verdaux)); + } + } + + SHeader.sh_size = Section.Entries.size() * sizeof(Elf_Verdef) + + AuxCnt * sizeof(Elf_Verdaux); + SHeader.sh_info = Section.Info; + + return true; +} + template bool ELFState::writeSectionContent(Elf_Shdr &SHeader, const ELFYAML::VerneedSection &Section, @@ -752,16 +802,19 @@ // Add the dynamic symbol names to .dynstr section. AddSymbols(DotDynstr, Doc.DynamicSymbols); - // SHT_GNU_verneed section also adds strings to .dynstr section. + // SHT_GNU_verdef and SHT_GNU_verneed sections might also + // add 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); + if (auto VerNeed = dyn_cast(Sec.get())) { + for (const ELFYAML::VerneedEntry &VE : VerNeed->VerneedV) { + DotDynstr.add(VE.File); + for (const ELFYAML::VernauxEntry &Aux : VE.AuxV) + DotDynstr.add(Aux.Name); + } + } else if (auto VerDef = dyn_cast(Sec.get())) { + for (const ELFYAML::VerdefEntry &E : VerDef->Entries) + for (StringRef Name : E.VerNames) + DotDynstr.add(Name); } }