From 0a9756fc15c57dc94146e65d251d7a3d941ae78a Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 3 Oct 2022 08:31:23 -0700 Subject: [PATCH] [lld][WebAssemlby] Improve support for -L / -l and add testing - Add support -Bdynamic/-Bstatic and their aliases - Add support for `--library` and `--library-path` long form args - Add test based on test/ELF/libsearch.s - In `-Bdynamic` mode search for `.so` files in preference to `.a`. - Unlike ELF continue to default to static mode until `-pie` or `-shared` are used. Differential Revision: https://reviews.llvm.org/D135087 --- lld/test/wasm/Inputs/libsearch-dyn.s | 8 +++ lld/test/wasm/Inputs/libsearch-st.s | 9 ++++ lld/test/wasm/Inputs/use-bar.s | 2 + lld/test/wasm/libsearch.s | 99 ++++++++++++++++++++++++++++++++++++ lld/wasm/Config.h | 1 + lld/wasm/Driver.cpp | 51 +++++++++++++++---- lld/wasm/Options.td | 17 ++++++- 7 files changed, 175 insertions(+), 12 deletions(-) create mode 100644 lld/test/wasm/Inputs/libsearch-dyn.s create mode 100644 lld/test/wasm/Inputs/libsearch-st.s create mode 100644 lld/test/wasm/Inputs/use-bar.s create mode 100644 lld/test/wasm/libsearch.s diff --git a/lld/test/wasm/Inputs/libsearch-dyn.s b/lld/test/wasm/Inputs/libsearch-dyn.s new file mode 100644 index 0000000..bb59580 --- /dev/null +++ b/lld/test/wasm/Inputs/libsearch-dyn.s @@ -0,0 +1,8 @@ +.globl _bar,_dynamic + +.section .data,"",@ +_bar: +.size _bar,4 + +_dynamic: +.size _dynamic,4 diff --git a/lld/test/wasm/Inputs/libsearch-st.s b/lld/test/wasm/Inputs/libsearch-st.s new file mode 100644 index 0000000..dc5d89b --- /dev/null +++ b/lld/test/wasm/Inputs/libsearch-st.s @@ -0,0 +1,9 @@ +.globl _bar,_static + +.section .data,"",@ +_bar: +.int32 42 +.size _bar,4 + +_static: +.size _static,4 diff --git a/lld/test/wasm/Inputs/use-bar.s b/lld/test/wasm/Inputs/use-bar.s new file mode 100644 index 0000000..4ba20a0 --- /dev/null +++ b/lld/test/wasm/Inputs/use-bar.s @@ -0,0 +1,2 @@ +.section .bar,"",@ + .quad _bar diff --git a/lld/test/wasm/libsearch.s b/lld/test/wasm/libsearch.s new file mode 100644 index 0000000..2333651 --- /dev/null +++ b/lld/test/wasm/libsearch.s @@ -0,0 +1,99 @@ +// Based on lld/test/ELF/libsearch.s + +// RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown \ +// RUN: %p/Inputs/libsearch-dyn.s -o %tdyn.o +// RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown \ +// RUN: %p/Inputs/libsearch-st.s -o %tst.o +// RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown \ +// RUN: %p/Inputs/use-bar.s -o %tbar.o +// RUN: mkdir -p %t.dir +// RUN: wasm-ld -shared --experimental-pic %tdyn.o -o %t.dir/libls.so +// RUN: cp -f %t.dir/libls.so %t.dir/libls2.so +// RUN: rm -f %t.dir/libls.a +// RUN: llvm-ar rcs %t.dir/libls.a %tst.o + +// Should fail if no library specified +// RUN: not wasm-ld -l 2>&1 \ +// RUN: | FileCheck --check-prefix=NOLIBRARY %s +// NOLIBRARY: -l: missing argument + +// Should link normally, because _bar is not used +// RUN: wasm-ld -o %t3 %t.o +// Should not link because of undefined symbol _bar +// RUN: not wasm-ld --no-gc-sections -o /dev/null %t.o %tbar.o 2>&1 \ +// RUN: | FileCheck --check-prefix=UNDEFINED %s +// UNDEFINED: wasm-ld: error: {{.*}}: undefined symbol: _bar + +// Should fail if cannot find specified library (without -L switch) +// RUN: not wasm-ld -o /dev/null %t.o -lls 2>&1 \ +// RUN: | FileCheck --check-prefix=NOLIB %s +// NOLIB: unable to find library -lls + +// Should use explicitly specified static library +// Also ensure that we accept -L +// RUN: wasm-ld --emit-relocs --no-gc-sections -o %t3 %t.o -L %t.dir -l:libls.a +// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=STATIC %s +// STATIC: Symbols [ +// STATIC: Name: _static + +// Should use explicitly specified dynamic library +// RUN: wasm-ld -pie --experimental-pic --emit-relocs --no-gc-sections -o %t3 %t.o -L%t.dir -l:libls.so +// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=DYNAMIC %s +// DYNAMIC: Symbols [ +// DYNAMIC-NOT: Name: _static + +// Should prefer static to dynamic when linking regular executable. +// RUN: wasm-ld --emit-relocs --no-gc-sections -o %t3 %t.o -L%t.dir -lls +// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=STATIC %s + +// Should prefer dynamic when linking PIE. +// RUN: wasm-ld -pie --experimental-pic --emit-relocs --no-gc-sections -o %t3 %t.o -L%t.dir -lls +// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=DYNAMIC %s + +// Check for library search order +// RUN: mkdir -p %t.dir2 +// RUN: cp %t.dir/libls.a %t.dir2 +// RUN: wasm-ld -pie --experimental-pic --emit-relocs --no-gc-sections -o %t3 %t.o -L%t.dir2 -L%t.dir -lls +// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=STATIC %s + +// -L can be placed after -l +// RUN: wasm-ld -o %t3 %t.o -lls -L%t.dir + +// Check long forms as well +// RUN: wasm-ld --emit-relocs --no-gc-sections -o %t3 %t.o --library-path=%t.dir --library=ls +// RUN: wasm-ld --emit-relocs --no-gc-sections -o %t3 %t.o --library-path %t.dir --library ls + +// Should not search for dynamic libraries if -Bstatic is specified +// RUN: wasm-ld -pie --experimental-pic --emit-relocs --no-gc-sections -o %t3 %t.o -L%t.dir -Bstatic -lls +// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=STATIC %s +// RUN: not wasm-ld -pie --experimental-pic --emit-relocs --no-gc-sections -o /dev/null %t.o -L%t.dir -Bstatic -lls2 2>&1 \ +// RUN: | FileCheck --check-prefix=NOLIB2 %s +// NOLIB2: unable to find library -lls2 + +// -Bdynamic should restore default behaviour +// RUN: wasm-ld -pie --experimental-pic --emit-relocs --no-gc-sections -o %t3 %t.o -L%t.dir -Bstatic -Bdynamic -lls +// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=DYNAMIC %s + +// -Bstatic and -Bdynamic should affect only libraries which follow them +// RUN: wasm-ld -pie --experimental-pic --emit-relocs --no-gc-sections -o %t3 %t.o -L%t.dir -lls -Bstatic -Bdynamic +// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=DYNAMIC %s +// RUN: wasm-ld -pie --experimental-pic --emit-relocs --no-gc-sections -o %t3 %t.o -L%t.dir -Bstatic -lls -Bdynamic +// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=STATIC %s + +// Check aliases as well +// RUN: wasm-ld -pie --experimental-pic --emit-relocs --no-gc-sections -o %t3 %t.o -L%t.dir -dn -lls +// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=STATIC %s +// RUN: wasm-ld -pie --experimental-pic --emit-relocs --no-gc-sections -o %t3 %t.o -L%t.dir -non_shared -lls +// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=STATIC %s +// RUN: wasm-ld -pie --experimental-pic --emit-relocs --no-gc-sections -o %t3 %t.o -L%t.dir -static -lls +// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=STATIC %s +// RUN: wasm-ld -pie --experimental-pic --emit-relocs --no-gc-sections -o %t3 %t.o -L%t.dir -Bstatic -dy -lls +// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=DYNAMIC %s +// RUN: wasm-ld -pie --experimental-pic --emit-relocs --no-gc-sections -o %t3 %t.o -L%t.dir -Bstatic -call_shared -lls +// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=DYNAMIC %s + +.globl _start, _bar +_start: + .functype _start () -> () + end_function diff --git a/lld/wasm/Config.h b/lld/wasm/Config.h index 2c79e41..fbc195e 100644 --- a/lld/wasm/Config.h +++ b/lld/wasm/Config.h @@ -53,6 +53,7 @@ struct Configuration { bool stripAll; bool stripDebug; bool stackFirst; + bool isStatic = false; bool trace; uint64_t globalBase; uint64_t initialMemory; diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index 2794319..e6b2239 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -279,27 +279,58 @@ void LinkerDriver::addFile(StringRef path) { } } -// Add a given library by searching it from input search paths. -void LinkerDriver::addLibrary(StringRef name) { +static Optional findFromSearchPaths(StringRef path) { + for (StringRef dir : config->searchPaths) + if (Optional s = findFile(dir, path)) + return s; + return None; +} + +// This is for -l. We'll look for lib.a from +// search paths. +static Optional searchLibraryBaseName(StringRef name) { for (StringRef dir : config->searchPaths) { - if (Optional s = findFile(dir, "lib" + name + ".a")) { - addFile(*s); - return; - } + // Currently we don't enable dyanmic linking at all unless -shared or -pie + // are used, so don't even look for .so files in that case.. + if (config->isPic && !config->isStatic) + if (Optional s = findFile(dir, "lib" + name + ".so")) + return s; + if (Optional s = findFile(dir, "lib" + name + ".a")) + return s; } + return None; +} - error("unable to find library -l" + name); +// This is for -l. +static Optional searchLibrary(StringRef name) { + if (name.startswith(":")) + return findFromSearchPaths(name.substr(1)); + return searchLibraryBaseName(name); +} + +// Add a given library by searching it from input search paths. +void LinkerDriver::addLibrary(StringRef name) { + if (Optional path = searchLibrary(name)) + addFile(saver().save(*path)); + else + error("unable to find library -l" + name, ErrorTag::LibNotFound, {name}); } void LinkerDriver::createFiles(opt::InputArgList &args) { for (auto *arg : args) { switch (arg->getOption().getID()) { - case OPT_l: + case OPT_library: addLibrary(arg->getValue()); break; case OPT_INPUT: addFile(arg->getValue()); break; + case OPT_Bstatic: + config->isStatic = true; + break; + case OPT_Bdynamic: + config->isStatic = false; + break; case OPT_whole_archive: inWholeArchive = true; break; @@ -382,7 +413,7 @@ static void readConfigs(opt::InputArgList &args) { config->printGcSections = args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false); config->saveTemps = args.hasArg(OPT_save_temps); - config->searchPaths = args::getStrings(args, OPT_L); + config->searchPaths = args::getStrings(args, OPT_library_path); config->shared = args.hasArg(OPT_shared); config->stripAll = args.hasArg(OPT_strip_all); config->stripDebug = args.hasArg(OPT_strip_debug); @@ -898,12 +929,12 @@ void LinkerDriver::linkerMain(ArrayRef argsArr) { cl::ParseCommandLineOptions(v.size(), v.data()); readConfigs(args); + setConfigs(); createFiles(args); if (errorCount()) return; - setConfigs(); checkOptions(args); if (errorCount()) return; diff --git a/lld/wasm/Options.td b/lld/wasm/Options.td index b0c4a81..7a61924 100644 --- a/lld/wasm/Options.td +++ b/lld/wasm/Options.td @@ -38,6 +38,10 @@ multiclass B { // The following flags are shared with the ELF linker def Bsymbolic: F<"Bsymbolic">, HelpText<"Bind defined symbols locally">; +def Bdynamic: F<"Bdynamic">, HelpText<"Link against shared libraries (default)">; + +def Bstatic: F<"Bstatic">, HelpText<"Do not link against shared libraries">; + defm color_diagnostics: B<"color-diagnostics", "Alias for --color-diagnostics=always", "Alias for --color-diagnostics=never">; @@ -80,10 +84,10 @@ defm merge_data_segments: BB<"merge-data-segments", def help: F<"help">, HelpText<"Print option help">; -def l: JoinedOrSeparate<["-"], "l">, MetaVarName<"">, +def library: JoinedOrSeparate<["-"], "l">, MetaVarName<"">, HelpText<"Root name of library to use">; -def L: JoinedOrSeparate<["-"], "L">, MetaVarName<"">, +def library_path: JoinedOrSeparate<["-"], "L">, MetaVarName<"">, HelpText<"Add a directory to the library search path">; def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target emulation">; @@ -219,8 +223,17 @@ def features: CommaJoined<["--", "-"], "features=">, // Aliases def: JoinedOrSeparate<["-"], "e">, Alias; def: J<"entry=">, Alias; +def: F<"call_shared">, Alias, HelpText<"Alias for --Bdynamic">; +def: F<"dy">, Alias, HelpText<"Alias for --Bdynamic">; +def: F<"dn">, Alias, HelpText<"Alias for --Bstatic">; +def: F<"non_shared">, Alias, HelpText<"Alias for --Bstatic">; +def: F<"static">, Alias, HelpText<"Alias for --Bstatic">; def: Flag<["-"], "E">, Alias, HelpText<"Alias for --export-dynamic">; def: Flag<["-"], "i">, Alias; +def: Separate<["--", "-"], "library">, Alias; +def: Joined<["--", "-"], "library=">, Alias; +def: Separate<["--", "-"], "library-path">, Alias; +def: Joined<["--", "-"], "library-path=">, Alias; def: Flag<["-"], "M">, Alias, HelpText<"Alias for --print-map">; def: Flag<["-"], "r">, Alias; def: Flag<["-"], "s">, Alias, HelpText<"Alias for --strip-all">; -- 2.7.4