Index: llvm/include/llvm/ObjectYAML/ELFYAML.h =================================================================== --- llvm/include/llvm/ObjectYAML/ELFYAML.h +++ llvm/include/llvm/ObjectYAML/ELFYAML.h @@ -64,6 +64,8 @@ LLVM_YAML_STRONG_TYPEDEF(uint32_t, MIPS_AFL_FLAGS1) LLVM_YAML_STRONG_TYPEDEF(uint32_t, MIPS_ISA) +LLVM_YAML_STRONG_TYPEDEF(StringRef, YAMLFlowString) + // For now, hardcode 64 bits everywhere that 32 or 64 would be needed // since 64-bit can hold 32-bit values too. struct FileHeader { @@ -149,6 +151,7 @@ Addrsig, Fill, LinkerOptions, + DependentLibraries, }; ChunkKind Kind; @@ -366,6 +369,17 @@ } }; +struct DependentLibrariesSection : Section { + Optional> Libs; + Optional Content; + + DependentLibrariesSection() : Section(ChunkKind::DependentLibraries) {} + + static bool classof(const Chunk *S) { + return S->Kind == ChunkKind::DependentLibraries; + } +}; + struct SymverSection : Section { std::vector Entries; Index: llvm/lib/ObjectYAML/ELFEmitter.cpp =================================================================== --- llvm/lib/ObjectYAML/ELFEmitter.cpp +++ llvm/lib/ObjectYAML/ELFEmitter.cpp @@ -203,6 +203,9 @@ void writeSectionContent(Elf_Shdr &SHeader, const ELFYAML::LinkerOptionsSection &Section, ContiguousBlobAccumulator &CBA); + void writeSectionContent(Elf_Shdr &SHeader, + const ELFYAML::DependentLibrariesSection &Section, + ContiguousBlobAccumulator &CBA); void writeFill(ELFYAML::Fill &Fill, ContiguousBlobAccumulator &CBA); @@ -475,6 +478,8 @@ writeSectionContent(SHeader, *S, CBA); } else if (auto S = dyn_cast(Sec)) { writeSectionContent(SHeader, *S, CBA); + } else if (auto S = dyn_cast(Sec)) { + writeSectionContent(SHeader, *S, CBA); } else { llvm_unreachable("Unknown section type"); } @@ -921,6 +926,28 @@ } } +template +void ELFState::writeSectionContent( + Elf_Shdr &SHeader, const ELFYAML::DependentLibrariesSection &Section, + ContiguousBlobAccumulator &CBA) { + raw_ostream &OS = + CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign); + + if (Section.Content) { + SHeader.sh_size = writeContent(OS, Section.Content, None); + return; + } + + if (!Section.Libs) + return; + + for (StringRef Lib : *Section.Libs) { + OS.write(Lib.data(), Lib.size()); + OS.write('\0'); + SHeader.sh_size += (Lib.size() + 1); + } +} + template void ELFState::writeSectionContent(Elf_Shdr &SHeader, const ELFYAML::HashSection &Section, Index: llvm/lib/ObjectYAML/ELFYAML.cpp =================================================================== --- llvm/lib/ObjectYAML/ELFYAML.cpp +++ llvm/lib/ObjectYAML/ELFYAML.cpp @@ -863,6 +863,24 @@ static const bool flow = true; }; +template <> struct ScalarTraits { + static void output(const ELFYAML::YAMLFlowString &Val, void *, + raw_ostream &Out) { + Out << Val; + } + static StringRef input(StringRef Scalar, void *, + ELFYAML::YAMLFlowString &Val) { + Val = Scalar; + return {}; + } + static QuotingType mustQuote(StringRef S) { + return ScalarTraits::mustQuote(S); + } +}; +template <> struct SequenceElementTraits { + static const bool flow = true; +}; + namespace { struct NormalizedOther { @@ -1106,6 +1124,13 @@ IO.mapOptional("Content", Section.Content); } +static void sectionMapping(IO &IO, + ELFYAML::DependentLibrariesSection &Section) { + commonSectionMapping(IO, Section); + IO.mapOptional("Libraries", Section.Libs); + IO.mapOptional("Content", Section.Content); +} + void MappingTraits::mapping( IO &IO, ELFYAML::SectionOrType §ionOrType) { IO.mapRequired("SectionOrType", sectionOrType.sectionNameOrType); @@ -1228,6 +1253,12 @@ Section.reset(new ELFYAML::LinkerOptionsSection()); sectionMapping(IO, *cast(Section.get())); break; + case ELF::SHT_LLVM_DEPENDENT_LIBRARIES: + if (!IO.outputting()) + Section.reset(new ELFYAML::DependentLibrariesSection()); + sectionMapping(IO, + *cast(Section.get())); + break; default: if (!IO.outputting()) { StringRef Name; @@ -1372,6 +1403,14 @@ return {}; } + if (const auto *Sec = dyn_cast(C.get())) { + if (Sec->Libs && Sec->Content) + return "SHT_LLVM_DEPENDENT_LIBRARIES: \"Libraries\" and \"Content\" " + "can't " + "be used together"; + return {}; + } + if (const auto *F = dyn_cast(C.get())) { if (!F->Pattern) return {}; Index: llvm/test/tools/obj2yaml/llvm-deplibs-section.yaml =================================================================== --- /dev/null +++ llvm/test/tools/obj2yaml/llvm-deplibs-section.yaml @@ -0,0 +1,42 @@ +## Check how obj2yaml produces SHT_LLVM_DEPENDENT_LIBRARIES section descriptions. + +# RUN: yaml2obj %s -o %t +# RUN: obj2yaml %t | FileCheck %s + +# CHECK: Sections: +# CHECK-NEXT: - Name: .deplibs.single +# CHECK-NEXT: Type: SHT_LLVM_DEPENDENT_LIBRARIES +# CHECK-NEXT: Libraries: [ foo ] +# CHECK-NEXT: - Name: .deplibs.multiple +# CHECK-NEXT: Type: SHT_LLVM_DEPENDENT_LIBRARIES +# CHECK-NEXT: Libraries: [ foo, bar, foo ] +# CHECK-NEXT: - Name: .deplibs.empty +# CHECK-NEXT: Type: SHT_LLVM_DEPENDENT_LIBRARIES +# CHECK-NEXT: Libraries: [ ] +# CHECK-NEXT: - Name: .deplibs.nonul +# CHECK-NEXT: Type: SHT_LLVM_DEPENDENT_LIBRARIES +# CHECK-NEXT: Content: 666F6F + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: +## Case 1: test we use "Libraries" to dump a valid section with a null-terminated string. + - Name: .deplibs.single + Type: SHT_LLVM_DEPENDENT_LIBRARIES + Libraries: [ foo ] +## Case 2: the same, but section now has multiple strings. + - Name: .deplibs.multiple + Type: SHT_LLVM_DEPENDENT_LIBRARIES + Libraries: [ foo, bar, foo ] +## Case 3: test we use "Libraries" to dump an empty section. + - Name: .deplibs.empty + Type: SHT_LLVM_DEPENDENT_LIBRARIES + Libraries: [ ] +## Case 4: test we use "Content" to dump a non-null terminated section. + - Name: .deplibs.nonul + Type: SHT_LLVM_DEPENDENT_LIBRARIES + Content: "666f6f" Index: llvm/test/tools/yaml2obj/ELF/llvm-deplibs-section.yaml =================================================================== --- /dev/null +++ llvm/test/tools/yaml2obj/ELF/llvm-deplibs-section.yaml @@ -0,0 +1,87 @@ +## Check how yaml2obj produces SHT_LLVM_DEPENDENT_LIBRARIES sections. + +## Check we can describe SHT_LLVM_DEPENDENT_LIBRARIES using +## "Libraries" and "Content" properies. + +# RUN: yaml2obj --docnum=1 %s -o %t1 +# RUN: llvm-readobj --sections --section-data %t1 | FileCheck %s --check-prefix=LIBRARIES + +# LIBRARIES: Name: .deplibs.lib +# LIBRARIES-NEXT: Type: SHT_LLVM_DEPENDENT_LIBRARIES (0x6FFF4C04) +# LIBRARIES-NEXT: Flags [ (0x0) +# LIBRARIES-NEXT: ] +# LIBRARIES-NEXT: Address: 0x0 +# LIBRARIES-NEXT: Offset: 0x40 +# LIBRARIES-NEXT: Size: 12 +# LIBRARIES-NEXT: Link: 0 +# LIBRARIES-NEXT: Info: 0 +# LIBRARIES-NEXT: AddressAlignment: 0 +# LIBRARIES-NEXT: EntrySize: 0 +# LIBRARIES-NEXT: SectionData ( +# LIBRARIES-NEXT: 0000: 666F6F00 62617200 666F6F00 |foo.bar.foo.| +# LIBRARIES-NEXT: ) + +# LIBRARIES: Name: .deplibs.content +# LIBRARIES-NEXT: Type: SHT_LLVM_DEPENDENT_LIBRARIES +# LIBRARIES-NEXT: Flags [ +# LIBRARIES-NEXT: ] +# LIBRARIES-NEXT: Address: 0x0 +# LIBRARIES-NEXT: Offset: 0x4C +# LIBRARIES-NEXT: Size: 3 +# LIBRARIES-NEXT: Link: 0 +# LIBRARIES-NEXT: Info: 0 +# LIBRARIES-NEXT: AddressAlignment: 0 +# LIBRARIES-NEXT: EntrySize: 0 +# LIBRARIES-NEXT: SectionData ( +# LIBRARIES-NEXT: 0000: 112233 +# LIBRARIES-NEXT: ) + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .deplibs.lib + Type: SHT_LLVM_DEPENDENT_LIBRARIES + Libraries: [ foo, bar, foo ] + - Name: .deplibs.content + Type: SHT_LLVM_DEPENDENT_LIBRARIES + Content: "112233" + +## Check we report an error when "Libraries" and "Content" are used together. + +# RUN: not yaml2obj --docnum=2 %s 2>&1 | FileCheck %s --check-prefix=LIBS-CONTENT + +# LIBS-CONTENT: error: SHT_LLVM_DEPENDENT_LIBRARIES: "Libraries" and "Content" can't be used together + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .deplibs + Type: SHT_LLVM_DEPENDENT_LIBRARIES + Libraries: [ foo ] + Content: "FF" + +## Check we create an empty section when neither "Libraries" nor "Content" are specified. + +# RUN: yaml2obj --docnum=3 %s -o %t3 +# RUN: llvm-readelf --sections %t3 | FileCheck %s --check-prefix=NOPROPS + +# NOPROPS: [Nr] Name Type Address Off Size +# NOPROPS: [ 1] .deplibs LLVM_DEPENDENT_LIBRARIES 0000000000000000 000040 000000 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .deplibs + Type: SHT_LLVM_DEPENDENT_LIBRARIES Index: llvm/tools/obj2yaml/elf2yaml.cpp =================================================================== --- llvm/tools/obj2yaml/elf2yaml.cpp +++ llvm/tools/obj2yaml/elf2yaml.cpp @@ -62,6 +62,8 @@ Expected dumpAddrsigSection(const Elf_Shdr *Shdr); Expected dumpLinkerOptionsSection(const Elf_Shdr *Shdr); + Expected + dumpDependentLibrariesSection(const Elf_Shdr *Shdr); Expected dumpDynamicSection(const Elf_Shdr *Shdr); Expected dumpRelocSection(const Elf_Shdr *Shdr); Expected @@ -325,6 +327,14 @@ Y->Chunks.emplace_back(*SecOrErr); break; } + case ELF::SHT_LLVM_DEPENDENT_LIBRARIES: { + Expected SecOrErr = + dumpDependentLibrariesSection(&Sec); + if (!SecOrErr) + return SecOrErr.takeError(); + Y->Chunks.emplace_back(*SecOrErr); + break; + } case ELF::SHT_NULL: { // We only dump the SHT_NULL section at index 0 when it // has at least one non-null field, because yaml2obj @@ -629,6 +639,33 @@ return S.release(); } +template +Expected +ELFDumper::dumpDependentLibrariesSection(const Elf_Shdr *Shdr) { + auto DL = std::make_unique(); + if (Error E = dumpCommonSection(Shdr, *DL)) + return std::move(E); + + Expected> ContentOrErr = Obj.getSectionContents(Shdr); + if (!ContentOrErr) + return ContentOrErr.takeError(); + + ArrayRef Content = *ContentOrErr; + if (!Content.empty() && Content.back() != 0) { + DL->Content = Content; + return DL.release(); + } + + DL->Libs.emplace(); + for (const uint8_t *I = Content.begin(), *E = Content.end(); I < E;) { + StringRef Lib((const char *)(I)); + DL->Libs->emplace_back(Lib); + I += Lib.size() + 1; + } + + return DL.release(); +} + template Expected ELFDumper::dumpDynamicSection(const Elf_Shdr *Shdr) {