Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[lld][WebAssembly] Implement --start-lib/--end-lib #78821

Merged
merged 1 commit into from
Jan 22, 2024
Merged

Conversation

sbc100
Copy link
Collaborator

@sbc100 sbc100 commented Jan 20, 2024

Fixes: #77960

@llvmbot
Copy link
Collaborator

llvmbot commented Jan 20, 2024

@llvm/pr-subscribers-lld
@llvm/pr-subscribers-lld-wasm

@llvm/pr-subscribers-lld-elf

Author: Sam Clegg (sbc100)

Changes

Fixes: #77960


Full diff: https://github.com/llvm/llvm-project/pull/78821.diff

8 Files Affected:

  • (modified) lld/ELF/InputFiles.h (+2-2)
  • (added) lld/test/wasm/Inputs/start-lib1.s (+7)
  • (added) lld/test/wasm/Inputs/start-lib2.s (+4)
  • (added) lld/test/wasm/start-lib.s (+33)
  • (modified) lld/wasm/Driver.cpp (+14-1)
  • (modified) lld/wasm/InputFiles.h (+2-3)
  • (modified) lld/wasm/Options.td (+6)
  • (modified) lld/wasm/Symbols.h (+3-3)
diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h
index ab98d78fcf1455a..108a87bc43eb6b1 100644
--- a/lld/ELF/InputFiles.h
+++ b/lld/ELF/InputFiles.h
@@ -126,8 +126,8 @@ class InputFile {
   uint8_t osabi = 0;
   uint8_t abiVersion = 0;
 
-  // True if this is a relocatable object file/bitcode file between --start-lib
-  // and --end-lib.
+  // True if this is a relocatable object file/bitcode file in an ar archive
+  // or between --start-lib and --end-lib.
   bool lazy = false;
 
   // True if this is an argument for --just-symbols. Usually false.
diff --git a/lld/test/wasm/Inputs/start-lib1.s b/lld/test/wasm/Inputs/start-lib1.s
new file mode 100644
index 000000000000000..229f67a4bd897f8
--- /dev/null
+++ b/lld/test/wasm/Inputs/start-lib1.s
@@ -0,0 +1,7 @@
+.functype bar () -> ()
+
+.globl foo
+foo:
+  .functype foo () -> ()
+  call bar
+  end_function
diff --git a/lld/test/wasm/Inputs/start-lib2.s b/lld/test/wasm/Inputs/start-lib2.s
new file mode 100644
index 000000000000000..28cfa6f637c58a9
--- /dev/null
+++ b/lld/test/wasm/Inputs/start-lib2.s
@@ -0,0 +1,4 @@
+.globl bar
+bar:
+  .functype bar () -> ()
+  end_function
diff --git a/lld/test/wasm/start-lib.s b/lld/test/wasm/start-lib.s
new file mode 100644
index 000000000000000..8bed63cdcf494cb
--- /dev/null
+++ b/lld/test/wasm/start-lib.s
@@ -0,0 +1,33 @@
+// Based on lld/test/ELF/start-lib.s
+
+// RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %s -o %t1.o
+// RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown \
+// RUN:   %p/Inputs/start-lib1.s -o %t2.o
+// RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown \
+// RUN:   %p/Inputs/start-lib2.s -o %t3.o
+
+// RUN: wasm-ld --no-gc-sections -o %t3 %t1.o %t2.o %t3.o
+// RUN: obj2yaml %t3 | FileCheck --check-prefix=TEST1 %s
+// TEST1: Name: foo
+// TEST1: Name: bar
+
+// RUN: wasm-ld --no-gc-sections -o %t3 %t1.o -u bar --start-lib %t2.o %t3.o
+// RUN: obj2yaml %t3 | FileCheck --check-prefix=TEST2 %s
+// TEST2-NOT: Name: foo
+// TEST2: Name: bar
+
+// RUN: wasm-ld --no-gc-sections -o %t3 %t1.o --start-lib %t2.o %t3.o
+// RUN: obj2yaml %t3 | FileCheck --check-prefix=TEST3 %s
+// TEST3-NOT: Name: foo
+// TEST3-NOT: Name: bar
+
+// RUN: not wasm-ld %t1.o --start-lib --start-lib 2>&1 | FileCheck -check-prefix=NESTED-LIB %s
+// NESTED-LIB: nested --start-lib
+
+// RUN: not wasm-ld --end-lib 2>&1 | FileCheck -check-prefix=END %s
+// END: stray --end-lib
+
+.globl _start
+_start:
+  .functype _start () -> ()
+  end_function
diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp
index edf1979c1d3025a..3a81f342baa1681 100644
--- a/lld/wasm/Driver.cpp
+++ b/lld/wasm/Driver.cpp
@@ -94,6 +94,9 @@ class LinkerDriver {
   // True if we are in --whole-archive and --no-whole-archive.
   bool inWholeArchive = false;
 
+  // True if we are in --start-lib and --end-lib.
+  bool inLib = false;
+
   std::vector<InputFile *> files;
 };
 } // anonymous namespace
