SHT_LLVM_LINKER_OPTIONS section contains pairs of null-terminated strings.
This patch adds support for them.
Differential revision: https://reviews.llvm.org/D69895
Symver,
MipsABIFlags,
Addrsig,
- Fill
+ Fill,
+ LinkerOptions,
};
ChunkKind Kind;
static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Addrsig; }
};
+struct LinkerOption {
+ StringRef Key;
+ StringRef Value;
+};
+
+struct LinkerOptionsSection : Section {
+ Optional<std::vector<LinkerOption>> Options;
+ Optional<yaml::BinaryRef> Content;
+
+ LinkerOptionsSection() : Section(ChunkKind::LinkerOptions) {}
+
+ static bool classof(const Chunk *S) {
+ return S->Kind == ChunkKind::LinkerOptions;
+ }
+};
+
struct SymverSection : Section {
std::vector<uint16_t> Entries;
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<llvm::ELFYAML::Chunk>)
static void mapping(IO &IO, ELFYAML::AddrsigSymbol &Sym);
};
+template <> struct MappingTraits<ELFYAML::LinkerOption> {
+ static void mapping(IO &IO, ELFYAML::LinkerOption &Sym);
+};
+
template <> struct MappingTraits<ELFYAML::Relocation> {
static void mapping(IO &IO, ELFYAML::Relocation &Rel);
};
void writeSectionContent(Elf_Shdr &SHeader,
const ELFYAML::GnuHashSection &Section,
ContiguousBlobAccumulator &CBA);
+ void writeSectionContent(Elf_Shdr &SHeader,
+ const ELFYAML::LinkerOptionsSection &Section,
+ ContiguousBlobAccumulator &CBA);
void writeFill(ELFYAML::Fill &Fill, ContiguousBlobAccumulator &CBA);
writeSectionContent(SHeader, *S, CBA);
} else if (auto S = dyn_cast<ELFYAML::AddrsigSection>(Sec)) {
writeSectionContent(SHeader, *S, CBA);
+ } else if (auto S = dyn_cast<ELFYAML::LinkerOptionsSection>(Sec)) {
+ writeSectionContent(SHeader, *S, CBA);
} else if (auto S = dyn_cast<ELFYAML::NoteSection>(Sec)) {
writeSectionContent(SHeader, *S, CBA);
} else if (auto S = dyn_cast<ELFYAML::GnuHashSection>(Sec)) {
}
template <class ELFT>
+void ELFState<ELFT>::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;
+ }
+
+ if (!Section.Options)
+ 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 <class ELFT>
void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
const ELFYAML::HashSection &Section,
ContiguousBlobAccumulator &CBA) {
IO.mapRequired("Size", Fill.Size);
}
+static void sectionMapping(IO &IO, ELFYAML::LinkerOptionsSection &Section) {
+ commonSectionMapping(IO, Section);
+ IO.mapOptional("Options", Section.Options);
+ IO.mapOptional("Content", Section.Content);
+}
+
void MappingTraits<ELFYAML::SectionOrType>::mapping(
IO &IO, ELFYAML::SectionOrType §ionOrType) {
IO.mapRequired("SectionOrType", sectionOrType.sectionNameOrType);
Section.reset(new ELFYAML::AddrsigSection());
sectionMapping(IO, *cast<ELFYAML::AddrsigSection>(Section.get()));
break;
+ case ELF::SHT_LLVM_LINKER_OPTIONS:
+ if (!IO.outputting())
+ Section.reset(new ELFYAML::LinkerOptionsSection());
+ sectionMapping(IO, *cast<ELFYAML::LinkerOptionsSection>(Section.get()));
+ break;
default:
if (!IO.outputting()) {
StringRef Name;
return {};
}
+ if (const auto *Sec = dyn_cast<ELFYAML::LinkerOptionsSection>(C.get())) {
+ if (Sec->Options && Sec->Content)
+ return "\"Options\" and \"Content\" can't be used together";
+ return {};
+ }
+
if (const auto *F = dyn_cast<ELFYAML::Fill>(C.get())) {
if (!F->Pattern)
return {};
IO.mapOptional("Index", Sym.Index);
}
+void MappingTraits<ELFYAML::LinkerOption>::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)
--- /dev/null
+## Check how obj2yaml produces SHT_LLVM_LINKER_OPTIONS section 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 corrupt sections using the "Content" key.
+
+# RUN: yaml2obj --docnum=2 %s -o %t2
+# RUN: obj2yaml %t2 | FileCheck %s --check-prefix=CORRUPT
+
+# CORRUPT: - Name: .linker-options-empty
+# CORRUPT-NEXT: Type: SHT_LLVM_LINKER_OPTIONS
+# CORRUPT-NEXT: Content: ''
+# CORRUPT-NEXT: - Name: .linker-options-no-null
+# CORRUPT-NEXT: Type: SHT_LLVM_LINKER_OPTIONS
+# CORRUPT-NEXT: Content: '610062'
+# CORRUPT-NEXT: - Name: .linker-options-incomplete
+# CORRUPT-NEXT: Type: SHT_LLVM_LINKER_OPTIONS
+# CORRUPT-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: "610062"
+## 3) Odd number of strings in the section.
+## (Hence it contains an incomplete key-value pair).
+ - Name: .linker-options-incomplete
+ Type: SHT_LLVM_LINKER_OPTIONS
+ Content: "6100"
--- /dev/null
+## 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 --string-dump .linker-options1 --sections --section-data %t1 \
+# RUN: | 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: Name: .linker-options2
+# OPTIONS-NEXT: Type: SHT_LLVM_LINKER_OPTIONS
+# OPTIONS: SectionData (
+# OPTIONS-NEXT: 0000: 00112233 |
+# OPTIONS-NEXT: )
+
+# OPTIONS: String dump of section '.linker-options1':
+# OPTIONS-NEXT: [ 0] option 0
+# OPTIONS-NEXT: [ 9] value 0
+# OPTIONS-NEXT: [ 11] option 1
+# OPTIONS-NEXT: [ 1a] value 1
+
+--- !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 can omit both "Options" and "Content". This produces an empty section.
+
+# RUN: yaml2obj %s --docnum=5 2>&1 -o %t5
+# RUN: llvm-readelf --sections %t5 | FileCheck %s --check-prefix=NONE
+
+# NONE: [Nr] Name Type Address Off Size
+# NONE: [ 1] .linker-options LLVM_LINKER_OPTIONS 0000000000000000 000040 000000
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .linker-options
+ Type: SHT_LLVM_LINKER_OPTIONS
ELFYAML::Relocation &R);
Expected<ELFYAML::AddrsigSection *> dumpAddrsigSection(const Elf_Shdr *Shdr);
+ Expected<ELFYAML::LinkerOptionsSection *>
+ dumpLinkerOptionsSection(const Elf_Shdr *Shdr);
Expected<ELFYAML::DynamicSection *> dumpDynamicSection(const Elf_Shdr *Shdr);
Expected<ELFYAML::RelocationSection *> dumpRelocSection(const Elf_Shdr *Shdr);
Expected<ELFYAML::RawContentSection *>
Y->Chunks.emplace_back(*SecOrErr);
break;
}
+ case ELF::SHT_LLVM_LINKER_OPTIONS: {
+ Expected<ELFYAML::LinkerOptionsSection *> SecOrErr =
+ dumpLinkerOptionsSection(&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
}
template <class ELFT>
+Expected<ELFYAML::LinkerOptionsSection *>
+ELFDumper<ELFT>::dumpLinkerOptionsSection(const Elf_Shdr *Shdr) {
+ auto S = std::make_unique<ELFYAML::LinkerOptionsSection>();
+ if (Error E = dumpCommonSection(Shdr, *S))
+ return std::move(E);
+
+ auto ContentOrErr = Obj.getSectionContents(Shdr);
+ if (!ContentOrErr)
+ return ContentOrErr.takeError();
+
+ ArrayRef<uint8_t> Content = *ContentOrErr;
+ if (Content.empty() || Content.back() != 0) {
+ S->Content = Content;
+ return S.release();
+ }
+
+ SmallVector<StringRef, 16> Strings;
+ toStringRef(Content.drop_back()).split(Strings, '\0');
+ if (Strings.size() % 2 != 0) {
+ S->Content = Content;
+ return S.release();
+ }
+
+ S->Options.emplace();
+ for (size_t I = 0, E = Strings.size(); I != E; I += 2)
+ S->Options->push_back({Strings[I], Strings[I + 1]});
+
+ return S.release();
+}
+
+template <class ELFT>
Expected<ELFYAML::DynamicSection *>
ELFDumper<ELFT>::dumpDynamicSection(const Elf_Shdr *Shdr) {
auto S = std::make_unique<ELFYAML::DynamicSection>();