Index: docs/Extensions.rst =================================================================== --- docs/Extensions.rst +++ docs/Extensions.rst @@ -221,6 +221,32 @@ .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 ``.linker-options`` is emitted when necessary. 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 C-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 emitted in raw assembly as: + +.. code-block:: gas + + .section ".linker-options","e",@llvm_linker_options + .asciz "option 1" + .asciz "value 1" + .asciz "option 2" + .asciz "value 2" + Target Specific Behaviour ========================= Index: include/llvm/BinaryFormat/ELF.h =================================================================== --- include/llvm/BinaryFormat/ELF.h +++ include/llvm/BinaryFormat/ELF.h @@ -737,6 +737,7 @@ SHT_ANDROID_REL = 0x60000001, SHT_ANDROID_RELA = 0x60000002, 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. Index: lib/CodeGen/TargetLoweringObjectFileImpl.cpp =================================================================== --- lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -93,6 +93,24 @@ 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(Operand)->getNumOperands() != 2) + report_fatal_error("invalid llvm.linker.options"); + for (const auto &Option : cast(Operand)->operands()) { + Streamer.EmitBytes(cast(Option)->getString()); + Streamer.EmitIntValue(0, 1); + } + } + } + unsigned Version = 0; unsigned Flags = 0; StringRef Section; @@ -101,7 +119,6 @@ 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"))); Index: lib/MC/MCParser/ELFAsmParser.cpp =================================================================== --- lib/MC/MCParser/ELFAsmParser.cpp +++ lib/MC/MCParser/ELFAsmParser.cpp @@ -608,6 +608,8 @@ 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"); } Index: lib/MC/MCSectionELF.cpp =================================================================== --- lib/MC/MCSectionELF.cpp +++ lib/MC/MCSectionELF.cpp @@ -148,6 +148,8 @@ 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()); Index: lib/Object/ELF.cpp =================================================================== --- lib/Object/ELF.cpp +++ lib/Object/ELF.cpp @@ -205,6 +205,7 @@ 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); Index: lib/ObjectYAML/ELFYAML.cpp =================================================================== --- lib/ObjectYAML/ELFYAML.cpp +++ lib/ObjectYAML/ELFYAML.cpp @@ -408,6 +408,7 @@ 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); Index: test/Feature/elf-linker-options.ll =================================================================== --- /dev/null +++ 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 Index: test/MC/ELF/section.s =================================================================== --- test/MC/ELF/section.s +++ test/MC/ELF/section.s @@ -279,3 +279,17 @@ // 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: } + Index: test/tools/llvm-readobj/elf-linker-options.ll =================================================================== --- /dev/null +++ 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: ] Index: tools/llvm-readobj/ELFDumper.cpp =================================================================== --- tools/llvm-readobj/ELFDumper.cpp +++ tools/llvm-readobj/ELFDumper.cpp @@ -164,6 +164,8 @@ void printNotes() override; + void printELFLinkerOptions() override; + private: std::unique_ptr> ELFDumperStyle; @@ -316,6 +318,7 @@ virtual void printProgramHeaders(const ELFFile *Obj) = 0; virtual void printHashHistogram(const ELFFile *Obj) = 0; virtual void printNotes(const ELFFile *Obj) = 0; + virtual void printELFLinkerOptions(const ELFFile *Obj) = 0; virtual void printMipsGOT(const MipsGOTParser &Parser) = 0; virtual void printMipsPLT(const MipsGOTParser &Parser) = 0; const ELFDumper *dumper() const { return Dumper; } @@ -345,6 +348,7 @@ void printProgramHeaders(const ELFO *Obj) override; void printHashHistogram(const ELFFile *Obj) override; void printNotes(const ELFFile *Obj) override; + void printELFLinkerOptions(const ELFFile *Obj) override; void printMipsGOT(const MipsGOTParser &Parser) override; void printMipsPLT(const MipsGOTParser &Parser) override; @@ -405,6 +409,7 @@ void printProgramHeaders(const ELFO *Obj) override; void printHashHistogram(const ELFFile *Obj) override; void printNotes(const ELFFile *Obj) override; + void printELFLinkerOptions(const ELFFile *Obj) override; void printMipsGOT(const MipsGOTParser &Parser) override; void printMipsPLT(const MipsGOTParser &Parser) override; @@ -1501,6 +1506,10 @@ ELFDumperStyle->printNotes(Obj); } +template void ELFDumper::printELFLinkerOptions() { + ELFDumperStyle->printELFLinkerOptions(Obj); +} + #define LLVM_READOBJ_TYPE_CASE(name) \ case DT_##name: return #name @@ -2694,6 +2703,8 @@ 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"; @@ -3554,6 +3565,11 @@ } } +template +void GNUStyle::printELFLinkerOptions(const ELFFile *Obj) { + OS << "printELFLinkerOptions not implemented!\n"; +} + template void GNUStyle::printMipsGOT(const MipsGOTParser &Parser) { size_t Bias = ELFT::Is64Bits ? 8 : 0; @@ -4062,6 +4078,27 @@ W.startLine() << "printNotes not implemented!\n"; } +template +void LLVMStyle::printELFLinkerOptions(const ELFFile *Obj) { + ListScope L(W, "LinkerOptions"); + + for (const Elf_Shdr &Shdr : unwrapOrError(Obj->sections())) { + if (Shdr.sh_type != ELF::SHT_LLVM_LINKER_OPTIONS) + continue; + + ArrayRef Contents = unwrapOrError(Obj->getSectionContents(&Shdr)); + for (const uint8_t *P = Contents.begin(), *E = Contents.end(); P < E; ) { + StringRef Key = StringRef(reinterpret_cast(P)); + StringRef Value = + StringRef(reinterpret_cast(P) + Key.size() + 1); + + W.printString(Key, Value); + + P = P + Key.size() + Value.size() + 2; + } + } +} + template void LLVMStyle::printMipsGOT(const MipsGOTParser &Parser) { auto PrintEntry = [&](const Elf_Addr *E) { Index: tools/llvm-readobj/ObjDumper.h =================================================================== --- tools/llvm-readobj/ObjDumper.h +++ tools/llvm-readobj/ObjDumper.h @@ -48,6 +48,7 @@ virtual void printGroupSections() {} virtual void printHashHistogram() {} virtual void printNotes() {} + virtual void printELFLinkerOptions() {} // Only implemented for ARM ELF at this time. virtual void printAttributes() { } Index: tools/llvm-readobj/llvm-readobj.cpp =================================================================== --- tools/llvm-readobj/llvm-readobj.cpp +++ tools/llvm-readobj/llvm-readobj.cpp @@ -229,6 +229,11 @@ COFFLoadConfig("coff-load-config", cl::desc("Display the PE/COFF load config")); + // -elf-linker-options + cl::opt + ELFLinkerOptions("elf-linker-options", + cl::desc("Display the ELF .linker-options section")); + // -macho-data-in-code cl::opt MachODataInCode("macho-data-in-code", @@ -419,6 +424,8 @@ if (opts::VersionInfo) Dumper->printVersionInfo(); if (Obj->isELF()) { + if (opts::ELFLinkerOptions) + Dumper->printELFLinkerOptions(); if (Obj->getArch() == llvm::Triple::arm) if (opts::ARMAttributes) Dumper->printAttributes();