Index: include/llvm/BinaryFormat/ELF.h =================================================================== --- include/llvm/BinaryFormat/ELF.h +++ include/llvm/BinaryFormat/ELF.h @@ -1380,6 +1380,10 @@ NT_GNU_GOLD_VERSION = 4, }; +enum { + NT_LLVM_LINKER_OPTIONS = 1, +}; + // AMDGPU specific notes. enum { // Note types with values between 0 and 9 (inclusive) are reserved. Index: lib/CodeGen/TargetLoweringObjectFileImpl.cpp =================================================================== --- lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -93,6 +93,31 @@ void TargetLoweringObjectFileELF::emitModuleMetadata( MCStreamer &Streamer, Module &M, const TargetMachine &TM) const { + if (NamedMDNode *LinkerOptions = M.getNamedMetadata("llvm.linker.options")) { + llvm::SmallString<128> Descriptor; + llvm::raw_svector_ostream DOS(Descriptor); + + for (const auto &Operand : LinkerOptions->operands()) + for (const auto &Option : cast(Operand)->operands()) + DOS << cast(Option)->getString() << '\0'; + + static const char Vendor[] = "LLVM"; + static const uint32_t Version = 1; + Streamer.SwitchSection(getContext().getELFSection(".note.linker-options", + ELF::SHT_NOTE, 0)); + Streamer.EmitIntValue(sizeof(Vendor), 4); // namesz + // The payload is the version (4 bytes), options (n bytes), null (1 byte) + Streamer.EmitIntValue(sizeof(Version) + Descriptor.size() + 1, 4); // descsz + Streamer.EmitIntValue(ELF::NT_LLVM_LINKER_OPTIONS, 4); // type + Streamer.EmitBytes(Vendor); // name + Streamer.EmitIntValue(0, 1); // null + Streamer.EmitValueToAlignment(4); // desc + Streamer.EmitIntValue(Version, sizeof(Version)); // version + Streamer.EmitBytes(DOS.str().str()); // option array + Streamer.EmitIntValue(0, 1); // null + Streamer.EmitValueToAlignment(4); + } + unsigned Version = 0; unsigned Flags = 0; StringRef Section; Index: test/Feature/elf-linker-options.ll =================================================================== --- /dev/null +++ test/Feature/elf-linker-options.ll @@ -0,0 +1,19 @@ +; RUN: llc -mtriple i686-unknown-linux-gnu -filetype asm -o - %s | FileCheck %s +; RUN: llc -mtriple x86_64-unknown-linux-gnu -filetype asm -o - %s | FileCheck %s + +!llvm.linker.options = !{!0, !1} + +!0 = !{!"spaced option"} +!1 = !{!"nospace"} + +; CHECK: .section ".note.linker-options","",@note +; CHECK: .long 5 +; CHECK: .long 29 +; CHECK: .long 8962 +; CHECK: .ascii "LLVM" +; CHECK: .byte 0 +; CHECK: .p2align 2 +; CHECK: .long 1 +; CHECK: .asciz "spaced option\000nospace" +; CHECK: .byte 0 +; CHECK: .p2align 2 Index: test/tools/llvm-readobj/elf-directives.test =================================================================== --- /dev/null +++ test/tools/llvm-readobj/elf-directives.test @@ -0,0 +1,24 @@ +# RUN: yaml2obj %s > %t.o +# RUN: llvm-readobj -elf-output-style GNU --notes %t.o | FileCheck %s + +# CHECK: Displaying notes found at file offset 0x00000180 with length 0x00000030: +# CHECK: Owner Data size Description +# CHECK: LLVM 0x0000001b NT_LLVM_LINKER_OPTIONS (linker options) +# CHECK: Linker Options: +# CHECK: Version: 1 +# CHECK: Options: +# CHECK: spaced option +# CHECK: nospace + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .note.linker-options + Type: SHT_NOTE + AddressAlign: 0x0000000000000004 + Content: 050000001B000000010000004C4C564D0000000001000000737061636564206F7074696F6E006E6F7370616365000000 +... Index: tools/llvm-readobj/ELFDumper.cpp =================================================================== --- tools/llvm-readobj/ELFDumper.cpp +++ tools/llvm-readobj/ELFDumper.cpp @@ -3460,6 +3460,24 @@ return OS.str(); } +static std::string getLLVMNoteTypeName(const uint32_t NT) { + static const struct { + uint32_t ID; + const char *Name; + } Notes[] = { + {ELF::NT_LLVM_LINKER_OPTIONS, "NT_LLVM_LINKER_OPTIONS (linker options)"}, + }; + + for (const auto &Note : Notes) + if (Note.ID == NT) + return std::string(Note.Name); + + std::string string; + raw_string_ostream OS(string); + OS << format("Unknown note type (0x%08x)", NT); + return OS.str(); +} + template static void printGNUNote(raw_ostream &OS, uint32_t NoteType, ArrayRef::Elf_Word> Words, @@ -3533,6 +3551,27 @@ OS.flush(); } +template +static void printLLVMNote(raw_ostream &OS, uint32_t NoteType, + ArrayRef::Elf_Word> Words, + size_t Size) { + switch (NoteType) { + default: return; + case ELF::NT_LLVM_LINKER_OPTIONS: + OS << " Linker Options:\n" + << " Version: " << Words[0] << '\n' + << " Options:\n"; + const char *Option = reinterpret_cast(&Words[1]); + while (*Option) { + StringRef OR(Option); + OS << " " << OR << '\n'; + Option = Option + OR.size() + 1; + } + break; + } + OS.flush(); +} + template void GNUStyle::printNotes(const ELFFile *Obj) { const Elf_Ehdr *e = Obj->getHeader(); @@ -3576,6 +3615,9 @@ } else if (Name == "AMD") { OS << getAMDGPUNoteTypeName(Type) << '\n'; printAMDGPUNote(OS, Type, Descriptor, DescriptorSize); + } else if (Name == "LLVM") { + OS << getLLVMNoteTypeName(Type) << '\n'; + printLLVMNote(OS, Type, Descriptor, DescriptorSize); } else { OS << "Unknown note type: (" << format_hex(Type, 10) << ')'; }