[llvm] 9659464 - [yaml2obj/obj2yaml] - Add support for SHT_LLVM_DEPENDENT_LIBRARIES sections.

Georgii Rymar via llvm-commits llvm-commits at lists.llvm.org
Mon Nov 25 01:58:08 PST 2019


Author: Georgii Rymar
Date: 2019-11-25T12:57:53+03:00
New Revision: 9659464d7e7f30c6a1cee07c739dfe8f812924fd

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

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

This section contains strings specifying libraries to be added to the link by the linker.
The strings are encoded as standard null-terminated UTF-8 strings.

This patch adds a way to describe and dump SHT_LLVM_DEPENDENT_LIBRARIES sections.

I introduced a new YAMLFlowString type here. That used to teach obj2yaml to dump
them like:

```
Libraries: [ foo, bar ]
```

instead of the following (if StringRef would be used):

```
Libraries:
  - foo
  - bar
```

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

Added: 
    llvm/test/tools/obj2yaml/llvm-deplibs-section.yaml
    llvm/test/tools/yaml2obj/ELF/llvm-deplibs-section.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 1c5da134e6bd..a498621a2a13 100644
--- a/llvm/include/llvm/ObjectYAML/ELFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h
@@ -64,6 +64,8 @@ LLVM_YAML_STRONG_TYPEDEF(uint32_t, MIPS_AFL_ASE)
 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 @@ struct Chunk {
     Addrsig,
     Fill,
     LinkerOptions,
+    DependentLibraries,
   };
 
   ChunkKind Kind;
@@ -366,6 +369,17 @@ struct LinkerOptionsSection : Section {
   }
 };
 
+struct DependentLibrariesSection : Section {
+  Optional<std::vector<YAMLFlowString>> Libs;
+  Optional<yaml::BinaryRef> Content;
+
+  DependentLibrariesSection() : Section(ChunkKind::DependentLibraries) {}
+
+  static bool classof(const Chunk *S) {
+    return S->Kind == ChunkKind::DependentLibraries;
+  }
+};
+
 struct SymverSection : Section {
   std::vector<uint16_t> Entries;
 

diff  --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp
index 1a6f0a8337aa..e8b54a7e6020 100644
--- a/llvm/lib/ObjectYAML/ELFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp
@@ -203,6 +203,9 @@ template <class ELFT> class ELFState {
   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 @@ void ELFState<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders,
       writeSectionContent(SHeader, *S, CBA);
     } else if (auto S = dyn_cast<ELFYAML::GnuHashSection>(Sec)) {
       writeSectionContent(SHeader, *S, CBA);
+    } else if (auto S = dyn_cast<ELFYAML::DependentLibrariesSection>(Sec)) {
+      writeSectionContent(SHeader, *S, CBA);
     } else {
       llvm_unreachable("Unknown section type");
     }
@@ -921,6 +926,28 @@ void ELFState<ELFT>::writeSectionContent(
   }
 }
 
+template <class ELFT>
+void ELFState<ELFT>::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 <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 bc546b19ff35..a5e5894af04d 100644
--- a/llvm/lib/ObjectYAML/ELFYAML.cpp
+++ b/llvm/lib/ObjectYAML/ELFYAML.cpp
@@ -863,6 +863,24 @@ template <> struct SequenceElementTraits<StOtherPiece> {
   static const bool flow = true;
 };
 
