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 ELFDependentLibraries; + /// @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,19 @@ EmitModuleLinkOptions(); } + // On ELF we pass the dependent library specifiers directly to the linker + // without manipulating them. This is in contrast to other platforms where + // they are mapped to a specific linker option by the compiler. This + // difference is a result of the greater variety of ELF linkers and the fact + // that ELF linkers tend to handle libraries in a more complicated fashion + // than on other platforms. This forces us to defer handling the dependent + // libs to the linker. + if (!ELFDependentLibraries.empty()) { + auto *NMD = getModule().getOrInsertNamedMetadata("llvm.dependent-libraries"); + for (auto *MD : ELFDependentLibraries) + 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 +1703,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()) { + ELFDependentLibraries.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 +1737,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 +1756,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 +4986,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.dependent-libraries = !{![[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.dependent-libraries = !{![[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 @@ -136,6 +136,7 @@ bool Cref; bool DefineCommon; bool Demangle = true; + bool DependentLibraries; bool DisableVerify; bool EhFrameHdr; bool EmitLLVM; Index: lld/ELF/Driver.h =================================================================== --- lld/ELF/Driver.h +++ lld/ELF/Driver.h @@ -64,6 +64,7 @@ llvm::Optional findFromSearchPaths(StringRef Path); llvm::Optional searchScript(StringRef Path); +llvm::Optional searchLibraryBaseName(StringRef Path); llvm::Optional searchLibrary(StringRef Path); } // namespace elf Index: lld/ELF/Driver.cpp =================================================================== --- lld/ELF/Driver.cpp +++ lld/ELF/Driver.cpp @@ -778,6 +778,7 @@ Config->DefineCommon = Args.hasFlag(OPT_define_common, OPT_no_define_common, !Args.hasArg(OPT_relocatable)); Config->Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, true); + Config->DependentLibraries = Args.hasFlag(OPT_dependent_libraries, OPT_no_dependent_libraries, true); Config->DisableVerify = Args.hasArg(OPT_disable_verify); Config->Discard = getDiscard(Args); Config->DwoDir = Args.getLastArgValue(OPT_plugin_opt_dwo_dir_eq); @@ -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 = 0; 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/DriverUtils.cpp =================================================================== --- lld/ELF/DriverUtils.cpp +++ lld/ELF/DriverUtils.cpp @@ -217,12 +217,9 @@ return None; } -// This is for -lfoo. We'll look for libfoo.so or libfoo.a from +// This is for -l. We'll look for lib.so or lib.a from // search paths. -Optional elf::searchLibrary(StringRef Name) { - if (Name.startswith(":")) - return findFromSearchPaths(Name.substr(1)); - +Optional elf::searchLibraryBaseName(StringRef Name) { for (StringRef Dir : Config->SearchPaths) { if (!Config->Static) if (Optional S = findFile(Dir, "lib" + Name + ".so")) @@ -233,6 +230,13 @@ return None; } +// This is for -l. +Optional elf::searchLibrary(StringRef Name) { + if (Name.startswith(":")) + return findFromSearchPaths(Name.substr(1)); + return searchLibraryBaseName (Name); +} + // If a linker/version script doesn't exist in the current directory, we also // look for the script in the '-L' search paths. This matches the behaviour of // '-T', --version-script=, and linker script INPUT() command in ld.bfd. 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,27 @@ } } +// An ELF object file may contain a `.deplibs` section. If it exists, the +// section contains a list of library specifiers such as `m` for libm. This +// function resolves a given name by finding the first matching library checking +// the various ways that a library can be specified to LLD. This ELF extension +// is a form of autolinking and is called `dependent libraries`. It is currently +// unique to LLVM and lld. +static void addDependentLibrary(StringRef Specifier, const InputFile *F) { + if (!Config->DependentLibraries) + return; + if (fs::exists(Specifier)) + Driver->addFile(Specifier, /*WithLOption=*/false); + else if (Optional S = findFromSearchPaths(Specifier)) + Driver->addFile(*S, /*WithLOption=*/true); + else if (Optional S = searchLibraryBaseName(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 +659,24 @@ } return &InputSection::Discarded; } + case SHT_LLVM_DEPENDENT_LIBRARIES: { + if (Config->Relocatable) + break; + ArrayRef Data = + CHECK(this->getObj().template getSectionContentsAsArray(&Sec), this); + if (!Data.empty() && Data.back() != '\0') { + error(toString(this) + + ": corrupted dependent libraries section (unterminated string): " + + Name); + return &InputSection::Discarded; + } + for (const char *D = Data.begin(), *E = Data.end(); D < E;) { + StringRef S(D); + addDependentLibrary(S, this); + D += S.size() + 1; + } + return &InputSection::Discarded; + } case SHT_RELA: case SHT_REL: { // Find a relocation target section and associate this section with that. @@ -1186,6 +1226,9 @@ for (const lto::InputFile::Symbol &ObjSym : Obj->symbols()) Symbols.push_back(createBitcodeSymbol(KeptComdats, ObjSym, *this)); + + for (auto L : Obj->getDependentLibraries()) + addDependentLibrary(L, this); } static ELFKind getELFKind(MemoryBufferRef MB, StringRef ArchiveName) { Index: lld/ELF/Options.td =================================================================== --- lld/ELF/Options.td +++ lld/ELF/Options.td @@ -71,6 +71,10 @@ "Apply link-time values for dynamic relocations", "Do not apply link-time values for dynamic relocations (default)">; +defm dependent_libraries: B<"dependent-libraries", + "Process dependent library specifiers from input files (default)", + "Ignore dependent library specifiers from input files">; + defm as_needed: B<"as-needed", "Only set DT_NEEDED for shared libraries if used", "Always set DT_NEEDED for shared libraries (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-colon-prefix.s =================================================================== --- /dev/null +++ lld/test/ELF/deplibs-colon-prefix.s @@ -0,0 +1,15 @@ +# 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 %tfoo.o +# RUN: rm -rf %t.dir +# RUN: mkdir -p %t.dir +# RUN: llvm-ar rc %t.dir/foo.a %tfoo.o +# RUN: not ld.lld %t.o -o /dev/null -L %t.dir 2>&1 | FileCheck %s -DOBJ=%t.o +# CHECK: error: [[OBJ]]: unable to find library from dependent library specifier: :foo.a + + .global _start +_start: + call foo + .section ".deplibs","MS",@llvm_dependent_libraries,1 + .asciz ":foo.a" Index: lld/test/ELF/deplibs-corrupt.s =================================================================== --- /dev/null +++ lld/test/ELF/deplibs-corrupt.s @@ -0,0 +1,9 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: not ld.lld %t.o -o /dev/null -L %t.dir 2>&1 | FileCheck %s -DOBJ=%t.o +# CHECK: error: [[OBJ]]: corrupted dependent libraries section (unterminated string): .deplibs + +.section ".deplibs","MS",@llvm_dependent_libraries,1 + .ascii ":foo.a" + Index: lld/test/ELF/deplibs.s =================================================================== --- /dev/null +++ lld/test/ELF/deplibs.s @@ -0,0 +1,57 @@ +# 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 %tfoo.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/deplibs-lib_bar.s -o %tbar.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-NEXT: error: [[OBJ]]: unable to find library from dependent library specifier: bar + +# can ignore dependent libraries +# RUN: not ld.lld %t.o -o /dev/null --no-dependent-libraries 2>&1 | FileCheck %s --check-prefix IGNORE +# IGNORE: error: undefined symbol: foo +# IGNORE: error: undefined symbol: bar + +# -r links preserve dependent libraries +# RUN: ld.lld %t.o %t.o -r -o %t-r.o +# RUN: not ld.lld %t-r.o -o /dev/null 2>&1 | sort | FileCheck %s -DOBJ=%t-r.o --check-prefixes MINUSR +# MINUSR: error: [[OBJ]]: unable to find library from dependent library specifier: bar +# MINUSR-NEXT: error: [[OBJ]]: unable to find library from dependent library specifier: foo.a +# MINUSR-NOT: unable to find library from dependent library specifier + +# 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 + + call foo + call bar +.section ".deplibs","MS",@llvm_dependent_libraries,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.dependent-libraries = !{!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_DEPENDENT_LIBRARIES`` Section (Dependent Libraries) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This section contains strings specifying 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_dependent_libraries,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 @@ -6081,10 +6081,10 @@ Automatic Linker Flags Named Metadata ===================================== -Some targets support embedding flags to the linker inside individual object +Some targets support embedding of 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.dependent-libraries``. 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.dependent-libraries = !{ !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_dependent_libraries(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_DEPENDENT_LIBRARIES = 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 DependentLibraries; 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 getDependentLibraries() const { return DependentLibraries; } + /// 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 DependentLibraries; + std::unique_ptr Mod; MemoryBufferRef MBRef; ModuleSymbolTable SymTab; @@ -153,6 +155,8 @@ StringRef getLinkerOpts() { return LinkerOpts; } + StringRef getDependentLibraries() { return DependentLibraries; } + 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,12 +125,13 @@ Str SectionName; }; + 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 /// change to LLVM would cause it to create a different symbol table. Word Version; - enum { kCurrentVersion = 1 }; + enum { kCurrentVersion = 2 }; /// The producer's version string (LLVM_VERSION_STRING " " LLVM_REVISION). /// Consumers should rebuild the symbol table from IR if the producer's @@ -147,6 +148,9 @@ /// COFF-specific: linker directives. Str COFFLinkerOpts; + + /// Dependent Library Specifiers + Range DependentLibraries; }; } // end namespace storage @@ -231,6 +235,7 @@ ArrayRef Comdats; ArrayRef Symbols; ArrayRef Uncommons; + ArrayRef DependentLibraries; StringRef str(storage::Str S) const { return S.get(Strtab); } @@ -251,6 +256,7 @@ Comdats = range(header().Comdats); Symbols = range(header().Symbols); Uncommons = range(header().Uncommons); + DependentLibraries = range(header().DependentLibraries); } using symbol_range = iterator_range>; @@ -283,6 +289,16 @@ /// COFF-specific: returns linker options specified in the input file. StringRef getCOFFLinkerOpts() const { return str(header().COFFLinkerOpts); } + + /// Returns dependent library specifiers + std::vector getDependentLibraries() const { + std::vector Specifiers; + Specifiers.reserve(DependentLibraries.size()); + for (auto S : DependentLibraries) { + Specifiers.push_back(str(S)); + } + 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 *DependentLibraries = M.getNamedMetadata("llvm.dependent-libraries")) { + auto *S = C.getELFSection(".deplibs", ELF::SHT_LLVM_DEPENDENT_LIBRARIES, + ELF::SHF_MERGE | ELF::SHF_STRINGS, 1, ""); + + Streamer.SwitchSection(S); + + for (const auto &Operand : DependentLibraries->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->DependentLibraries = FOrErr->TheReader.getDependentLibraries(); 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,9 @@ emitLinkerFlagsForGlobalCOFF(OS, Sym.symbol, TT, M); } - // Add other interesting metadata here. + // Dependent Libraries + raw_string_ostream OSD(DependentLibraries); + if (NamedMDNode *DependentLibraries = getModule().getNamedMetadata("llvm.dependent-libraries")) + for (MDNode *N : DependentLibraries->operands()) + OSD << " " << cast(N->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_dependent_libraries") + Type = ELF::SHT_LLVM_DEPENDENT_LIBRARIES; 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_DEPENDENT_LIBRARIES) + OS << "llvm_dependent_libraries"; 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_DEPENDENT_LIBRARIES); 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 DependentLibraries; + 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.dependent-libraries")) { + for (MDNode *MDOptions : N->operands()) { + const auto OperandStr = + cast(cast(MDOptions)->getOperand(0))->getString(); + storage::Str Specifier; + setStr(Specifier, OperandStr); + DependentLibraries.emplace_back(Specifier); + } + } + } + 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.DependentLibraries, DependentLibraries); *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_DEPENDENT_LIBRARIES); 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.dependent-libraries = !{!0, !1, !0} + +!0 = !{!"foo"} +!1 = !{!"b a r"} + +; CHECK: .section .deplibs,"MS",@llvm_dependent_libraries,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/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.dependent-libraries = !{!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_DEPENDENT_LIBRARIES + +.section .deplibs,"MS",@llvm_dependent_libaries,1 +// ASM: .section .deplibs,"MS",@llvm_dependent_libaries,1 + +// CHECK: Section { +// CHECK: Name: .deplibs +// CHECK-NEXT: Type: SHT_LLVM_DEPENDENT_LIBRARIES +// 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,16 +9,17 @@ ; 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 = '\x02\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' ; BCA-NEXT: -; SYMTAB: version: 1 +; SYMTAB: version: 2 ; 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.dependent-libraries = !{!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->getDependentLibraries()) + 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_DEPENDENT_LIBRARIES: + return "LLVM_DEPENDENT_LIBRARIES"; // 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_dependent_libraries(lto_module_t mod) { + return unwrap(mod)->getDependentLibraries().data(); +} + void lto_codegen_set_diagnostic_handler(lto_code_gen_t cg, lto_diagnostic_handler_t diag_handler, void *ctxt) {