diff options
Diffstat (limited to 'wasm/Driver.cpp')
| -rw-r--r-- | wasm/Driver.cpp | 288 | 
1 files changed, 184 insertions, 104 deletions
diff --git a/wasm/Driver.cpp b/wasm/Driver.cpp index 329b5ae80a9cf..fab4c0c4ed8bb 100644 --- a/wasm/Driver.cpp +++ b/wasm/Driver.cpp @@ -31,6 +31,7 @@  #define DEBUG_TYPE "lld"  using namespace llvm; +using namespace llvm::object;  using namespace llvm::sys;  using namespace llvm::wasm; @@ -78,7 +79,7 @@ private:  bool lld::wasm::link(ArrayRef<const char *> Args, bool CanExitEarly,                       raw_ostream &Error) { -  errorHandler().LogName = sys::path::filename(Args[0]); +  errorHandler().LogName = args::getFilenameWithoutExe(Args[0]);    errorHandler().ErrorOS = &Error;    errorHandler().ColorDiagnostics = Error.has_colors();    errorHandler().ErrorLimitExceededMsg = @@ -186,8 +187,7 @@ static void readImportFile(StringRef Filename) {  // Returns slices of MB by parsing MB as an archive file.  // Each slice consists of a member file in the archive. -std::vector<MemoryBufferRef> static getArchiveMembers( -    MemoryBufferRef MB) { +std::vector<MemoryBufferRef> static getArchiveMembers(MemoryBufferRef MB) {    std::unique_ptr<Archive> File =        CHECK(Archive::create(MB),              MB.getBufferIdentifier() + ": failed to parse archive"); @@ -205,8 +205,8 @@ std::vector<MemoryBufferRef> static getArchiveMembers(      V.push_back(MBRef);    }    if (Err) -    fatal(MB.getBufferIdentifier() + ": Archive::children failed: " + -          toString(std::move(Err))); +    fatal(MB.getBufferIdentifier() + +          ": Archive::children failed: " + toString(std::move(Err)));    // Take ownership of memory buffers created for members of thin archives.    for (std::unique_ptr<MemoryBuffer> &MB : File->takeThinBuffers()) @@ -306,17 +306,14 @@ static void handleWeakUndefines() {      // It is possible for undefined functions not to have a signature (eg. if      // added via "--undefined"), but weak undefined ones do have a signature. -    assert(FuncSym->FunctionType); -    const WasmSignature &Sig = *FuncSym->FunctionType; +    assert(FuncSym->Signature); +    const WasmSignature &Sig = *FuncSym->Signature;      // Add a synthetic dummy for weak undefined functions.  These dummies will      // be GC'd if not used as the target of any "call" instructions. -    Optional<std::string> SymName = demangleItanium(Sym->getName()); -    StringRef DebugName = -        Saver.save("undefined function " + -                   (SymName ? StringRef(*SymName) : Sym->getName())); -    SyntheticFunction *Func = -        make<SyntheticFunction>(Sig, Sym->getName(), DebugName); +    std::string SymName = toString(*Sym); +    StringRef DebugName = Saver.save("undefined function " + SymName); +    auto *Func = make<SyntheticFunction>(Sig, Sym->getName(), DebugName);      Func->setBody(UnreachableFn);      // Ensure it compares equal to the null pointer, and so that table relocs      // don't pull in the stub body (only call-operand relocs should do that). @@ -328,51 +325,24 @@ static void handleWeakUndefines() {    }  } -// Force Sym to be entered in the output. Used for -u or equivalent. -static Symbol *addUndefined(StringRef Name) { -  Symbol *S = Symtab->addUndefinedFunction(Name, 0, nullptr, nullptr); - -  // Since symbol S may not be used inside the program, LTO may -  // eliminate it. Mark the symbol as "used" to prevent it. -  S->IsUsedInRegularObj = true; - -  return S; -} - -void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { -  WasmOptTable Parser; -  opt::InputArgList Args = Parser.parse(ArgsArr.slice(1)); - -  // Handle --help -  if (Args.hasArg(OPT_help)) { -    Parser.PrintHelp(outs(), ArgsArr[0], "LLVM Linker", false); -    return; -  } - -  // Handle --version -  if (Args.hasArg(OPT_version) || Args.hasArg(OPT_v)) { -    outs() << getLLDVersion() << "\n"; -    return; -  } - -  // Parse and evaluate -mllvm options. -  std::vector<const char *> V; -  V.push_back("wasm-ld (LLVM option parsing)"); -  for (auto *Arg : Args.filtered(OPT_mllvm)) -    V.push_back(Arg->getValue()); -  cl::ParseCommandLineOptions(V.size(), V.data()); - -  errorHandler().ErrorLimit = args::getInteger(Args, OPT_error_limit, 20); - +// Some Config members do not directly correspond to any particular +// command line options, but computed based on other Config values. +// This function initialize such members. See Config.h for the details +// of these values. +static void setConfigs(opt::InputArgList &Args) {    Config->AllowUndefined = Args.hasArg(OPT_allow_undefined); +  Config->CompressRelocations = Args.hasArg(OPT_compress_relocations);    Config->Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, true);    Config->DisableVerify = Args.hasArg(OPT_disable_verify);    Config->Entry = getEntry(Args, Args.hasArg(OPT_relocatable) ? "" : "_start");    Config->ExportAll = Args.hasArg(OPT_export_all); +  Config->ExportDynamic = Args.hasFlag(OPT_export_dynamic, +      OPT_no_export_dynamic, false);    Config->ExportTable = Args.hasArg(OPT_export_table);    errorHandler().FatalWarnings =        Args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false);    Config->ImportMemory = Args.hasArg(OPT_import_memory); +  Config->SharedMemory = Args.hasArg(OPT_shared_memory);    Config->ImportTable = Args.hasArg(OPT_import_table);    Config->LTOO = args::getInteger(Args, OPT_lto_O, 2);    Config->LTOPartitions = args::getInteger(Args, OPT_lto_partitions, 1); @@ -384,10 +354,12 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {    Config->MergeDataSegments =        Args.hasFlag(OPT_merge_data_segments, OPT_no_merge_data_segments,                     !Config->Relocatable); +  Config->Pie = Args.hasFlag(OPT_pie, OPT_no_pie, false);    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->Shared = Args.hasArg(OPT_shared);    Config->StripAll = Args.hasArg(OPT_strip_all);    Config->StripDebug = Args.hasArg(OPT_strip_debug);    Config->StackFirst = Args.hasArg(OPT_stack_first); @@ -404,8 +376,14 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {    Config->MaxMemory = args::getInteger(Args, OPT_max_memory, 0);    Config->ZStackSize =        args::getZOptionValue(Args, OPT_z, "stack-size", WasmPageSize); +} -  Config->CompressRelocTargets = Config->Optimize > 0 && !Config->Relocatable; +// Some command line options or some combinations of them are not allowed. +// This function checks for such errors. +static void checkOptions(opt::InputArgList &Args) { +  if (!Config->StripDebug && !Config->StripAll && Config->CompressRelocations) +    error("--compress-relocations is incompatible with output debug" +          " information. Please pass --strip-debug or --strip-all");    if (Config->LTOO > 3)      error("invalid optimization level for LTO: " + Twine(Config->LTOO)); @@ -414,13 +392,8 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {    if (Config->ThinLTOJobs == 0)      error("--thinlto-jobs: number of threads must be > 0"); -  if (auto *Arg = Args.getLastArg(OPT_allow_undefined_file)) -    readImportFile(Arg->getValue()); - -  if (!Args.hasArg(OPT_INPUT)) { -    error("no input files"); -    return; -  } +  if (Config->Pie && Config->Shared) +    error("-shared and -pie may not be used together");    if (Config->OutputFile.empty())      error("no output file specified"); @@ -433,46 +406,151 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {        error("entry point specified for relocatable output file");      if (Config->GcSections)        error("-r and --gc-sections may not be used together"); +    if (Config->CompressRelocations) +      error("-r -and --compress-relocations may not be used together");      if (Args.hasArg(OPT_undefined))        error("-r -and --undefined may not be used together"); +    if (Config->Pie) +      error("-r and -pie may not be used together");    } +} -  Symbol *EntrySym = nullptr; -  if (!Config->Relocatable) { +// Force Sym to be entered in the output. Used for -u or equivalent. +static Symbol *handleUndefined(StringRef Name) { +  Symbol *Sym = Symtab->find(Name); +  if (!Sym) +    return nullptr; + +  // Since symbol S may not be used inside the program, LTO may +  // eliminate it. Mark the symbol as "used" to prevent it. +  Sym->IsUsedInRegularObj = true; + +  if (auto *LazySym = dyn_cast<LazySymbol>(Sym)) +    LazySym->fetch(); + +  return Sym; +} + +static UndefinedGlobal * +createUndefinedGlobal(StringRef Name, llvm::wasm::WasmGlobalType *Type) { +  auto *Sym = +      cast<UndefinedGlobal>(Symtab->addUndefinedGlobal(Name, 0, nullptr, Type)); +  Config->AllowUndefinedSymbols.insert(Sym->getName()); +  Sym->IsUsedInRegularObj = true; +  return Sym; +} + +// Create ABI-defined synthetic symbols +static void createSyntheticSymbols() { +  static WasmSignature NullSignature = {{}, {}}; +  static llvm::wasm::WasmGlobalType GlobalTypeI32 = {WASM_TYPE_I32, false}; +  static llvm::wasm::WasmGlobalType MutableGlobalTypeI32 = {WASM_TYPE_I32, +                                                            true}; + +  if (!Config->Relocatable) +    WasmSym::CallCtors = Symtab->addSyntheticFunction( +        "__wasm_call_ctors", WASM_SYMBOL_VISIBILITY_HIDDEN, +        make<SyntheticFunction>(NullSignature, "__wasm_call_ctors")); + +  // The __stack_pointer is imported in the shared library case, and exported +  // in the non-shared (executable) case. +  if (Config->Shared) { +    WasmSym::StackPointer = +        createUndefinedGlobal("__stack_pointer", &MutableGlobalTypeI32); +  } else {      llvm::wasm::WasmGlobal Global;      Global.Type = {WASM_TYPE_I32, true};      Global.InitExpr.Value.Int32 = 0;      Global.InitExpr.Opcode = WASM_OPCODE_I32_CONST;      Global.SymbolName = "__stack_pointer"; -    InputGlobal *StackPointer = make<InputGlobal>(Global, nullptr); +    auto *StackPointer = make<InputGlobal>(Global, nullptr);      StackPointer->Live = true; - -    static WasmSignature NullSignature = {{}, WASM_TYPE_NORESULT}; - -    // Add synthetic symbols before any others -    WasmSym::CallCtors = Symtab->addSyntheticFunction( -        "__wasm_call_ctors", WASM_SYMBOL_VISIBILITY_HIDDEN, -        make<SyntheticFunction>(NullSignature, "__wasm_call_ctors")); +    // For non-PIC code      // TODO(sbc): Remove WASM_SYMBOL_VISIBILITY_HIDDEN when the mutable global      // spec proposal is implemented in all major browsers.      // See: https://github.com/WebAssembly/mutable-global      WasmSym::StackPointer = Symtab->addSyntheticGlobal(          "__stack_pointer", WASM_SYMBOL_VISIBILITY_HIDDEN, StackPointer);      WasmSym::HeapBase = Symtab->addSyntheticDataSymbol("__heap_base", 0); -    WasmSym::DsoHandle = Symtab->addSyntheticDataSymbol( -        "__dso_handle", WASM_SYMBOL_VISIBILITY_HIDDEN);      WasmSym::DataEnd = Symtab->addSyntheticDataSymbol("__data_end", 0); -    // For now, since we don't actually use the start function as the -    // wasm start symbol, we don't need to care about it signature. -    if (!Config->Entry.empty()) -      EntrySym = addUndefined(Config->Entry); +    // These two synthetic symbols exist purely for the embedder so we always +    // want to export them. +    WasmSym::HeapBase->ForceExport = true; +    WasmSym::DataEnd->ForceExport = true; +  } + +  if (Config->Pic) { +    // For PIC code, we import two global variables (__memory_base and +    // __table_base) from the environment and use these as the offset at +    // which to load our static data and function table. +    // See: +    // https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md +    WasmSym::MemoryBase = +        createUndefinedGlobal("__memory_base", &GlobalTypeI32); +    WasmSym::TableBase = createUndefinedGlobal("__table_base", &GlobalTypeI32); +    WasmSym::MemoryBase->markLive(); +    WasmSym::TableBase->markLive(); +  } + +  WasmSym::DsoHandle = Symtab->addSyntheticDataSymbol( +      "__dso_handle", WASM_SYMBOL_VISIBILITY_HIDDEN); +} + +void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { +  WasmOptTable Parser; +  opt::InputArgList Args = Parser.parse(ArgsArr.slice(1)); + +  // Handle --help +  if (Args.hasArg(OPT_help)) { +    Parser.PrintHelp(outs(), +                     (std::string(ArgsArr[0]) + " [options] file...").c_str(), +                     "LLVM Linker", false); +    return; +  } -    // Handle the `--undefined <sym>` options. -    for (auto *Arg : Args.filtered(OPT_undefined)) -      addUndefined(Arg->getValue()); +  // Handle --version +  if (Args.hasArg(OPT_version) || Args.hasArg(OPT_v)) { +    outs() << getLLDVersion() << "\n"; +    return;    } +  // Parse and evaluate -mllvm options. +  std::vector<const char *> V; +  V.push_back("wasm-ld (LLVM option parsing)"); +  for (auto *Arg : Args.filtered(OPT_mllvm)) +    V.push_back(Arg->getValue()); +  cl::ParseCommandLineOptions(V.size(), V.data()); + +  errorHandler().ErrorLimit = args::getInteger(Args, OPT_error_limit, 20); + +  setConfigs(Args); +  checkOptions(Args); + +  if (auto *Arg = Args.getLastArg(OPT_allow_undefined_file)) +    readImportFile(Arg->getValue()); + +  if (!Args.hasArg(OPT_INPUT)) { +    error("no input files"); +    return; +  } + +  Config->Pic = Config->Pie || Config->Shared; + +  if (Config->Pic) { +    if (Config->ExportTable) +      error("-shared/-pie is incompatible with --export-table"); +    Config->ImportTable = true; +  } + +  if (Config->Shared) { +    Config->ExportDynamic = true; +    Config->AllowUndefined = true; +  } + +  if (!Config->Relocatable) +    createSyntheticSymbols(); +    createFiles(Args);    if (errorCount())      return; @@ -484,44 +562,46 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {    if (errorCount())      return; -  // Add synthetic dummies for weak undefined functions. -  if (!Config->Relocatable) -    handleWeakUndefines(); +  // Handle the `--undefined <sym>` options. +  for (auto *Arg : Args.filtered(OPT_undefined)) +    handleUndefined(Arg->getValue()); -  // Handle --export. +  // Handle the `--export <sym>` options +  // This works like --undefined but also exports the symbol if its found    for (auto *Arg : Args.filtered(OPT_export)) { -    StringRef Name = Arg->getValue(); -    Symbol *Sym = Symtab->find(Name); +    Symbol *Sym = handleUndefined(Arg->getValue());      if (Sym && Sym->isDefined())        Sym->ForceExport = true;      else if (!Config->AllowUndefined) -      error("symbol exported via --export not found: " + Name); +      error(Twine("symbol exported via --export not found: ") + +            Arg->getValue());    } -  // Do link-time optimization if given files are LLVM bitcode files. -  // This compiles bitcode files into real object files. -  Symtab->addCombinedLTOObject(); -  if (errorCount()) -    return; +  Symbol *EntrySym = nullptr; +  if (!Config->Relocatable) { +    // Add synthetic dummies for weak undefined functions. +    handleWeakUndefines(); -  // Make sure we have resolved all symbols. -  if (!Config->Relocatable && !Config->AllowUndefined) { -    Symtab->reportRemainingUndefines(); -  } else { -    // Even when using --allow-undefined we still want to report the absence of -    // our initial set of undefined symbols (i.e. the entry point and symbols -    // specified via --undefined). -    // Part of the reason for this is that these function don't have signatures -    // so which means they cannot be written as wasm function imports. -    for (auto *Arg : Args.filtered(OPT_undefined)) { -      Symbol *Sym = Symtab->find(Arg->getValue()); -      if (!Sym->isDefined()) -        error("symbol forced with --undefined not found: " + Sym->getName()); +    if (!Config->Shared && !Config->Entry.empty()) { +      EntrySym = handleUndefined(Config->Entry); +      if (EntrySym && EntrySym->isDefined()) +        EntrySym->ForceExport = true; +      else +        error("entry symbol not defined (pass --no-entry to supress): " + +              Config->Entry);      } -    if (EntrySym && !EntrySym->isDefined()) -      error("entry symbol not defined (pass --no-entry to supress): " + -            EntrySym->getName()); + +    // Make sure we have resolved all symbols. +    if (!Config->AllowUndefined) +      Symtab->reportRemainingUndefines();    } + +  if (errorCount()) +    return; + +  // Do link-time optimization if given files are LLVM bitcode files. +  // This compiles bitcode files into real object files. +  Symtab->addCombinedLTOObject();    if (errorCount())      return;  | 
