[lld] 0a9756f - [lld][WebAssemlby] Improve support for -L / -l and add testing

Sam Clegg via llvm-commits llvm-commits at lists.llvm.org
Mon Oct 3 17:02:00 PDT 2022


Author: Sam Clegg
Date: 2022-10-03T16:53:30-07:00
New Revision: 0a9756fc15c57dc94146e65d251d7a3d941ae78a

URL: https://github.com/llvm/llvm-project/commit/0a9756fc15c57dc94146e65d251d7a3d941ae78a
DIFF: https://github.com/llvm/llvm-project/commit/0a9756fc15c57dc94146e65d251d7a3d941ae78a.diff

LOG: [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

Added: 
    lld/test/wasm/Inputs/libsearch-dyn.s
    lld/test/wasm/Inputs/libsearch-st.s
    lld/test/wasm/Inputs/use-bar.s
    lld/test/wasm/libsearch.s

Modified: 
    lld/wasm/Config.h
    lld/wasm/Driver.cpp
    lld/wasm/Options.td

Removed: 
    


################################################################################
diff  --git a/lld/test/wasm/Inputs/libsearch-dyn.s b/lld/test/wasm/Inputs/libsearch-dyn.s
new file mode 100644
index 000000000000..bb59580b830f
--- /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 000000000000..dc5d89b406af
--- /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 000000000000..4ba20a061466
--- /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 000000000000..23336510748c
--- /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 <arg>
+// 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 2c79e4196338..fbc195e974f0 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 27943198c93f..e6b2239e7a15 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<std::string> findFromSearchPaths(StringRef path) {
+  for (StringRef dir : config->searchPaths)
+    if (Optional<std::string> s = findFile(dir, path))
+      return s;
+  return None;
+}
+
+// This is for -l<basename>. We'll look for lib<basename>.a from
+// search paths.
+static Optional<std::string> searchLibraryBaseName(StringRef name) {
   for (StringRef dir : config->searchPaths) {
-    if (Optional<std::string> 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<std::string> s = findFile(dir, "lib" + name + ".so"))
+        return s;
+    if (Optional<std::string> s = findFile(dir, "lib" + name + ".a"))
+      return s;
   }
+  return None;
+}
 
-  error("unable to find library -l" + name);
+// This is for -l<namespec>.
+static Optional<std::string> 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<std::string> 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<const char *> 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 b0c4a811e85a..7a6192433ec8 100644
--- a/lld/wasm/Options.td
+++ b/lld/wasm/Options.td
@@ -38,6 +38,10 @@ multiclass B<string name, string help1, string help2> {
 // 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<"<libName>">,
+def library: JoinedOrSeparate<["-"], "l">, MetaVarName<"<libName>">,
   HelpText<"Root name of library to use">;
 
-def L: JoinedOrSeparate<["-"], "L">, MetaVarName<"<dir>">,
+def library_path: JoinedOrSeparate<["-"], "L">, MetaVarName<"<dir>">,
   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<entry>;
 def: J<"entry=">, Alias<entry>;
+def: F<"call_shared">, Alias<Bdynamic>, HelpText<"Alias for --Bdynamic">;
+def: F<"dy">, Alias<Bdynamic>, HelpText<"Alias for --Bdynamic">;
+def: F<"dn">, Alias<Bstatic>, HelpText<"Alias for --Bstatic">;
+def: F<"non_shared">, Alias<Bstatic>, HelpText<"Alias for --Bstatic">;
+def: F<"static">, Alias<Bstatic>, HelpText<"Alias for --Bstatic">;
 def: Flag<["-"], "E">, Alias<export_dynamic>, HelpText<"Alias for --export-dynamic">;
 def: Flag<["-"], "i">, Alias<initial_memory>;
+def: Separate<["--", "-"], "library">, Alias<library>;
+def: Joined<["--", "-"], "library=">, Alias<library>;
+def: Separate<["--", "-"], "library-path">, Alias<library_path>;
+def: Joined<["--", "-"], "library-path=">, Alias<library_path>;
 def: Flag<["-"], "M">, Alias<print_map>, HelpText<"Alias for --print-map">;
 def: Flag<["-"], "r">, Alias<relocatable>;
 def: Flag<["-"], "s">, Alias<strip_all>, HelpText<"Alias for --strip-all">;


        


More information about the llvm-commits mailing list