Index: llvm/include/llvm/ObjectYAML/ELFYAML.h =================================================================== --- llvm/include/llvm/ObjectYAML/ELFYAML.h +++ llvm/include/llvm/ObjectYAML/ELFYAML.h @@ -324,7 +324,8 @@ }; struct VerneedSection : Section { - std::vector VerneedV; + Optional Content; + Optional> VerneedV; llvm::yaml::Hex64 Info; VerneedSection() : Section(ChunkKind::Verneed) {} Index: llvm/lib/ObjectYAML/ELFEmitter.cpp =================================================================== --- llvm/lib/ObjectYAML/ELFEmitter.cpp +++ llvm/lib/ObjectYAML/ELFEmitter.cpp @@ -1036,15 +1036,24 @@ typedef typename ELFT::Vernaux Elf_Vernaux; auto &OS = CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign); + SHeader.sh_info = Section.Info; + + if (Section.Content) { + SHeader.sh_size = writeContent(OS, Section.Content, None); + return; + } + + if (!Section.VerneedV) + return; uint64_t AuxCnt = 0; - for (size_t I = 0; I < Section.VerneedV.size(); ++I) { - const ELFYAML::VerneedEntry &VE = Section.VerneedV[I]; + 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) + if (I == Section.VerneedV->size() - 1) VerNeed.vn_next = 0; else VerNeed.vn_next = @@ -1069,9 +1078,8 @@ } } - SHeader.sh_size = Section.VerneedV.size() * sizeof(Elf_Verneed) + + SHeader.sh_size = Section.VerneedV->size() * sizeof(Elf_Verneed) + AuxCnt * sizeof(Elf_Vernaux); - SHeader.sh_info = Section.Info; } template @@ -1344,10 +1352,12 @@ // add strings to .dynstr section. for (const ELFYAML::Chunk *Sec : Doc.getSections()) { if (auto VerNeed = dyn_cast(Sec)) { - for (const ELFYAML::VerneedEntry &VE : VerNeed->VerneedV) { - DotDynstr.add(VE.File); - for (const ELFYAML::VernauxEntry &Aux : VE.AuxV) - DotDynstr.add(Aux.Name); + if (VerNeed->VerneedV) { + 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)) { if (VerDef->Entries) Index: llvm/lib/ObjectYAML/ELFYAML.cpp =================================================================== --- llvm/lib/ObjectYAML/ELFYAML.cpp +++ llvm/lib/ObjectYAML/ELFYAML.cpp @@ -1086,7 +1086,8 @@ static void sectionMapping(IO &IO, ELFYAML::VerneedSection &Section) { commonSectionMapping(IO, Section); IO.mapRequired("Info", Section.Info); - IO.mapRequired("Dependencies", Section.VerneedV); + IO.mapOptional("Dependencies", Section.VerneedV); + IO.mapOptional("Content", Section.Content); } static void sectionMapping(IO &IO, ELFYAML::RelocationSection &Section) { @@ -1427,6 +1428,13 @@ return {}; } + if (const auto *VD = dyn_cast(C.get())) { + if (VD->VerneedV && VD->Content) + return "SHT_GNU_verneed: \"Dependencies\" and \"Content\" can't be used " + "together"; + return {}; + } + return {}; } Index: llvm/test/tools/yaml2obj/ELF/verneed-section.yaml =================================================================== --- llvm/test/tools/yaml2obj/ELF/verneed-section.yaml +++ llvm/test/tools/yaml2obj/ELF/verneed-section.yaml @@ -1,7 +1,7 @@ ## Check we are able to handle SHT_GNU_verneed sections. -# RUN: yaml2obj %s -o %t -# RUN: llvm-readobj -V %t | FileCheck %s +# RUN: yaml2obj --docnum=1 %s -o %t1 +# RUN: llvm-readobj -V %t1 | FileCheck %s # CHECK: VersionRequirements [ # CHECK-NEXT: Dependency { @@ -82,3 +82,77 @@ DynamicSymbols: - Name: f1 Binding: STB_GLOBAL + +## Check we can use "Content" to describe the content. + +# RUN: yaml2obj --docnum=2 %s -o %t2 +# RUN: llvm-readobj --sections --section-data %t2 | FileCheck %s --check-prefix=CONTENT + +# CONTENT: Name: .gnu.version_r +# CONTENT-NEXT: Type: SHT_GNU_verneed +# CONTENT-NEXT: Flags [ (0x2) +# CONTENT-NEXT: SHF_ALLOC (0x2) +# CONTENT-NEXT: ] +# CONTENT-NEXT: Address: 0x0 +# CONTENT-NEXT: Offset: 0x40 +# CONTENT-NEXT: Size: 3 +# CONTENT-NEXT: Link: 0 +# CONTENT-NEXT: Info: 1 +# CONTENT-NEXT: AddressAlignment: 0 +# CONTENT-NEXT: EntrySize: 0 +# CONTENT-NEXT: SectionData ( +# CONTENT-NEXT: 0000: 112233 +# CONTENT-NEXT: ) + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .gnu.version_r + Type: SHT_GNU_verneed + Flags: [ SHF_ALLOC ] + Info: 0x1 + Content: "112233" + +## Check we can omit "Content" and "Dependencies" fields to produce an empty SHT_GNU_verneed section. + +# RUN: yaml2obj --docnum=3 %s -o %t3 +# RUN: llvm-readelf --sections %t3 | FileCheck %s --check-prefix=NO-PROPS + +# NO-PROPS: [Nr] Name Type Address Off Size +# NO-PROPS: [ 1] .gnu.version_r VERNEED 0000000000000000 000040 000000 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .gnu.version_r + Type: SHT_GNU_verneed + Flags: [ SHF_ALLOC ] + Info: 0x0 + +## Check we can't use both "Dependencies" and "Content" together. + +# RUN: not yaml2obj --docnum=4 %s 2>&1 | FileCheck %s --check-prefix=BOTH + +# BOTH: error: SHT_GNU_verneed: "Dependencies" and "Content" can't be used together + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .gnu.version_r + Type: SHT_GNU_verneed + Flags: [ SHF_ALLOC ] + Info: 0x0 + Content: "" + Dependencies: [] Index: llvm/tools/obj2yaml/elf2yaml.cpp =================================================================== --- llvm/tools/obj2yaml/elf2yaml.cpp +++ llvm/tools/obj2yaml/elf2yaml.cpp @@ -993,6 +993,8 @@ if (!StringTableOrErr) return StringTableOrErr.takeError(); + S->VerneedV.emplace(); + llvm::ArrayRef Data = *Contents; const uint8_t *Buf = Data.data(); while (Buf) { @@ -1019,7 +1021,7 @@ BufAux = Vernaux->vna_next ? BufAux + Vernaux->vna_next : nullptr; } - S->VerneedV.push_back(Entry); + S->VerneedV->push_back(Entry); Buf = Verneed->vn_next ? Buf + Verneed->vn_next : nullptr; }