+template <> struct ScalarTraits<ELFYAML::YAMLFlowString> {
+  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<StringRef>::mustQuote(S);
+  }
+};
+template <> struct SequenceElementTraits<ELFYAML::YAMLFlowString> {
+  static const bool flow = true;
+};
+
 namespace {
 
 struct NormalizedOther {
@@ -1106,6 +1124,13 @@ static void sectionMapping(IO &IO, ELFYAML::LinkerOptionsSection &Section) {
   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<ELFYAML::SectionOrType>::mapping(
     IO &IO, ELFYAML::SectionOrType &sectionOrType) {
   IO.mapRequired("SectionOrType", sectionOrType.sectionNameOrType);
@@ -1228,6 +1253,12 @@ void MappingTraits<std::unique_ptr<ELFYAML::Chunk>>::mapping(
       Section.reset(new ELFYAML::LinkerOptionsSection());
     sectionMapping(IO, *cast<ELFYAML::LinkerOptionsSection>(Section.get()));
     break;
+  case ELF::SHT_LLVM_DEPENDENT_LIBRARIES:
+    if (!IO.outputting())
+      Section.reset(new ELFYAML::DependentLibrariesSection());
+    sectionMapping(IO,
+                   *cast<ELFYAML::DependentLibrariesSection>(Section.get()));
+    break;
   default:
     if (!IO.outputting()) {
       StringRef Name;
@@ -1372,6 +1403,14 @@ StringRef MappingTraits<std::unique_ptr<ELFYAML::Chunk>>::validate(
     return {};
   }
 
+  if (const auto *Sec = dyn_cast<ELFYAML::DependentLibrariesSection>(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<ELFYAML::Fill>(C.get())) {
     if (!F->Pattern)
       return {};

diff  --git a/llvm/test/tools/obj2yaml/llvm-deplibs-section.yaml b/llvm/test/tools/obj2yaml/llvm-deplibs-section.yaml
new file mode 100644
index 000000000000..d2cd6e706c31
--- /dev/null
+++ b/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" when dumping a valid section with a null-terminated string.
+  - Name:      .deplibs.single
+    Type:      SHT_LLVM_DEPENDENT_LIBRARIES
+    Libraries: [ foo ]
+## Case 2: the same, but the section has multiple strings.
+  - Name:      .deplibs.multiple
+    Type:      SHT_LLVM_DEPENDENT_LIBRARIES
+    Libraries: [ foo, bar, foo ]
+## Case 3: test we use "Libraries" when dumping an empty section.
+  - Name:      .deplibs.empty
+    Type:      SHT_LLVM_DEPENDENT_LIBRARIES
+    Libraries: [ ]
+## Case 4: test we use "Content" when dumping a non-null terminated section.
+  - Name:      .deplibs.nonul
+    Type:      SHT_LLVM_DEPENDENT_LIBRARIES
+    Content:   "666f6f"

diff  --git a/llvm/test/tools/yaml2obj/ELF/llvm-deplibs-section.yaml b/llvm/test/tools/yaml2obj/ELF/llvm-deplibs-section.yaml
new file mode 100644
index 000000000000..0ef19929e80d
--- /dev/null
+++ b/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
+    Content:   "FF"
+    Libraries: [ foo ]
+
+## 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

diff  --git a/llvm/tools/obj2yaml/elf2yaml.cpp b/llvm/tools/obj2yaml/elf2yaml.cpp
index 15c38c630b96..3dc48b8b8802 100644
--- a/llvm/tools/obj2yaml/elf2yaml.cpp
+++ b/llvm/tools/obj2yaml/elf2yaml.cpp
@@ -62,6 +62,8 @@ class ELFDumper {
   Expected<ELFYAML::AddrsigSection *> dumpAddrsigSection(const Elf_Shdr *Shdr);
   Expected<ELFYAML::LinkerOptionsSection *>
   dumpLinkerOptionsSection(const Elf_Shdr *Shdr);
+  Expected<ELFYAML::DependentLibrariesSection *>
+  dumpDependentLibrariesSection(const Elf_Shdr *Shdr);
   Expected<ELFYAML::DynamicSection *> dumpDynamicSection(const Elf_Shdr *Shdr);
   Expected<ELFYAML::RelocationSection *> dumpRelocSection(const Elf_Shdr *Shdr);
   Expected<ELFYAML::RawContentSection *>
@@ -325,6 +327,14 @@ template <class ELFT> Expected<ELFYAML::Object *> ELFDumper<ELFT>::dump() {
       Y->Chunks.emplace_back(*SecOrErr);
       break;
     }
+    case ELF::SHT_LLVM_DEPENDENT_LIBRARIES: {
+      Expected<ELFYAML::DependentLibrariesSection *> 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 @@ ELFDumper<ELFT>::dumpLinkerOptionsSection(const Elf_Shdr *Shdr) {
   return S.release();
 }
 
+template <class ELFT>
+Expected<ELFYAML::DependentLibrariesSection *>
+ELFDumper<ELFT>::dumpDependentLibrariesSection(const Elf_Shdr *Shdr) {
+  auto DL = std::make_unique<ELFYAML::DependentLibrariesSection>();
+  if (Error E = dumpCommonSection(Shdr, *DL))
+    return std::move(E);
+
+  Expected<ArrayRef<uint8_t>> ContentOrErr = Obj.getSectionContents(Shdr);
+  if (!ContentOrErr)
+    return ContentOrErr.takeError();
+
+  ArrayRef<uint8_t> 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 <class ELFT>
 Expected<ELFYAML::DynamicSection *>
 ELFDumper<ELFT>::dumpDynamicSection(const Elf_Shdr *Shdr) {


        


More information about the llvm-commits mailing list