Index: llvm/include/llvm/ObjectYAML/ELFYAML.h =================================================================== --- llvm/include/llvm/ObjectYAML/ELFYAML.h +++ llvm/include/llvm/ObjectYAML/ELFYAML.h @@ -146,7 +146,8 @@ SymtabShndxSection, Symver, MipsABIFlags, - Addrsig + Addrsig, + LinkerOptions }; SectionKind Kind; StringRef Name; @@ -327,6 +328,24 @@ } }; +struct LinkerOption { + LinkerOption(StringRef K, StringRef V) : Key(K), Value(V) {} + LinkerOption() = default; + StringRef Key; + StringRef Value; +}; + +struct LinkerOptionsSection : Section { + Optional> Options; + Optional Content; + + LinkerOptionsSection() : Section(SectionKind::LinkerOptions) {} + + static bool classof(const Section *S) { + return S->Kind == SectionKind::LinkerOptions; + } +}; + struct SymverSection : Section { std::vector Entries; @@ -436,6 +455,7 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::AddrsigSymbol) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::StackSizeEntry) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::DynamicEntry) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::LinkerOption) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::NoteEntry) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::ProgramHeader) LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr) @@ -603,6 +623,10 @@ static void mapping(IO &IO, ELFYAML::AddrsigSymbol &Sym); }; +template <> struct MappingTraits { + static void mapping(IO &IO, ELFYAML::LinkerOption &Sym); +}; + template <> struct MappingTraits { static void mapping(IO &IO, ELFYAML::Relocation &Rel); }; Index: llvm/lib/ObjectYAML/ELFEmitter.cpp =================================================================== --- llvm/lib/ObjectYAML/ELFEmitter.cpp +++ llvm/lib/ObjectYAML/ELFEmitter.cpp @@ -185,6 +185,9 @@ void writeSectionContent(Elf_Shdr &SHeader, const ELFYAML::GnuHashSection &Section, ContiguousBlobAccumulator &CBA); + void writeSectionContent(Elf_Shdr &SHeader, + const ELFYAML::LinkerOptionsSection &Section, + ContiguousBlobAccumulator &CBA); ELFState(ELFYAML::Object &D, yaml::ErrorHandler EH); @@ -441,6 +444,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 if (auto S = dyn_cast(Sec)) { writeSectionContent(SHeader, *S, CBA); } else if (auto S = dyn_cast(Sec)) { @@ -846,6 +851,27 @@ } } +template +void ELFState::writeSectionContent( + Elf_Shdr &SHeader, const ELFYAML::LinkerOptionsSection &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; + } + + for (const ELFYAML::LinkerOption &LO : *Section.Options) { + OS.write(LO.Key.data(), LO.Key.size()); + OS.write('\0'); + OS.write(LO.Value.data(), LO.Value.size()); + OS.write('\0'); + SHeader.sh_size += (LO.Key.size() + LO.Value.size() + 2); + } +} + 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 @@ -1094,6 +1094,12 @@ IO.mapOptional("Symbols", Section.Symbols); } +static void sectionMapping(IO &IO, ELFYAML::LinkerOptionsSection &Section) { + commonSectionMapping(IO, Section); + IO.mapOptional("Options", Section.Options); + IO.mapOptional("Content", Section.Content); +} + void MappingTraits::mapping( IO &IO, ELFYAML::SectionOrType §ionOrType) { IO.mapRequired("SectionOrType", sectionOrType.sectionNameOrType); @@ -1199,6 +1205,11 @@ Section.reset(new ELFYAML::AddrsigSection()); sectionMapping(IO, *cast(Section.get())); break; + case ELF::SHT_LLVM_LINKER_OPTIONS: + if (!IO.outputting()) + Section.reset(new ELFYAML::LinkerOptionsSection()); + sectionMapping(IO, *cast(Section.get())); + break; default: if (!IO.outputting()) { StringRef Name; @@ -1337,6 +1348,15 @@ return {}; } + if (const auto *Sec = + dyn_cast(Section.get())) { + if (!Sec->Options && !Sec->Content) + return "either \"Options\" or \"Content\" must be specified"; + if (Sec->Options && Sec->Content) + return "\"Options\" and \"Content\" can't be used together"; + return {}; + } + return {}; } @@ -1467,6 +1487,13 @@ IO.mapOptional("Index", Sym.Index); } +void MappingTraits::mapping(IO &IO, + ELFYAML::LinkerOption &Opt) { + assert(IO.getContext() && "The IO context is not initialized"); + IO.mapRequired("Name", Opt.Key); + IO.mapRequired("Value", Opt.Value); +} + LLVM_YAML_STRONG_TYPEDEF(uint8_t, MIPS_AFL_REG) LLVM_YAML_STRONG_TYPEDEF(uint8_t, MIPS_ABI_FP) LLVM_YAML_STRONG_TYPEDEF(uint32_t, MIPS_AFL_EXT) Index: llvm/test/tools/llvm-readobj/elf-section-types.test =================================================================== --- llvm/test/tools/llvm-readobj/elf-section-types.test +++ llvm/test/tools/llvm-readobj/elf-section-types.test @@ -193,6 +193,7 @@ Type: SHT_LLVM_ODRTAB - Name: linker_options Type: SHT_LLVM_LINKER_OPTIONS + Content: "" - Name: llvm_call_graph_profile Type: SHT_LLVM_CALL_GRAPH_PROFILE - Name: llvm_addrsig Index: llvm/test/tools/obj2yaml/linker-options.yaml =================================================================== --- /dev/null +++ llvm/test/tools/obj2yaml/linker-options.yaml @@ -0,0 +1,69 @@ +## Check how obj2yaml produces SHT_LLVM_LINKER_OPTIONS sections descriptions. + +## Check we dump valid sections using pairs of "Name" and "Value" strings. + +# RUN: yaml2obj --docnum=1 %s -o %t1 +# RUN: obj2yaml %t1 | FileCheck %s --check-prefix=VALID + +# VALID: - Name: .linker-options-valid1 +# VALID-NEXT: Type: SHT_LLVM_LINKER_OPTIONS +# VALID-NEXT: Options: +# VALID-NEXT: - Name: a +# VALID-NEXT: Value: b +# VALID-NEXT: - Name: .linker-options-valid2 +# VALID-NEXT: Type: SHT_LLVM_LINKER_OPTIONS +# VALID-NEXT: Options: +# VALID-NEXT: - Name: a +# VALID-NEXT: Value: b +# VALID-NEXT: - Name: c +# VALID-NEXT: Value: d + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .linker-options-valid1 + Type: SHT_LLVM_LINKER_OPTIONS + Content: "61006200" + - Name: .linker-options-valid2 + Type: SHT_LLVM_LINKER_OPTIONS + Content: "6100620063006400" + +## Check we dump corrupted sections using "Content" key. + +# RUN: yaml2obj --docnum=2 %s -o %t2 +# RUN: obj2yaml %t2 | FileCheck %s --check-prefix=CORRUPTED + +# CORRUPTED: - Name: .linker-options-empty +# CORRUPTED-NEXT: Type: SHT_LLVM_LINKER_OPTIONS +# CORRUPTED-NEXT: Content: '' +# CORRUPTED-NEXT: - Name: .linker-options-no-null +# CORRUPTED-NEXT: Type: SHT_LLVM_LINKER_OPTIONS +# CORRUPTED-NEXT: Content: '61' +# CORRUPTED-NEXT: - Name: .linker-options-incomplete +# CORRUPTED-NEXT: Type: SHT_LLVM_LINKER_OPTIONS +# CORRUPTED-NEXT: Content: '6100' + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: +## 1) Empty content. + - Name: .linker-options-empty + Type: SHT_LLVM_LINKER_OPTIONS + Content: "" +## 2) Non-null terminated content. + - Name: .linker-options-no-null + Type: SHT_LLVM_LINKER_OPTIONS + Content: "61" +## 2) Odd number of strings in the section. +## (Hence it contains incomplete key-value pair). + - Name: .linker-options-incomplete + Type: SHT_LLVM_LINKER_OPTIONS + Content: "6100" Index: llvm/test/tools/yaml2obj/linker-options.yaml =================================================================== --- /dev/null +++ llvm/test/tools/yaml2obj/linker-options.yaml @@ -0,0 +1,117 @@ +## Check we are able to produce a valid SHT_LLVM_LINKER_OPTIONS +## section from its description. + +## Check we can use either "Options" or "Content" to describe the data. + +# RUN: yaml2obj --docnum=1 %s -o %t1 +# RUN: llvm-readobj --sections --section-data %t1 | FileCheck %s --check-prefix=OPTIONS + +# OPTIONS: Name: .linker-options1 +# OPTIONS-NEXT: Type: SHT_LLVM_LINKER_OPTIONS +# OPTIONS-NEXT: Flags [ +# OPTIONS-NEXT: ] +# OPTIONS-NEXT: Address: 0x0 +# OPTIONS-NEXT: Offset: 0x40 +# OPTIONS-NEXT: Size: 34 +# OPTIONS-NEXT: Link: 0 +# OPTIONS-NEXT: Info: 0 +# OPTIONS-NEXT: AddressAlignment: 0 +# OPTIONS-NEXT: EntrySize: 0 +# OPTIONS-NEXT: SectionData ( +# OPTIONS-NEXT: 0000: 6F707469 6F6E2030 0076616C 75652030 | +# OPTIONS-NEXT: 0010: 006F7074 696F6E20 31007661 6C756520 | +# OPTIONS-NEXT: 0020: 3100 | +# OPTIONS-NEXT: ) +# OPTIONS-NEXT: } + +# OPTIONS: Name: .linker-options2 +# OPTIONS-NEXT: Type: SHT_LLVM_LINKER_OPTIONS +# OPTIONS: SectionData ( +# OPTIONS-NEXT: 0000: 00112233 | +# OPTIONS-NEXT: ) + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .linker-options1 + Type: SHT_LLVM_LINKER_OPTIONS + Options: + - Name: option 0 + Value: value 0 + - Name: option 1 + Value: value 1 + - Name: .linker-options2 + Type: SHT_LLVM_LINKER_OPTIONS + Content: "00112233" + +## Check that "Value" and "Name" fields are mandatory when using "Options" key. + +# RUN: not yaml2obj --docnum=2 %s 2>&1 | FileCheck %s --check-prefix=NOVALUE +# RUN: not yaml2obj --docnum=3 %s 2>&1 | FileCheck %s --check-prefix=NONAME + +# NOVALUE: error: missing required key 'Value' +# NONAME: error: missing required key 'Name' + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .linker-options + Type: SHT_LLVM_LINKER_OPTIONS + Options: + - Name: name + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .linker-options + Type: SHT_LLVM_LINKER_OPTIONS + Options: + - Value: value + +## Check we can't use both "Options" and "Content" together. + +# RUN: not yaml2obj %s --docnum=4 2>&1 | FileCheck %s --check-prefix=BOTH + +# BOTH: error: "Options" and "Content" can't be used together + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .linker-options + Type: SHT_LLVM_LINKER_OPTIONS + Options: + - Name: name + Value: value + Content: "00112233" + +## Check we should specify either "Options" or "Content". + +# RUN: not yaml2obj %s --docnum=5 2>&1 | FileCheck %s --check-prefix=ONEOF + +# ONEOF: error: either "Options" or "Content" must be specified + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .linker-options + Type: SHT_LLVM_LINKER_OPTIONS Index: llvm/tools/obj2yaml/elf2yaml.cpp =================================================================== --- llvm/tools/obj2yaml/elf2yaml.cpp +++ llvm/tools/obj2yaml/elf2yaml.cpp @@ -60,6 +60,8 @@ ELFYAML::Relocation &R); Expected dumpAddrsigSection(const Elf_Shdr *Shdr); + Expected + dumpLinkerOptionsSection(const Elf_Shdr *Shdr); Expected dumpDynamicSection(const Elf_Shdr *Shdr); Expected dumpRelocSection(const Elf_Shdr *Shdr); Expected @@ -315,6 +317,14 @@ Y->Sections.emplace_back(*SecOrErr); break; } + case ELF::SHT_LLVM_LINKER_OPTIONS: { + Expected SecOrErr = + dumpLinkerOptionsSection(&Sec); + if (!SecOrErr) + return SecOrErr.takeError(); + Y->Sections.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 @@ -588,6 +598,37 @@ return S.release(); } +template +Expected +ELFDumper::dumpLinkerOptionsSection(const Elf_Shdr *Shdr) { + auto S = std::make_unique(); + if (Error E = dumpCommonSection(Shdr, *S)) + return std::move(E); + + auto ContentOrErr = Obj.getSectionContents(Shdr); + if (!ContentOrErr) + return ContentOrErr.takeError(); + + ArrayRef Content = *ContentOrErr; + if (Content.empty() || Content.back() != 0) { + S->Content = Content; + return S.release(); + } + + SmallVector Strings; + toStringRef(Content.drop_back()).split(Strings, '\0'); + if (Strings.size() % 2 != 0) { + S->Content = Content; + return S.release(); + } + + S->Options = std::vector(); + for (size_t I = 0; I != Strings.size(); I += 2) + S->Options->emplace_back(Strings[I], Strings[I + 1]); + + return S.release(); +} + template Expected ELFDumper::dumpDynamicSection(const Elf_Shdr *Shdr) {