[llvm] dd10153 - [yaml2obj/obj2yaml] - Add support for SHT_LLVM_LINKER_OPTIONS sections.

Georgii Rymar via llvm-commits llvm-commits at lists.llvm.org
Mon Nov 11 22:56:47 PST 2019


Author: Georgii Rymar
Date: 2019-11-12T09:55:20+03:00
New Revision: dd101539dac5e464042c04b72090741317d48c23

URL: https://github.com/llvm/llvm-project/commit/dd101539dac5e464042c04b72090741317d48c23
DIFF: https://github.com/llvm/llvm-project/commit/dd101539dac5e464042c04b72090741317d48c23.diff

LOG: [yaml2obj/obj2yaml] - Add support for SHT_LLVM_LINKER_OPTIONS sections.

SHT_LLVM_LINKER_OPTIONS section contains pairs of null-terminated strings.
This patch adds support for them.

Differential revision: https://reviews.llvm.org/D69895

Added: 
    llvm/test/tools/obj2yaml/linker-options.yaml
    llvm/test/tools/yaml2obj/linker-options.yaml

Modified: 
    llvm/include/llvm/ObjectYAML/ELFYAML.h
    llvm/lib/ObjectYAML/ELFEmitter.cpp
    llvm/lib/ObjectYAML/ELFYAML.cpp
    llvm/tools/obj2yaml/elf2yaml.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h
index 927afc2287a7..1c5da134e6bd 100644
--- a/llvm/include/llvm/ObjectYAML/ELFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h
@@ -147,7 +147,8 @@ struct Chunk {
     Symver,
     MipsABIFlags,
     Addrsig,
-    Fill
+    Fill,
+    LinkerOptions,
   };
 
   ChunkKind Kind;
@@ -349,6 +350,22 @@ struct AddrsigSection : Section {
   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;
 
@@ -464,6 +481,7 @@ struct Object {
 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>)
@@ -631,6 +649,10 @@ template <> struct MappingTraits<ELFYAML::AddrsigSymbol> {
   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);
 };

diff  --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp
index b9c22e7d99c8..1a6f0a8337aa 100644
--- a/llvm/lib/ObjectYAML/ELFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp
@@ -200,6 +200,9 @@ template <class ELFT> class ELFState {
   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);
 
@@ -466,6 +469,8 @@ void ELFState<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders,
       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)) {
@@ -892,6 +897,30 @@ void ELFState<ELFT>::writeSectionContent(
   }
 }
 
+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,

diff  --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp
index b50f842bba5b..bc546b19ff35 100644
--- a/llvm/lib/ObjectYAML/ELFYAML.cpp
+++ b/llvm/lib/ObjectYAML/ELFYAML.cpp
@@ -1100,6 +1100,12 @@ static void fillMapping(IO &IO, ELFYAML::Fill &Fill) {
   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 &sectionOrType) {
   IO.mapRequired("SectionOrType", sectionOrType.sectionNameOrType);
@@ -1217,6 +1223,11 @@ void MappingTraits<std::unique_ptr<ELFYAML::Chunk>>::mapping(
       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;
@@ -1355,6 +1366,12 @@ StringRef MappingTraits<std::unique_ptr<ELFYAML::Chunk>>::validate(
     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 {};
@@ -1493,6 +1510,13 @@ void MappingTraits<ELFYAML::AddrsigSymbol>::mapping(IO &IO, ELFYAML::AddrsigSymb
   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)

diff  --git a/llvm/test/tools/obj2yaml/linker-options.yaml b/llvm/test/tools/obj2yaml/linker-options.yaml
new file mode 100644
index 000000000000..260f6fd52292
--- /dev/null
+++ b/llvm/test/tools/obj2yaml/linker-options.yaml
@@ -0,0 +1,69 @@
+## 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"

diff  --git a/llvm/test/tools/yaml2obj/linker-options.yaml b/llvm/test/tools/yaml2obj/linker-options.yaml
new file mode 100644
index 000000000000..2082e4945344
--- /dev/null
+++ b/llvm/test/tools/yaml2obj/linker-options.yaml
@@ -0,0 +1,120 @@
+## 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

diff  --git a/llvm/tools/obj2yaml/elf2yaml.cpp b/llvm/tools/obj2yaml/elf2yaml.cpp
index 13469804b983..15c38c630b96 100644
--- a/llvm/tools/obj2yaml/elf2yaml.cpp
+++ b/llvm/tools/obj2yaml/elf2yaml.cpp
@@ -60,6 +60,8 @@ class ELFDumper {
                        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 *>
@@ -315,6 +317,14 @@ template <class ELFT> Expected<ELFYAML::Object *> ELFDumper<ELFT>::dump() {
       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
@@ -588,6 +598,37 @@ ELFDumper<ELFT>::dumpAddrsigSection(const Elf_Shdr *Shdr) {
   return S.release();
 }
 
+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) {


        


More information about the llvm-commits mailing list