summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/docs/Extensions.rst38
-rw-r--r--llvm/include/llvm/BinaryFormat/ELF.h77
-rw-r--r--llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp19
-rw-r--r--llvm/lib/MC/MCParser/ELFAsmParser.cpp2
-rw-r--r--llvm/lib/MC/MCSectionELF.cpp2
-rw-r--r--llvm/lib/Object/ELF.cpp1
-rw-r--r--llvm/lib/ObjectYAML/ELFYAML.cpp1
-rw-r--r--llvm/test/Feature/elf-linker-options.ll16
-rw-r--r--llvm/test/MC/ELF/section.s14
-rw-r--r--llvm/test/tools/llvm-readobj/elf-linker-options.ll11
-rw-r--r--llvm/tools/llvm-readobj/ELFDumper.cpp37
-rw-r--r--llvm/tools/llvm-readobj/ObjDumper.h1
-rw-r--r--llvm/tools/llvm-readobj/llvm-readobj.cpp7
13 files changed, 187 insertions, 39 deletions
diff --git a/llvm/docs/Extensions.rst b/llvm/docs/Extensions.rst
index 32eeadd78ba..46189a3b1ec 100644
--- a/llvm/docs/Extensions.rst
+++ b/llvm/docs/Extensions.rst
@@ -221,6 +221,44 @@ which is equivalent to just
.section .foo,"a",@progbits
.section .bar,"ao",@progbits,.foo
+``.linker-options`` Section (linker options)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In order to support passing linker options from the frontend to the linker, a
+special section of type ``SHT_LLVM_LINKER_OPTIONS`` (usually named
+``.linker-options`` though the name is not significant as it is identified by
+the type). The contents of this section is a simple pair-wise encoding of
+options for consideration by the linker. The strings are encoded as standard
+null-terminated UTF-8 strings. They are emitted inline to avoid having the
+linker to traverse the object file for retrieving the value. The linker is
+permitted to not honour the option and instead provide a warning/error to the
+user that the requested option was not honoured.
+
+The section is marked as ``SHT_LLVM_LINKER_OPTIONS`` and has the ``SHF_EXCLUDE``
+flag to ensure that the section is treated as opaque by linkers which do not
+support the feature and will not be emitted into the final linked binary.
+
+This would be equivalent to the follow raw assembly:
+
+.. code-block:: gas
+
+ .section ".linker-options","e",@llvm_linker_options
+ .asciz "option 1"
+ .asciz "value 1"
+ .asciz "option 2"
+ .asciz "value 2"
+
+LLVM emits the following options:
+ - lib
+
+ The parameter identifies a library to be linked against. The library will
+ be looked up in the default and any specified library search paths
+ (specified to this point).
+
+ - path
+
+ The paramter identifies an additional library search path to be considered
+ when looking up libraries after the inclusion of this option.
Target Specific Behaviour
=========================
diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h
index c902972d93b..d2bdc1ef198 100644
--- a/llvm/include/llvm/BinaryFormat/ELF.h
+++ b/llvm/include/llvm/BinaryFormat/ELF.h
@@ -714,36 +714,37 @@ enum {
// Section types.
enum : unsigned {
- SHT_NULL = 0, // No associated section (inactive entry).
- SHT_PROGBITS = 1, // Program-defined contents.
- SHT_SYMTAB = 2, // Symbol table.
- SHT_STRTAB = 3, // String table.
- SHT_RELA = 4, // Relocation entries; explicit addends.
- SHT_HASH = 5, // Symbol hash table.
- SHT_DYNAMIC = 6, // Information for dynamic linking.
- SHT_NOTE = 7, // Information about the file.
- SHT_NOBITS = 8, // Data occupies no space in the file.
- SHT_REL = 9, // Relocation entries; no explicit addends.
- SHT_SHLIB = 10, // Reserved.
- SHT_DYNSYM = 11, // Symbol table.
- SHT_INIT_ARRAY = 14, // Pointers to initialization functions.
- SHT_FINI_ARRAY = 15, // Pointers to termination functions.
- SHT_PREINIT_ARRAY = 16, // Pointers to pre-init functions.
- SHT_GROUP = 17, // Section group.
- SHT_SYMTAB_SHNDX = 18, // Indices for SHN_XINDEX entries.
- SHT_LOOS = 0x60000000, // Lowest operating system-specific type.
+ SHT_NULL = 0, // No associated section (inactive entry).
+ SHT_PROGBITS = 1, // Program-defined contents.
+ SHT_SYMTAB = 2, // Symbol table.
+ SHT_STRTAB = 3, // String table.
+ SHT_RELA = 4, // Relocation entries; explicit addends.
+ SHT_HASH = 5, // Symbol hash table.
+ SHT_DYNAMIC = 6, // Information for dynamic linking.
+ SHT_NOTE = 7, // Information about the file.
+ SHT_NOBITS = 8, // Data occupies no space in the file.
+ SHT_REL = 9, // Relocation entries; no explicit addends.
+ SHT_SHLIB = 10, // Reserved.
+ SHT_DYNSYM = 11, // Symbol table.
+ SHT_INIT_ARRAY = 14, // Pointers to initialization functions.
+ SHT_FINI_ARRAY = 15, // Pointers to termination functions.
+ SHT_PREINIT_ARRAY = 16, // Pointers to pre-init functions.
+ SHT_GROUP = 17, // Section group.
+ SHT_SYMTAB_SHNDX = 18, // Indices for SHN_XINDEX entries.
+ SHT_LOOS = 0x60000000, // Lowest operating system-specific type.
// Android packed relocation section types.
// https://android.googlesource.com/platform/bionic/+/6f12bfece5dcc01325e0abba56a46b1bcf991c69/tools/relocation_packer/src/elf_file.cc#37
SHT_ANDROID_REL = 0x60000001,
SHT_ANDROID_RELA = 0x60000002,
- SHT_LLVM_ODRTAB = 0x6fff4c00, // LLVM ODR table.
- SHT_GNU_ATTRIBUTES = 0x6ffffff5, // Object attributes.
- SHT_GNU_HASH = 0x6ffffff6, // GNU-style hash table.
- SHT_GNU_verdef = 0x6ffffffd, // GNU version definitions.
- SHT_GNU_verneed = 0x6ffffffe, // GNU version references.
- SHT_GNU_versym = 0x6fffffff, // GNU symbol versions table.
- SHT_HIOS = 0x6fffffff, // Highest operating system-specific type.
- SHT_LOPROC = 0x70000000, // Lowest processor arch-specific type.
+ SHT_LLVM_ODRTAB = 0x6fff4c00, // LLVM ODR table.
+ SHT_LLVM_LINKER_OPTIONS = 0x6fff4c01, // LLVM Linker Options.
+ SHT_GNU_ATTRIBUTES = 0x6ffffff5, // Object attributes.
+ SHT_GNU_HASH = 0x6ffffff6, // GNU-style hash table.
+ SHT_GNU_verdef = 0x6ffffffd, // GNU version definitions.
+ SHT_GNU_verneed = 0x6ffffffe, // GNU version references.
+ SHT_GNU_versym = 0x6fffffff, // GNU symbol versions table.
+ SHT_HIOS = 0x6fffffff, // Highest operating system-specific type.
+ SHT_LOPROC = 0x70000000, // Lowest processor arch-specific type.
// Fixme: All this is duplicated in MCSectionELF. Why??
// Exception Index table
SHT_ARM_EXIDX = 0x70000001U,
@@ -753,18 +754,18 @@ enum : unsigned {
SHT_ARM_ATTRIBUTES = 0x70000003U,
SHT_ARM_DEBUGOVERLAY = 0x70000004U,
SHT_ARM_OVERLAYSECTION = 0x70000005U,
- SHT_HEX_ORDERED = 0x70000000, // Link editor is to sort the entries in
- // this section based on their sizes
- SHT_X86_64_UNWIND = 0x70000001, // Unwind information
-
- SHT_MIPS_REGINFO = 0x70000006, // Register usage information
- SHT_MIPS_OPTIONS = 0x7000000d, // General options
- SHT_MIPS_DWARF = 0x7000001e, // DWARF debugging section.
- SHT_MIPS_ABIFLAGS = 0x7000002a, // ABI information.
-
- SHT_HIPROC = 0x7fffffff, // Highest processor arch-specific type.
- SHT_LOUSER = 0x80000000, // Lowest type reserved for applications.
- SHT_HIUSER = 0xffffffff // Highest type reserved for applications.
+ SHT_HEX_ORDERED = 0x70000000, // Link editor is to sort the entries in
+ // this section based on their sizes
+ SHT_X86_64_UNWIND = 0x70000001, // Unwind information
+
+ SHT_MIPS_REGINFO = 0x70000006, // Register usage information
+ SHT_MIPS_OPTIONS = 0x7000000d, // General options
+ SHT_MIPS_DWARF = 0x7000001e, // DWARF debugging section.
+ SHT_MIPS_ABIFLAGS = 0x7000002a, // ABI information.
+
+ SHT_HIPROC = 0x7fffffff, // Highest processor arch-specific type.
+ SHT_LOUSER = 0x80000000, // Lowest type reserved for applications.
+ SHT_HIUSER = 0xffffffff // Highest type reserved for applications.
};
// Section flags.
diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
index 0e90df901fd..dc3efe1d4bc 100644
--- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
@@ -93,6 +93,24 @@ static void GetObjCImageInfo(Module &M, unsigned &Version, unsigned &Flags,
void TargetLoweringObjectFileELF::emitModuleMetadata(
MCStreamer &Streamer, Module &M, const TargetMachine &TM) const {
+ auto &C = getContext();
+
+ if (NamedMDNode *LinkerOptions = M.getNamedMetadata("llvm.linker.options")) {
+ auto *S = C.getELFSection(".linker-options", ELF::SHT_LLVM_LINKER_OPTIONS,
+ ELF::SHF_EXCLUDE);
+
+ Streamer.SwitchSection(S);
+
+ for (const auto &Operand : LinkerOptions->operands()) {
+ if (cast<MDNode>(Operand)->getNumOperands() != 2)
+ report_fatal_error("invalid llvm.linker.options");
+ for (const auto &Option : cast<MDNode>(Operand)->operands()) {
+ Streamer.EmitBytes(cast<MDString>(Option)->getString());
+ Streamer.EmitIntValue(0, 1);
+ }
+ }
+ }
+
unsigned Version = 0;
unsigned Flags = 0;
StringRef Section;
@@ -101,7 +119,6 @@ void TargetLoweringObjectFileELF::emitModuleMetadata(
if (Section.empty())
return;
- auto &C = getContext();
auto *S = C.getELFSection(Section, ELF::SHT_PROGBITS, ELF::SHF_ALLOC);
Streamer.SwitchSection(S);
Streamer.EmitLabel(C.getOrCreateSymbol(StringRef("OBJC_IMAGE_INFO")));
diff --git a/llvm/lib/MC/MCParser/ELFAsmParser.cpp b/llvm/lib/MC/MCParser/ELFAsmParser.cpp
index c634df99a11..59ffd756b2b 100644
--- a/llvm/lib/MC/MCParser/ELFAsmParser.cpp
+++ b/llvm/lib/MC/MCParser/ELFAsmParser.cpp
@@ -608,6 +608,8 @@ EndStmt:
Type = ELF::SHT_X86_64_UNWIND;
else if (TypeName == "llvm_odrtab")
Type = ELF::SHT_LLVM_ODRTAB;
+ else if (TypeName == "llvm_linker_options")
+ Type = ELF::SHT_LLVM_LINKER_OPTIONS;
else if (TypeName.getAsInteger(0, Type))
return TokError("unknown section type");
}
diff --git a/llvm/lib/MC/MCSectionELF.cpp b/llvm/lib/MC/MCSectionELF.cpp
index bf1fcb03273..36cdb421655 100644
--- a/llvm/lib/MC/MCSectionELF.cpp
+++ b/llvm/lib/MC/MCSectionELF.cpp
@@ -148,6 +148,8 @@ void MCSectionELF::PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
OS << "0x7000001e";
else if (Type == ELF::SHT_LLVM_ODRTAB)
OS << "llvm_odrtab";
+ else if (Type == ELF::SHT_LLVM_LINKER_OPTIONS)
+ OS << "llvm_linker_options";
else
report_fatal_error("unsupported type 0x" + Twine::utohexstr(Type) +
" for section " + getSectionName());
diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp
index 5906dc5f530..92a64f48924 100644
--- a/llvm/lib/Object/ELF.cpp
+++ b/llvm/lib/Object/ELF.cpp
@@ -205,6 +205,7 @@ StringRef llvm::object::getELFSectionTypeName(uint32_t Machine, unsigned Type) {
STRINGIFY_ENUM_CASE(ELF, SHT_ANDROID_REL);
STRINGIFY_ENUM_CASE(ELF, SHT_ANDROID_RELA);
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_ODRTAB);
+ STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_LINKER_OPTIONS);
STRINGIFY_ENUM_CASE(ELF, SHT_GNU_ATTRIBUTES);
STRINGIFY_ENUM_CASE(ELF, SHT_GNU_HASH);
STRINGIFY_ENUM_CASE(ELF, SHT_GNU_verdef);
diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp
index 7e7f3d1fdde..551269e1d6f 100644
--- a/llvm/lib/ObjectYAML/ELFYAML.cpp
+++ b/llvm/lib/ObjectYAML/ELFYAML.cpp
@@ -408,6 +408,7 @@ void ScalarEnumerationTraits<ELFYAML::ELF_SHT>::enumeration(
ECase(SHT_ANDROID_REL);
ECase(SHT_ANDROID_RELA);
ECase(SHT_LLVM_ODRTAB);
+ ECase(SHT_LLVM_LINKER_OPTIONS);
ECase(SHT_GNU_ATTRIBUTES);
ECase(SHT_GNU_HASH);
ECase(SHT_GNU_verdef);
diff --git a/llvm/test/Feature/elf-linker-options.ll b/llvm/test/Feature/elf-linker-options.ll
new file mode 100644
index 00000000000..7e002c27b9e
--- /dev/null
+++ b/llvm/test/Feature/elf-linker-options.ll
@@ -0,0 +1,16 @@
+; RUN: llc -mtriple x86_64-elf -filetype asm -o - %s | FileCheck %s
+
+!llvm.linker.options = !{!0, !1}
+
+!0 = !{!"option 0", !"value 0"}
+!1 = !{!"option 1", !"value 1"}
+
+; CHECK: .section ".linker-options","e",@llvm_linker_options
+; CHECK-NEXT: .ascii "option 0"
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "value 0"
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "option 1"
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .ascii "value 1"
+; CHECK-NEXT: .byte 0
diff --git a/llvm/test/MC/ELF/section.s b/llvm/test/MC/ELF/section.s
index c3f7d426ba5..57755223db1 100644
--- a/llvm/test/MC/ELF/section.s
+++ b/llvm/test/MC/ELF/section.s
@@ -279,3 +279,17 @@ bar:
// CHECK-NEXT: Flags [
// CHECK-NEXT: SHF_EXCLUDE
// CHECK-NEXT: ]
+
+// Test SHT_LLVM_LINKER_OPTIONS
+
+.section ".linker-options","e",@llvm_linker_options
+// ASM: .section ".linker-options","e",@llvm_linker_options
+
+// CHECK: Section {
+// CHECK: Name: .linker-options
+// CHECK-NEXT: Type: SHT_LLVM_LINKER_OPTIONS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: SHF_EXCLUDE
+// CHECK-NEXT: ]
+// CHECK: }
+
diff --git a/llvm/test/tools/llvm-readobj/elf-linker-options.ll b/llvm/test/tools/llvm-readobj/elf-linker-options.ll
new file mode 100644
index 00000000000..6f96613c777
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/elf-linker-options.ll
@@ -0,0 +1,11 @@
+; RUN: llc -mtriple x86_64-elf -filetype obj -o - %s | llvm-readobj -elf-linker-options - | FileCheck %s
+
+!llvm.linker.options = !{!0, !1}
+
+!0 = !{!"option 0", !"value 0"}
+!1 = !{!"option 1", !"value 1"}
+
+; CHECK: LinkerOptions [
+; CHECK: option 0: value 0
+; CHECK: option 1: value 1
+; CHECK: ]
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index dfc5560cc7a..dd81c0b4562 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -164,6 +164,8 @@ public:
void printNotes() override;
+ void printELFLinkerOptions() override;
+
private:
std::unique_ptr<DumpStyle<ELFT>> ELFDumperStyle;
@@ -316,6 +318,7 @@ public:
virtual void printProgramHeaders(const ELFFile<ELFT> *Obj) = 0;
virtual void printHashHistogram(const ELFFile<ELFT> *Obj) = 0;
virtual void printNotes(const ELFFile<ELFT> *Obj) = 0;
+ virtual void printELFLinkerOptions(const ELFFile<ELFT> *Obj) = 0;
virtual void printMipsGOT(const MipsGOTParser<ELFT> &Parser) = 0;
virtual void printMipsPLT(const MipsGOTParser<ELFT> &Parser) = 0;
const ELFDumper<ELFT> *dumper() const { return Dumper; }
@@ -345,6 +348,7 @@ public:
void printProgramHeaders(const ELFO *Obj) override;
void printHashHistogram(const ELFFile<ELFT> *Obj) override;
void printNotes(const ELFFile<ELFT> *Obj) override;
+ void printELFLinkerOptions(const ELFFile<ELFT> *Obj) override;
void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override;
void printMipsPLT(const MipsGOTParser<ELFT> &Parser) override;
@@ -405,6 +409,7 @@ public:
void printProgramHeaders(const ELFO *Obj) override;
void printHashHistogram(const ELFFile<ELFT> *Obj) override;
void printNotes(const ELFFile<ELFT> *Obj) override;
+ void printELFLinkerOptions(const ELFFile<ELFT> *Obj) override;
void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override;
void printMipsPLT(const MipsGOTParser<ELFT> &Parser) override;
@@ -1501,6 +1506,10 @@ template <class ELFT> void ELFDumper<ELFT>::printNotes() {
ELFDumperStyle->printNotes(Obj);
}
+template <class ELFT> void ELFDumper<ELFT>::printELFLinkerOptions() {
+ ELFDumperStyle->printELFLinkerOptions(Obj);
+}
+
#define LLVM_READOBJ_TYPE_CASE(name) \
case DT_##name: return #name
@@ -2694,6 +2703,8 @@ std::string getSectionTypeString(unsigned Arch, unsigned Type) {
return "SYMTAB SECTION INDICES";
case SHT_LLVM_ODRTAB:
return "LLVM_ODRTAB";
+ case SHT_LLVM_LINKER_OPTIONS:
+ return "LLVM_LINKER_OPTIONS";
// FIXME: Parse processor specific GNU attributes
case SHT_GNU_ATTRIBUTES:
return "ATTRIBUTES";
@@ -3555,6 +3566,11 @@ void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {
}
template <class ELFT>
+void GNUStyle<ELFT>::printELFLinkerOptions(const ELFFile<ELFT> *Obj) {
+ OS << "printELFLinkerOptions not implemented!\n";
+}
+
+template <class ELFT>
void GNUStyle<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) {
size_t Bias = ELFT::Is64Bits ? 8 : 0;
auto PrintEntry = [&](const Elf_Addr *E, StringRef Purpose) {
@@ -4063,6 +4079,27 @@ void LLVMStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {
}
template <class ELFT>
+void LLVMStyle<ELFT>::printELFLinkerOptions(const ELFFile<ELFT> *Obj) {
+ ListScope L(W, "LinkerOptions");
+
+ for (const Elf_Shdr &Shdr : unwrapOrError(Obj->sections())) {
+ if (Shdr.sh_type != ELF::SHT_LLVM_LINKER_OPTIONS)
+ continue;
+
+ ArrayRef<uint8_t> Contents = unwrapOrError(Obj->getSectionContents(&Shdr));
+ for (const uint8_t *P = Contents.begin(), *E = Contents.end(); P < E; ) {
+ StringRef Key = StringRef(reinterpret_cast<const char *>(P));
+ StringRef Value =
+ StringRef(reinterpret_cast<const char *>(P) + Key.size() + 1);
+
+ W.printString(Key, Value);
+
+ P = P + Key.size() + Value.size() + 2;
+ }
+ }
+}
+
+template <class ELFT>
void LLVMStyle<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) {
auto PrintEntry = [&](const Elf_Addr *E) {
W.printHex("Address", Parser.getGotAddress(E));
diff --git a/llvm/tools/llvm-readobj/ObjDumper.h b/llvm/tools/llvm-readobj/ObjDumper.h
index 2648eea9f31..2bf4dfe5a40 100644
--- a/llvm/tools/llvm-readobj/ObjDumper.h
+++ b/llvm/tools/llvm-readobj/ObjDumper.h
@@ -48,6 +48,7 @@ public:
virtual void printGroupSections() {}
virtual void printHashHistogram() {}
virtual void printNotes() {}
+ virtual void printELFLinkerOptions() {}
// Only implemented for ARM ELF at this time.
virtual void printAttributes() { }
diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp
index 5b7b227aa36..1d87b87d437 100644
--- a/llvm/tools/llvm-readobj/llvm-readobj.cpp
+++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp
@@ -229,6 +229,11 @@ namespace opts {
COFFLoadConfig("coff-load-config",
cl::desc("Display the PE/COFF load config"));
+ // -elf-linker-options
+ cl::opt<bool>
+ ELFLinkerOptions("elf-linker-options",
+ cl::desc("Display the ELF .linker-options section"));
+
// -macho-data-in-code
cl::opt<bool>
MachODataInCode("macho-data-in-code",
@@ -419,6 +424,8 @@ static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer) {
if (opts::VersionInfo)
Dumper->printVersionInfo();
if (Obj->isELF()) {
+ if (opts::ELFLinkerOptions)
+ Dumper->printELFLinkerOptions();
if (Obj->getArch() == llvm::Triple::arm)
if (opts::ARMAttributes)
Dumper->printAttributes();
OpenPOWER on IntegriCloud