[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 §ionOrType) {
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