diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h index 833124275b2e1..0cbe00aa396ac 100644 --- a/lld/ELF/InputFiles.h +++ b/lld/ELF/InputFiles.h @@ -129,8 +129,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 0000000000000..229f67a4bd897 --- /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 0000000000000..28cfa6f637c58 --- /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 0000000000000..8bed63cdcf494 --- /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 88a3db75b54a1..635f19f78b15e 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 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 fd3d5e5ef4796..a129be36515d0 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 95ebc202a4518..8190717cef63b 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<"">, 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 de52c92d34e78..38586bbd13236 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