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 = 0x2302, +}; + // 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,34 @@ 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()) { + std::string Directive; + for (const auto &Option : cast(Operand)->operands()) { + Directive.push_back(' '); + Directive.append(cast(Option)->getString()); + } + Directive.push_back('\0'); + DOS << Directive; + } + + Streamer.SwitchSection(getContext().getELFSection(".note.linker-options", + ELF::SHT_NOTE, 0)); + Streamer.EmitIntValue(5, 4); // namesz + Streamer.EmitIntValue(Descriptor.size() + 5, 4); // descsz + Streamer.EmitIntValue(ELF::NT_LLVM_LINKER_OPTIONS, 4); // type + Streamer.EmitBytes("LLVM"); // name + Streamer.EmitIntValue(0, 1); // null + Streamer.EmitValueToAlignment(4); // desc + Streamer.EmitIntValue(1, 4); // 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\000 nospace" +; CHECK: .byte 0 +; CHECK: .p2align 3 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) << ')'; }