diff options
-rw-r--r-- | llvm/docs/Extensions.rst | 38 | ||||
-rw-r--r-- | llvm/include/llvm/BinaryFormat/ELF.h | 77 | ||||
-rw-r--r-- | llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp | 19 | ||||
-rw-r--r-- | llvm/lib/MC/MCParser/ELFAsmParser.cpp | 2 | ||||
-rw-r--r-- | llvm/lib/MC/MCSectionELF.cpp | 2 | ||||
-rw-r--r-- | llvm/lib/Object/ELF.cpp | 1 | ||||
-rw-r--r-- | llvm/lib/ObjectYAML/ELFYAML.cpp | 1 | ||||
-rw-r--r-- | llvm/test/Feature/elf-linker-options.ll | 16 | ||||
-rw-r--r-- | llvm/test/MC/ELF/section.s | 14 | ||||
-rw-r--r-- | llvm/test/tools/llvm-readobj/elf-linker-options.ll | 11 | ||||
-rw-r--r-- | llvm/tools/llvm-readobj/ELFDumper.cpp | 37 | ||||
-rw-r--r-- | llvm/tools/llvm-readobj/ObjDumper.h | 1 | ||||
-rw-r--r-- | llvm/tools/llvm-readobj/llvm-readobj.cpp | 7 |
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(); |