@@ -304,7 +307,7 @@ void LinkerDriver::addFile(StringRef path) {
   }
   case file_magic::bitcode:
   case file_magic::wasm_object:
-    files.push_back(createObjectFile(mbref));
+    files.push_back(createObjectFile(mbref, "", 0, inLib));
     break;
   case file_magic::unknown:
     if (mbref.getBuffer().starts_with("#STUB")) {
@@ -375,6 +378,16 @@ void LinkerDriver::createFiles(opt::InputArgList &args) {
     case OPT_no_whole_archive:
       inWholeArchive = false;
       break;
+    case OPT_start_lib:
+      if (inLib)
+        error("nested --start-lib");
+      inLib = true;
+      break;
+    case OPT_end_lib:
+      if (!inLib)
+        error("stray --end-lib");
+      inLib = false;
+      break;
     }
   }
   if (files.empty() && errorCount() == 0)
diff --git a/lld/wasm/InputFiles.h b/lld/wasm/InputFiles.h
index fd3d5e5ef479677..a129be36515d017 100644
--- a/lld/wasm/InputFiles.h
+++ b/lld/wasm/InputFiles.h
@@ -67,9 +67,8 @@ class InputFile {
   void markLive() { live = true; }
   bool isLive() const { return live; }
 
-  // True if this file is exists as in an archive file and has not yet been
-  // extracted.
-  // TODO(sbc): Use this to implement --start-lib/--end-lib.
+  // True if this is a relocatable object file/bitcode file in an ar archive
+  // or between --start-lib and --end-lib.
   bool lazy = false;
 
 protected:
diff --git a/lld/wasm/Options.td b/lld/wasm/Options.td
index 95ebc202a451879..8190717cef63bb9 100644
--- a/lld/wasm/Options.td
+++ b/lld/wasm/Options.td
@@ -70,6 +70,9 @@ defm export_dynamic: B<"export-dynamic",
     "Put symbols in the dynamic symbol table",
     "Do not put symbols in the dynamic symbol table (default)">;
 
+def end_lib: F<"end-lib">,
+  HelpText<"End a grouping of objects that should be treated as if they were together in an archive">;
+
 def entry: S<"entry">, MetaVarName<"<entry>">,
   HelpText<"Name of entry point symbol">;
 
@@ -128,6 +131,9 @@ defm rsp_quoting: Eq<"rsp-quoting", "Quoting style for response files">,
 
 def shared: F<"shared">, HelpText<"Build a shared object">;
 
+def start_lib: F<"start-lib">,
+  HelpText<"Start a grouping of objects that should be treated as if they were together in an archive">;
+
 def strip_all: F<"strip-all">, HelpText<"Strip all symbols">;
 
 def strip_debug: F<"strip-debug">, HelpText<"Strip debugging information">;
diff --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h
index de52c92d34e78b0..38586bbd1323629 100644
--- a/lld/wasm/Symbols.h
+++ b/lld/wasm/Symbols.h
@@ -486,9 +486,9 @@ class UndefinedTag : public TagSymbol {
   static bool classof(const Symbol *s) { return s->kind() == UndefinedTagKind; }
 };
 
-// LazySymbol represents a symbol that is not yet in the link, but we know where
-// to find it if needed. If the resolver finds both Undefined and Lazy for the
-// same name, it will ask the Lazy to load a file.
+// LazySymbol symbols represent symbols in object files between --start-lib and
+// --end-lib options. LLD also handles traditional archives as if all the files
+// in the archive are surrounded by --start-lib and --end-lib.
 //
 // A special complication is the handling of weak undefined symbols. They should
 // not load a file, but we have to remember we have seen both the weak undefined

lld/wasm/Driver.cpp Show resolved Hide resolved
lld/wasm/Driver.cpp Show resolved Hide resolved
@sbc100 sbc100 merged commit 1926139 into llvm:main Jan 22, 2024
3 of 4 checks passed
@sbc100 sbc100 deleted the start_lib branch January 22, 2024 18:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add support for --start-lib / --end-lib to Wasm LLD to omit the use of archives
3 participants