Index: clang/lib/CodeGen/CodeGenModule.h =================================================================== --- clang/lib/CodeGen/CodeGenModule.h +++ clang/lib/CodeGen/CodeGenModule.h @@ -465,9 +465,12 @@ /// have been emitted. llvm::SmallPtrSet EmittedModuleInitializers; - /// A vector of metadata strings. + /// A vector of metadata strings for linker options. SmallVector LinkerOptionsMetadata; + /// A vector of metadata strings for dependent libraries for ELF. + SmallVector ELFDependentLibs; + /// @name Cache for Objective-C runtime types /// @{ @@ -1152,11 +1155,9 @@ /// Appends a detect mismatch command to the linker options. void AddDetectMismatch(StringRef Name, StringRef Value); - /// Appends a dependent lib to the "llvm.linker.options" metadata - /// value. + /// Appends a dependent lib to the appropriate metadata value. void AddDependentLib(StringRef Lib); - void AddELFLibDirective(StringRef Lib); llvm::GlobalVariable::LinkageTypes getFunctionLinkage(GlobalDecl GD); Index: clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- clang/lib/CodeGen/CodeGenModule.cpp +++ clang/lib/CodeGen/CodeGenModule.cpp @@ -445,6 +445,14 @@ EmitModuleLinkOptions(); } + // On ELF we pass the dependent library specifiers + // directly to the linker without manipulating them. + if (!ELFDependentLibs.empty()) { + auto *NMD = getModule().getOrInsertNamedMetadata("llvm.deplibs"); + for (auto *MD : ELFDependentLibs) + NMD->addOperand(MD); + } + // Record mregparm value now so it is visible through rest of codegen. if (Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86) getModule().addModuleFlag(llvm::Module::Error, "NumRegisterParameters", @@ -1690,17 +1698,18 @@ LinkerOptionsMetadata.push_back(llvm::MDNode::get(getLLVMContext(), MDOpts)); } -void CodeGenModule::AddELFLibDirective(StringRef Lib) { - auto &C = getLLVMContext(); - LinkerOptionsMetadata.push_back(llvm::MDNode::get( - C, {llvm::MDString::get(C, "lib"), llvm::MDString::get(C, Lib)})); -} - void CodeGenModule::AddDependentLib(StringRef Lib) { + auto &C = getLLVMContext(); + if (getTarget().getTriple().isOSBinFormatELF()) { + ELFDependentLibs.push_back( + llvm::MDNode::get(C, llvm::MDString::get(C, Lib))); + return; + } + llvm::SmallString<24> Opt; getTargetCodeGenInfo().getDependentLibraryOption(Lib, Opt); auto *MDOpts = llvm::MDString::get(getLLVMContext(), Opt); - LinkerOptionsMetadata.push_back(llvm::MDNode::get(getLLVMContext(), MDOpts)); + LinkerOptionsMetadata.push_back(llvm::MDNode::get(C, MDOpts)); } /// Add link options implied by the given module, including modules @@ -1723,7 +1732,6 @@ // described by this module. llvm::LLVMContext &Context = CGM.getLLVMContext(); bool IsELF = CGM.getTarget().getTriple().isOSBinFormatELF(); - bool IsPS4 = CGM.getTarget().getTriple().isPS4(); // For modules that use export_as for linking, use that module // name instead. @@ -1743,7 +1751,7 @@ } // Link against a library. - if (IsELF && !IsPS4) { + if (IsELF) { llvm::Metadata *Args[2] = { llvm::MDString::get(Context, "lib"), llvm::MDString::get(Context, Mod->LinkLibraries[I - 1].Library), @@ -4973,10 +4981,6 @@ AppendLinkerOptions(PCD->getArg()); break; case PCK_Lib: - if (getTarget().getTriple().isOSBinFormatELF() && - !getTarget().getTriple().isPS4()) - AddELFLibDirective(PCD->getArg()); - else AddDependentLib(PCD->getArg()); break; case PCK_Compiler: Index: clang/lib/CodeGen/TargetInfo.cpp =================================================================== --- clang/lib/CodeGen/TargetInfo.cpp +++ clang/lib/CodeGen/TargetInfo.cpp @@ -2348,22 +2348,6 @@ } }; -class PS4TargetCodeGenInfo : public X86_64TargetCodeGenInfo { -public: - PS4TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, X86AVXABILevel AVXLevel) - : X86_64TargetCodeGenInfo(CGT, AVXLevel) {} - - void getDependentLibraryOption(llvm::StringRef Lib, - llvm::SmallString<24> &Opt) const override { - Opt = "\01"; - // If the argument contains a space, enclose it in quotes. - if (Lib.find(" ") != StringRef::npos) - Opt += "\"" + Lib.str() + "\""; - else - Opt += Lib; - } -}; - static std::string qualifyWindowsLibrary(llvm::StringRef Lib) { // If the argument does not end in .lib, automatically add the suffix. // If the argument contains a space, enclose it in quotes. @@ -9492,8 +9476,6 @@ switch (Triple.getOS()) { case llvm::Triple::Win32: return SetCGInfo(new WinX86_64TargetCodeGenInfo(Types, AVXLevel)); - case llvm::Triple::PS4: - return SetCGInfo(new PS4TargetCodeGenInfo(Types, AVXLevel)); default: return SetCGInfo(new X86_64TargetCodeGenInfo(Types, AVXLevel)); } Index: clang/test/CodeGen/dependent-lib.c =================================================================== --- clang/test/CodeGen/dependent-lib.c +++ clang/test/CodeGen/dependent-lib.c @@ -1,12 +1,12 @@ // RUN: %clang_cc1 %s --dependent-lib=msvcrt -triple thumbv7-windows -emit-llvm -o - | FileCheck %s // RUN: %clang_cc1 %s --dependent-lib=msvcrt -triple i686-pc-win32 -emit-llvm -o - | FileCheck %s // RUN: %clang_cc1 %s --dependent-lib=msvcrt -triple x86_64-pc-win32 -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 %s --dependent-lib=msvcrt -triple i686-pc-linux -emit-llvm -o - | FileCheck -check-prefix LINUX %s +// RUN: %clang_cc1 %s --dependent-lib=msvcrt -triple i686-pc-linux -emit-llvm -o - | FileCheck -check-prefix LINUX %s --implicit-check-not llvm.linker.options // CHECK: !llvm.linker.options = !{![[msvcrt:[0-9]+]]} // CHECK: ![[msvcrt]] = !{!"/DEFAULTLIB:msvcrt.lib"} -// LINUX: !llvm.linker.options = !{![[msvcrt:[0-9]+]]} -// LINUX: ![[msvcrt]] = !{!"-lmsvcrt"} +// LINUX: !llvm.deplibs = !{![[msvcrt:[0-9]+]]} +// LINUX: ![[msvcrt]] = !{!"msvcrt"} int f(); Index: clang/test/CodeGen/elf-linker-options.c =================================================================== --- clang/test/CodeGen/elf-linker-options.c +++ /dev/null @@ -1,7 +0,0 @@ -// RUN: %clang_cc1 -triple i686---elf -emit-llvm %s -o - | FileCheck %s - -#pragma comment(lib, "alpha") - -// CHECK: !llvm.linker.options = !{[[NODE:![0-9]+]]} -// CHECK: [[NODE]] = !{!"lib", !"alpha"} - Index: clang/test/CodeGen/pragma-comment.c =================================================================== --- clang/test/CodeGen/pragma-comment.c +++ clang/test/CodeGen/pragma-comment.c @@ -1,9 +1,9 @@ // RUN: %clang_cc1 %s -triple i686-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s // RUN: %clang_cc1 %s -triple thumbv7-windows -fms-extensions -emit-llvm -o - | FileCheck %s // RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 %s -triple thumbv7-linux-gnueabihf -fms-extensions -emit-llvm -o - | FileCheck -check-prefix LINUX %s -// RUN: %clang_cc1 %s -triple i686-pc-linux -fms-extensions -emit-llvm -o - | FileCheck -check-prefix LINUX %s -// RUN: %clang_cc1 %s -triple x86_64-scei-ps4 -fms-extensions -emit-llvm -o - | FileCheck -check-prefix PS4 %s +// RUN: %clang_cc1 %s -triple thumbv7-linux-gnueabihf -fms-extensions -emit-llvm -o - | FileCheck -check-prefix ELF %s --implicit-check-not llvm.linker.options +// RUN: %clang_cc1 %s -triple i686-pc-linux -fms-extensions -emit-llvm -o - | FileCheck -check-prefix ELF %s --implicit-check-not llvm.linker.options +// RUN: %clang_cc1 %s -triple x86_64-scei-ps4 -fms-extensions -emit-llvm -o - | FileCheck -check-prefix ELF %s --implicit-check-not llvm.linker.options // RUN: %clang_cc1 %s -triple aarch64-windows-msvc -fms-extensions -emit-llvm -o - | FileCheck %s #pragma comment(lib, "msvcrt.lib") @@ -23,11 +23,10 @@ // CHECK: ![[bar]] = !{!" /bar=2"} // CHECK: ![[foo]] = !{!" /foo=\22foo bar\22"} -// LINUX: !{!"lib", !"msvcrt.lib"} -// LINUX: !{!"lib", !"kernel32"} -// LINUX: !{!"lib", !"USER32.LIB"} - -// PS4: !{!"\01msvcrt.lib"} -// PS4: !{!"\01kernel32"} -// PS4: !{!"\01USER32.LIB"} -// PS4: !{!"\01\22with space\22"} +// ELF: !llvm.deplibs = !{![[msvcrt:[0-9]+]], ![[kernel32:[0-9]+]], ![[USER32:[0-9]+]], ![[space:[0-9]+]] +// ELF: ![[msvcrt]] = !{!"msvcrt.lib"} +// ELF: ![[kernel32]] = !{!"kernel32"} +// ELF: ![[USER32]] = !{!"USER32.LIB"} +// ELF: ![[space]] = !{!"with space"} +// ELF-NOT: bar +// ELF-NOT: foo Index: clang/test/Modules/autolink.m =================================================================== --- clang/test/Modules/autolink.m +++ clang/test/Modules/autolink.m @@ -37,9 +37,9 @@ // NOTE: "autolink_sub" is intentionally not linked. // CHECK: !llvm.linker.options = !{![[AUTOLINK_PCH:[0-9]+]], ![[AUTOLINK_FRAMEWORK:[0-9]+]], ![[AUTOLINK:[0-9]+]], ![[DEPENDSONMODULE:[0-9]+]], ![[MODULE:[0-9]+]], ![[NOUMBRELLA:[0-9]+]]} -// CHECK: ![[AUTOLINK_PCH]] = !{!"{{(\\01|-l|/DEFAULTLIB:|lib", !")}}autolink_from_pch{{(\.lib)?}}"} +// CHECK: ![[AUTOLINK_PCH]] = !{!"{{(-l|/DEFAULTLIB:|lib", !")}}autolink_from_pch{{(\.lib)?}}"} // CHECK: ![[AUTOLINK_FRAMEWORK]] = !{!"-framework", !"autolink_framework"} -// CHECK: ![[AUTOLINK]] = !{!"{{(\\01|-l|/DEFAULTLIB:|lib", !")}}autolink{{(\.lib)?}}"} +// CHECK: ![[AUTOLINK]] = !{!"{{(-l|/DEFAULTLIB:|lib", !")}}autolink{{(\.lib)?}}"} // CHECK: ![[DEPENDSONMODULE]] = !{!"-framework", !"DependsOnModule"} // CHECK: ![[MODULE]] = !{!"-framework", !"Module"} // CHECK: ![[NOUMBRELLA]] = !{!"-framework", !"NoUmbrella"} Index: lld/ELF/Config.h =================================================================== --- lld/ELF/Config.h +++ lld/ELF/Config.h @@ -121,6 +121,7 @@ llvm::MapVector, uint64_t> CallGraphProfile; + bool DepLibs; bool AllowMultipleDefinition; bool AllowShlibUndefined; bool AndroidPackDynRelocs; Index: lld/ELF/Driver.cpp =================================================================== --- lld/ELF/Driver.cpp +++ lld/ELF/Driver.cpp @@ -760,6 +760,7 @@ Args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false); ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true); + Config->DepLibs = !Args.hasArg(OPT_ignore_deplibs); Config->AllowMultipleDefinition = Args.hasFlag(OPT_allow_multiple_definition, OPT_no_allow_multiple_definition, false) || @@ -1493,9 +1494,11 @@ Symtab->trace(Arg->getValue()); // Add all files to the symbol table. This will add almost all - // symbols that we need to the symbol table. - for (InputFile *F : Files) - Symtab->addFile(F); + // symbols that we need to the symbol table. This process might + // add files to the link, via autolinking, these files are always + // appended to the Files vector. + for (size_t I = 0u; I < Files.size(); ++I) + Symtab->addFile(Files[I]); // Now that we have every file, we can decide if we will need a // dynamic symbol table. Index: lld/ELF/InputFiles.cpp =================================================================== --- lld/ELF/InputFiles.cpp +++ lld/ELF/InputFiles.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "InputFiles.h" +#include "Driver.h" #include "InputSection.h" #include "LinkerScript.h" #include "SymbolTable.h" @@ -396,6 +397,18 @@ } } +static void processDepLib(StringRef Specifier, const InputFile *F) { + if (Config->DepLibs) + if (fs::exists(Specifier)) + Driver->addFile(Specifier, /*WithLOption=*/false); + else if (Optional S = findFromSearchPaths(Specifier)) + Driver->addFile(*S, /*WithLOption=*/true); + else if (Optional S = searchLibrary(Specifier)) + Driver->addFile(*S, /*WithLOption=*/true); + else + error(toString(F) + ": unable to find library from dependent library specifier: " + Specifier); +} + template void ObjFile::initializeSections( DenseSet &ComdatGroups) { @@ -637,6 +650,18 @@ } return &InputSection::Discarded; } + case SHT_LLVM_DEPLIBS: { + if (!Config->Relocatable) { + ArrayRef Contents = + CHECK(this->getObj().getSectionContents(&Sec), this); + for (const uint8_t *P = Contents.begin(), *E = Contents.end(); P < E;) { + StringRef A = reinterpret_cast(P); + processDepLib(A, this); + P += A.size() + 1; + } + return &InputSection::Discarded; + } + } case SHT_RELA: case SHT_REL: { // Find a relocation target section and associate this section with that. @@ -1186,6 +1211,9 @@ for (const lto::InputFile::Symbol &ObjSym : Obj->symbols()) Symbols.push_back(createBitcodeSymbol(KeptComdats, ObjSym, *this)); + + for (auto L : Obj->getDepLibs()) + processDepLib(L, this); } static ELFKind getELFKind(MemoryBufferRef MB, StringRef ArchiveName) { Index: lld/ELF/Options.td =================================================================== --- lld/ELF/Options.td +++ lld/ELF/Options.td @@ -59,6 +59,8 @@ defm Ttext: Eq<"Ttext", "Same as --section-start with .text as the sectionname">; +def ignore_deplibs: F<"ignore-deplibs">, HelpText<"Ignore dependent library specifiers from input files">; + defm allow_multiple_definition: B<"allow-multiple-definition", "Allow multiple definitions", "Do not allow multiple definitions (default)">; Index: lld/test/ELF/Inputs/deplibs-lib_bar.s =================================================================== --- /dev/null +++ lld/test/ELF/Inputs/deplibs-lib_bar.s @@ -0,0 +1,2 @@ + .global bar +bar: Index: lld/test/ELF/Inputs/deplibs-lib_foo.s =================================================================== --- /dev/null +++ lld/test/ELF/Inputs/deplibs-lib_foo.s @@ -0,0 +1,2 @@ + .global foo +foo: Index: lld/test/ELF/deplibs.s =================================================================== --- /dev/null +++ lld/test/ELF/deplibs.s @@ -0,0 +1,51 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/deplibs-lib_foo.s -o %tbar.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/deplibs-lib_bar.s -o %tfoo.o +# RUN: rm -rf %t.dir %t.cwd +# RUN: mkdir -p %t.dir + +# error if dependent libraries cannot be found +# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s -DOBJ=%t.o --check-prefix MISSING +# MISSING: error: [[OBJ]]: unable to find library from dependent library specifier: foo.a +# MISSING: error: [[OBJ]]: unable to find library from dependent library specifier: bar + +# can ignore dependent libraries +# RUN: not ld.lld %t.o -o /dev/null --ignore-deplibs 2>&1 | FileCheck %s --check-prefix IGNORE +# IGNORE: error: undefined symbol: foo +# IGNORE: error: undefined symbol: bar + +# static archives located relative to library search paths +# RUN: llvm-ar rc %t.dir/foo.a %tfoo.o +# RUN: llvm-ar rc %t.dir/libbar.a %tbar.o +# RUN: ld.lld %t.o -o /dev/null -L %t.dir + +# shared objects located relative to library search paths +# RUN: rm %t.dir/libbar.a +# RUN: ld.lld -shared -o %t.dir/libbar.so %tbar.o +# RUN: ld.lld -Bdynamic %t.o -o /dev/null -L %t.dir + +# dependent libraries searched for symbols after libraries on the command line +# RUN: mkdir -p %t.cwd +# RUN: cd %t.cwd +# RUN: cp %t.dir/foo.a %t.cwd/libcmdline.a +# RUN: ld.lld %t.o libcmdline.a -o /dev/null -L %t.dir --trace 2>&1 | FileCheck %s -DOBJ=%t.o -DSO=%t.dir --check-prefix CMDLINE --implicit-check-not foo.a +# CMDLINE: [[OBJ]] +# CMDLINE-NEXT: {{^libcmdline\.a}} +# CMDLINE-NEXT: [[SO]]{{[\\/]}}libbar.so + +# libraries can be found from specifiers as if the specifiers were listed on on the command-line. +# RUN: cp %t.dir/foo.a %t.cwd/foo.a +# RUN: ld.lld %t.o -o /dev/null -L %t.dir --trace 2>&1 | FileCheck %s -DOBJ=%t.o -DSO=%t.dir --check-prefix ASIFCMDLINE --implicit-check-not foo.a +# ASIFCMDLINE: [[OBJ]] +# ASIFCMDLINE-NEXT: {{^foo\.a}} +# ASIFCMDLINE-NEXT: [[SO]]{{[\\/]}}libbar.so + + .global _start +_start: + call foo + call bar + .section ".deplibs","MS",@llvm_deplibs,1 + .asciz "foo.a" + .asciz "bar" Index: lld/test/ELF/lto/deplibs.s =================================================================== --- /dev/null +++ lld/test/ELF/lto/deplibs.s @@ -0,0 +1,15 @@ +; REQUIRES: x86 + +; RUN: llvm-as %s -o %t.o +; RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s -DOBJ=%t.o + +; CHECK: error: [[OBJ]]: unable to find library from dependent library specifier: foo +; CHECK: error: [[OBJ]]: unable to find library from dependent library specifier: bar + +target triple = "x86_64-unknown-linux-gnu" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +!llvm.deplibs = !{!0, !1} + +!0 = !{!"foo"} +!1 = !{!"bar"} Index: llvm/docs/Extensions.rst =================================================================== --- llvm/docs/Extensions.rst +++ llvm/docs/Extensions.rst @@ -285,6 +285,26 @@ The paramter identifies an additional library search path to be considered when looking up libraries after the inclusion of this option. +``SHT_LLVM_DEPLIBS`` Section (Dependent Libraries) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This section allows for embedding a set of strings specifing libraries to be +added to the link by the linker. + +The section should be consumed by the linker and not written to the output. + +The strings are encoded as standard null-terminated UTF-8 strings. + +For example: + +.. code-block:: gas + + .section ".deplibs","MS",@llvm_deplibs,1 + .asciz "library specifier 1" + .asciz "library specifier 2" + +The interpretation of the library specifiers is defined by the consuming linker. + ``SHT_LLVM_CALL_GRAPH_PROFILE`` Section (Call Graph Profile) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Index: llvm/docs/LangRef.rst =================================================================== --- llvm/docs/LangRef.rst +++ llvm/docs/LangRef.rst @@ -6083,8 +6083,8 @@ Some targets support embedding flags to the linker inside individual object files. Typically this is used in conjunction with language extensions which -allow source files to explicitly declare the libraries they depend on, and have -these automatically be transmitted to the linker via object files. +allow source files to contain linker command line options, and have these +automatically be transmitted to the linker via object files. These flags are encoded in the IR using named metadata with the name ``!llvm.linker.options``. Each operand is expected to be a metadata node @@ -6095,8 +6095,8 @@ linker options, presumably to link against ``libz`` and the ``Cocoa`` framework:: - !0 = !{ !"-lz" }, - !1 = !{ !"-framework", !"Cocoa" } } } + !0 = !{ !"-lz" } + !1 = !{ !"-framework", !"Cocoa" } !llvm.linker.options = !{ !0, !1 } The metadata encoding as lists of lists of options, as opposed to a collapsed @@ -6109,6 +6109,28 @@ linker, or an option that is reserved by the target specific assembly writer or object file emitter. No other aspect of these options is defined by the IR. +Dependent Libs Named Metadata +============================= + +Some targets support embedding of strings into object files to indicate +a set of libraries to add to the link. Typically this is used in conjunction +with language extensions which allow source files to explicitly declare the +libraries they depend on, and have these automatically be transmitted to the +linker via object files. + +The list is encoded in the IR using named metadata with the name +``!llvm.deplibs``. Each operand is expected to be a metadata node which should +contain a single string operand. + +For example, the following metadata section contains two library specfiers:: + + !0 = !{!"a library specifier"} + !1 = !{!"another library specifier"} + !llvm.deplibs = !{ !0, !1 } + +Each library specifier will be handled independently by the consuming linker. +The effect of the library specifiers are defined by the consuming linker. + .. _summary: ThinLTO Summary Index: llvm/include/llvm-c/lto.h =================================================================== --- llvm/include/llvm-c/lto.h +++ llvm/include/llvm-c/lto.h @@ -44,7 +44,7 @@ * @{ */ -#define LTO_API_VERSION 23 +#define LTO_API_VERSION 24 /** * \since prior to LTO_API_VERSION=3 @@ -297,6 +297,14 @@ extern const char* lto_module_get_linkeropts(lto_module_t mod); +/** +* Returns the module's dependent library specifiers. +* +* \since LTO_API_VERSION=24 +*/ +extern const char* +lto_module_get_deplibs(lto_module_t mod); + /** * Diagnostic severity. * Index: llvm/include/llvm/BinaryFormat/ELF.h =================================================================== --- llvm/include/llvm/BinaryFormat/ELF.h +++ llvm/include/llvm/BinaryFormat/ELF.h @@ -838,6 +838,7 @@ SHT_LLVM_CALL_GRAPH_PROFILE = 0x6fff4c02, // LLVM Call Graph Profile. SHT_LLVM_ADDRSIG = 0x6fff4c03, // List of address-significant symbols // for safe ICF. + SHT_LLVM_DEPLIBS = 0x6fff4c04, // LLVM Dependent Library Specifiers. // Android's experimental support for SHT_RELR sections. // https://android.googlesource.com/platform/bionic/+/b7feec74547f84559a1467aca02708ff61346d2a/libc/include/elf.h#512 SHT_ANDROID_RELR = 0x6fffff00, // Relocation entries; only offsets. Index: llvm/include/llvm/LTO/LTO.h =================================================================== --- llvm/include/llvm/LTO/LTO.h +++ llvm/include/llvm/LTO/LTO.h @@ -110,6 +110,7 @@ std::vector> ModuleSymIndices; StringRef TargetTriple, SourceFileName, COFFLinkerOpts; + std::vector DepLibs; std::vector ComdatTable; public: @@ -149,6 +150,9 @@ /// Returns linker options specified in the input file. StringRef getCOFFLinkerOpts() const { return COFFLinkerOpts; } + /// Returns dependent library specifiers from the input file. + ArrayRef getDepLibs() const { return DepLibs; } + /// Returns the path to the InputFile. StringRef getName() const; Index: llvm/include/llvm/LTO/legacy/LTOModule.h =================================================================== --- llvm/include/llvm/LTO/legacy/LTOModule.h +++ llvm/include/llvm/LTO/legacy/LTOModule.h @@ -47,6 +47,8 @@ std::string LinkerOpts; + std::string DepLibs; + std::unique_ptr Mod; MemoryBufferRef MBRef; ModuleSymbolTable SymTab; @@ -153,6 +155,8 @@ StringRef getLinkerOpts() { return LinkerOpts; } + StringRef getDepLibs() { return DepLibs; } + const std::vector &getAsmUndefinedRefs() { return _asm_undefines; } private: Index: llvm/include/llvm/Object/IRSymtab.h =================================================================== --- llvm/include/llvm/Object/IRSymtab.h +++ llvm/include/llvm/Object/IRSymtab.h @@ -125,6 +125,11 @@ Str SectionName; }; +/// Dependent Library Specifiers +struct DepLib { + Str Specifier; +}; + struct Header { /// Version number of the symtab format. This number should be incremented /// when the format changes, but it does not need to be incremented if a @@ -147,6 +152,9 @@ /// COFF-specific: linker directives. Str COFFLinkerOpts; + +/// Dependent Library Specifiers + Range DepLibs; }; } // end namespace storage @@ -231,6 +239,7 @@ ArrayRef Comdats; ArrayRef Symbols; ArrayRef Uncommons; + ArrayRef DepLibs; StringRef str(storage::Str S) const { return S.get(Strtab); } @@ -251,6 +260,7 @@ Comdats = range(header().Comdats); Symbols = range(header().Symbols); Uncommons = range(header().Uncommons); + DepLibs = range(header().DepLibs); } using symbol_range = iterator_range>; @@ -283,6 +293,16 @@ /// COFF-specific: returns linker options specified in the input file. StringRef getCOFFLinkerOpts() const { return str(header().COFFLinkerOpts); } + + /// Returns dependent library specifiers + std::vector getDepLibs() const { + std::vector Specifiers; + Specifiers.reserve(DepLibs.size()); + for (auto L : DepLibs) { + Specifiers.push_back(str(L.Specifier)); + } + return Specifiers; + } }; /// Ephemeral symbols produced by Reader::symbols() and Index: llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp =================================================================== --- llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -271,6 +271,19 @@ } } + if (NamedMDNode *llvmDepLibs = M.getNamedMetadata("llvm.deplibs")) { + auto *S = C.getELFSection(".deplibs", ELF::SHT_LLVM_DEPLIBS, + ELF::SHF_MERGE | ELF::SHF_STRINGS, 1, ""); + + Streamer.SwitchSection(S); + + for (const auto &Operand : llvmDepLibs->operands()) { + Streamer.EmitBytes( + cast(cast(Operand)->getOperand(0))->getString()); + Streamer.EmitIntValue(0, 1); + } + } + unsigned Version = 0; unsigned Flags = 0; StringRef Section; Index: llvm/lib/LTO/LTO.cpp =================================================================== --- llvm/lib/LTO/LTO.cpp +++ llvm/lib/LTO/LTO.cpp @@ -398,6 +398,7 @@ File->TargetTriple = FOrErr->TheReader.getTargetTriple(); File->SourceFileName = FOrErr->TheReader.getSourceFileName(); File->COFFLinkerOpts = FOrErr->TheReader.getCOFFLinkerOpts(); + File->DepLibs = FOrErr->TheReader.getDepLibs(); File->ComdatTable = FOrErr->TheReader.getComdatTable(); for (unsigned I = 0; I != FOrErr->Mods.size(); ++I) { Index: llvm/lib/LTO/LTOModule.cpp =================================================================== --- llvm/lib/LTO/LTOModule.cpp +++ llvm/lib/LTO/LTOModule.cpp @@ -646,5 +646,14 @@ emitLinkerFlagsForGlobalCOFF(OS, Sym.symbol, TT, M); } - // Add other interesting metadata here. + // Dependent Libraries + raw_string_ostream OSD(DepLibs); + if (NamedMDNode *DepLibs = + getModule().getNamedMetadata("llvm.deplibs")) { + for (unsigned i = 0, e = DepLibs->getNumOperands(); i != e; ++i) { + MDNode *MDOptions = DepLibs->getOperand(i); + + OSD << " " << cast(MDOptions->getOperand(0))->getString(); + } + } } Index: llvm/lib/MC/MCParser/ELFAsmParser.cpp =================================================================== --- llvm/lib/MC/MCParser/ELFAsmParser.cpp +++ llvm/lib/MC/MCParser/ELFAsmParser.cpp @@ -615,6 +615,8 @@ Type = ELF::SHT_LLVM_LINKER_OPTIONS; else if (TypeName == "llvm_call_graph_profile") Type = ELF::SHT_LLVM_CALL_GRAPH_PROFILE; + else if (TypeName == "llvm_deplibs") + Type = ELF::SHT_LLVM_DEPLIBS; else if (TypeName.getAsInteger(0, Type)) return TokError("unknown section type"); } Index: llvm/lib/MC/MCSectionELF.cpp =================================================================== --- llvm/lib/MC/MCSectionELF.cpp +++ llvm/lib/MC/MCSectionELF.cpp @@ -152,6 +152,8 @@ OS << "llvm_linker_options"; else if (Type == ELF::SHT_LLVM_CALL_GRAPH_PROFILE) OS << "llvm_call_graph_profile"; + else if (Type == ELF::SHT_LLVM_DEPLIBS) + OS << "llvm_deplibs"; else report_fatal_error("unsupported type 0x" + Twine::utohexstr(Type) + " for section " + getSectionName()); Index: llvm/lib/Object/ELF.cpp =================================================================== --- llvm/lib/Object/ELF.cpp +++ llvm/lib/Object/ELF.cpp @@ -253,6 +253,7 @@ STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_LINKER_OPTIONS); STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_CALL_GRAPH_PROFILE); STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_ADDRSIG); + STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_DEPLIBS); STRINGIFY_ENUM_CASE(ELF, SHT_GNU_ATTRIBUTES); STRINGIFY_ENUM_CASE(ELF, SHT_GNU_HASH); STRINGIFY_ENUM_CASE(ELF, SHT_GNU_verdef); Index: llvm/lib/Object/IRSymtab.cpp =================================================================== --- llvm/lib/Object/IRSymtab.cpp +++ llvm/lib/Object/IRSymtab.cpp @@ -89,6 +89,8 @@ std::string COFFLinkerOpts; raw_string_ostream COFFLinkerOptsOS{COFFLinkerOpts}; + std::vector DepLibs; + void setStr(storage::Str &S, StringRef Value) { S.Offset = StrtabBuilder.add(Value); S.Size = Value.size(); @@ -140,6 +142,20 @@ } } + if (TT.isOSBinFormatELF()) { + if (auto E = M->materializeMetadata()) + return E; + if (NamedMDNode *N = M->getNamedMetadata("llvm.deplibs")) { + for (MDNode *MDOptions : N->operands()) { + const auto OperandStr = + cast(cast(MDOptions)->getOperand(0))->getString(); + storage::DepLib L; + setStr(L.Specifier, OperandStr); + DepLibs.emplace_back(L); + } + } + } + for (ModuleSymbolTable::Symbol Msym : Msymtab.symbols()) if (Error Err = addSymbol(Msymtab, Used, Msym)) return Err; @@ -312,7 +328,7 @@ writeRange(Hdr.Comdats, Comdats); writeRange(Hdr.Symbols, Syms); writeRange(Hdr.Uncommons, Uncommons); - + writeRange(Hdr.DepLibs, DepLibs); *reinterpret_cast(Symtab.data()) = Hdr; return Error::success(); } Index: llvm/lib/ObjectYAML/ELFYAML.cpp =================================================================== --- llvm/lib/ObjectYAML/ELFYAML.cpp +++ llvm/lib/ObjectYAML/ELFYAML.cpp @@ -454,6 +454,7 @@ ECase(SHT_LLVM_LINKER_OPTIONS); ECase(SHT_LLVM_CALL_GRAPH_PROFILE); ECase(SHT_LLVM_ADDRSIG); + ECase(SHT_LLVM_DEPLIBS); ECase(SHT_GNU_ATTRIBUTES); ECase(SHT_GNU_HASH); ECase(SHT_GNU_verdef); Index: llvm/test/Feature/elf-deplibs.ll =================================================================== --- /dev/null +++ llvm/test/Feature/elf-deplibs.ll @@ -0,0 +1,15 @@ +; RUN: llc -mtriple x86_64-elf -filetype asm -o - %s | FileCheck %s +; REQUIRES: x86-registered-target + +!llvm.deplibs = !{!0, !1, !0} + +!0 = !{!"foo"} +!1 = !{!"b a r"} + +; CHECK: .section .deplibs,"MS",@llvm_deplibs,1 +; CHECK-NEXT: .ascii "foo" +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "b a r" +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "foo" +; CHECK-NEXT: .byte 0 Index: llvm/test/Feature/elf-linker-options.ll =================================================================== --- llvm/test/Feature/elf-linker-options.ll +++ llvm/test/Feature/elf-linker-options.ll @@ -1,17 +1,17 @@ -; RUN: llc -mtriple x86_64-elf -filetype asm -o - %s | FileCheck %s -; REQUIRES: x86-registered-target - -!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 +; RUN: llc -mtriple x86_64-elf -filetype asm -o - %s | FileCheck %s +; REQUIRES: x86-registered-target + +!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: llvm/test/LTO/Resolution/X86/symtab-elf.ll =================================================================== --- llvm/test/LTO/Resolution/X86/symtab-elf.ll +++ llvm/test/LTO/Resolution/X86/symtab-elf.ll @@ -9,6 +9,12 @@ !0 = !{!"/include:foo"} !llvm.linker.options = !{ !0 } +; CHECK: {{^dependent libraries: \"foo\" \"b a r\" \"baz\"$}} +!1 = !{!"foo"} +!2 = !{!"b a r"} +!3 = !{!"baz"} +!llvm.deplibs = !{!1, !2, !3} + @g1 = global i32 0 ; CHECK-NOT: fallback g1 Index: llvm/test/MC/ELF/section.s =================================================================== --- llvm/test/MC/ELF/section.s +++ llvm/test/MC/ELF/section.s @@ -293,3 +293,17 @@ // CHECK-NEXT: ] // CHECK: } +// Test SHT_LLVM_DEPLIBS + +.section .deplibs,"MS",@llvm_deplibs,1 +// ASM: .section .deplibs,"MS",@llvm_deplibs,1 + +// CHECK: Section { +// CHECK: Name: .deplibs +// CHECK-NEXT: Type: SHT_LLVM_DEPLIBS +// CHECK-NEXT: Flags [ +// CHECK-NEXT: SHF_MERGE +// CHECK-NEXT: SHF_STRINGS +// CHECK-NEXT: ] +// CHECK: } + Index: llvm/test/Object/X86/irsymtab.ll =================================================================== --- llvm/test/Object/X86/irsymtab.ll +++ llvm/test/Object/X86/irsymtab.ll @@ -9,7 +9,7 @@ ; BCA: blob data = '\x01\x00\x00\x00\x06\x00\x00\x00\x08\x00\x00\x00D\x00\x00\x00\x01\x00\x00\x00P\x00\x00\x00\x00\x00\x00\x00P\x00\x00\x00\x02\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x0E\x00\x00\x00\x18\x00\x00\x00&\x00\x00\x00\x0B\x00\x00\x001\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\xFF\xFF\xFF\xFF\x00$\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\xFF\xFF\xFF\xFF\x08$\x00\x00' +; BCA-NEXT: blob data = '\x01\x00\x00\x00\x06\x00\x00\x00\x08\x00\x00\x00L\x00\x00\x00\x01\x00\x00\x00X\x00\x00\x00\x00\x00\x00\x00X\x00\x00\x00\x02\x00\x00\x00\x88\x00\x00\x00\x00\x00\x00\x00\x0E\x00\x00\x00\x18\x00\x00\x00&\x00\x00\x00\x0B\x00\x00\x001\x00\x00\x00\x00\x00\x00\x00\x88\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\xFF\xFF\xFF\xFF\x00$\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\xFF\xFF\xFF\xFF\x08$\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00' ; BCA-NEXT: ; BCA-NEXT: blob data = 'foobarproducerx86_64-unknown-linux-gnuirsymtab.ll' @@ -19,6 +19,7 @@ ; SYMTAB-NEXT: producer: producer ; SYMTAB-NEXT: target triple: x86_64-unknown-linux-gnu ; SYMTAB-NEXT: source filename: irsymtab.ll +; SYMTAB-NEXT: {{^dependent libraries: \"foo\" \"bar\"$}} ; SYMTAB-NEXT: D------X foo ; SYMTAB-NEXT: DU-----X bar @@ -31,3 +32,8 @@ } declare void @bar() + +!llvm.deplibs = !{!0, !1} + +!0 = !{!"foo"} +!1 = !{!"bar"} Index: llvm/tools/llvm-lto2/llvm-lto2.cpp =================================================================== --- llvm/tools/llvm-lto2/llvm-lto2.cpp +++ llvm/tools/llvm-lto2/llvm-lto2.cpp @@ -360,6 +360,13 @@ if (TT.isOSBinFormatCOFF()) outs() << "linker opts: " << Input->getCOFFLinkerOpts() << '\n'; + if (TT.isOSBinFormatELF()) { + outs() << "dependent libraries:"; + for (auto L : Input->getDepLibs()) + outs() << " \"" << L << "\""; + outs() << '\n'; + } + std::vector ComdatTable = Input->getComdatTable(); for (const InputFile::Symbol &Sym : Input->symbols()) { switch (Sym.getVisibility()) { Index: llvm/tools/llvm-readobj/ELFDumper.cpp =================================================================== --- llvm/tools/llvm-readobj/ELFDumper.cpp +++ llvm/tools/llvm-readobj/ELFDumper.cpp @@ -2830,6 +2830,8 @@ return "LLVM_CALL_GRAPH_PROFILE"; case SHT_LLVM_ADDRSIG: return "LLVM_ADDRSIG"; + case SHT_LLVM_DEPLIBS: + return "LLVM_DEPLIBS"; // FIXME: Parse processor specific GNU attributes case SHT_GNU_ATTRIBUTES: return "ATTRIBUTES"; Index: llvm/tools/lto/lto.cpp =================================================================== --- llvm/tools/lto/lto.cpp +++ llvm/tools/lto/lto.cpp @@ -325,6 +325,10 @@ return unwrap(mod)->getLinkerOpts().data(); } +const char* lto_module_get_deplibs(lto_module_t mod) { + return unwrap(mod)->getDepLibs().data(); +} + void lto_codegen_set_diagnostic_handler(lto_code_gen_t cg, lto_diagnostic_handler_t diag_handler, void *ctxt) {