1 //===- Driver.cpp ---------------------------------------------------------===// 2 // 3 // The LLVM Linker 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "lld/Common/Driver.h" 11 #include "InputChunks.h" 12 #include "MarkLive.h" 13 #include "SymbolTable.h" 14 #include "Writer.h" 15 #include "lld/Common/Args.h" 16 #include "lld/Common/ErrorHandler.h" 17 #include "lld/Common/Memory.h" 18 #include "lld/Common/Threads.h" 19 #include "lld/Common/Version.h" 20 #include "llvm/ADT/Twine.h" 21 #include "llvm/Object/Wasm.h" 22 #include "llvm/Option/ArgList.h" 23 #include "llvm/Support/CommandLine.h" 24 #include "llvm/Support/Path.h" 25 #include "llvm/Support/Process.h" 26 27 #define DEBUG_TYPE "lld" 28 29 using namespace llvm; 30 using namespace llvm::sys; 31 using namespace llvm::wasm; 32 33 using namespace lld; 34 using namespace lld::wasm; 35 36 namespace { 37 38 // Parses command line options. 39 class WasmOptTable : public llvm::opt::OptTable { 40 public: 41 WasmOptTable(); 42 llvm::opt::InputArgList parse(ArrayRef<const char *> Argv); 43 }; 44 45 // Create enum with OPT_xxx values for each option in Options.td 46 enum { 47 OPT_INVALID = 0, 48 #define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID, 49 #include "Options.inc" 50 #undef OPTION 51 }; 52 53 class LinkerDriver { 54 public: 55 void link(ArrayRef<const char *> ArgsArr); 56 57 private: 58 void createFiles(llvm::opt::InputArgList &Args); 59 void addFile(StringRef Path); 60 void addLibrary(StringRef Name); 61 std::vector<InputFile *> Files; 62 }; 63 64 } // anonymous namespace 65 66 Configuration *lld::wasm::Config; 67 68 bool lld::wasm::link(ArrayRef<const char *> Args, bool CanExitEarly, 69 raw_ostream &Error) { 70 errorHandler().LogName = Args[0]; 71 errorHandler().ErrorOS = &Error; 72 errorHandler().ColorDiagnostics = Error.has_colors(); 73 errorHandler().ErrorLimitExceededMsg = 74 "too many errors emitted, stopping now (use " 75 "-error-limit=0 to see all errors)"; 76 77 Config = make<Configuration>(); 78 Symtab = make<SymbolTable>(); 79 80 LinkerDriver().link(Args); 81 82 // Exit immediately if we don't need to return to the caller. 83 // This saves time because the overhead of calling destructors 84 // for all globally-allocated objects is not negligible. 85 if (CanExitEarly) 86 exitLld(errorCount() ? 1 : 0); 87 88 freeArena(); 89 return !errorCount(); 90 } 91 92 // Create OptTable 93 94 // Create prefix string literals used in Options.td 95 #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; 96 #include "Options.inc" 97 #undef PREFIX 98 99 // Create table mapping all options defined in Options.td 100 static const opt::OptTable::Info OptInfo[] = { 101 #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \ 102 {X1, X2, X10, X11, OPT_##ID, opt::Option::KIND##Class, \ 103 X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12}, 104 #include "Options.inc" 105 #undef OPTION 106 }; 107 108 // Set color diagnostics according to -color-diagnostics={auto,always,never} 109 // or -no-color-diagnostics flags. 110 static void handleColorDiagnostics(opt::InputArgList &Args) { 111 auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq, 112 OPT_no_color_diagnostics); 113 if (!Arg) 114 return; 115 116 if (Arg->getOption().getID() == OPT_color_diagnostics) 117 errorHandler().ColorDiagnostics = true; 118 else if (Arg->getOption().getID() == OPT_no_color_diagnostics) 119 errorHandler().ColorDiagnostics = false; 120 else { 121 StringRef S = Arg->getValue(); 122 if (S == "always") 123 errorHandler().ColorDiagnostics = true; 124 if (S == "never") 125 errorHandler().ColorDiagnostics = false; 126 if (S != "auto") 127 error("unknown option: -color-diagnostics=" + S); 128 } 129 } 130 131 // Find a file by concatenating given paths. 132 static Optional<std::string> findFile(StringRef Path1, const Twine &Path2) { 133 SmallString<128> S; 134 path::append(S, Path1, Path2); 135 if (fs::exists(S)) 136 return S.str().str(); 137 return None; 138 } 139 140 static void printHelp(const char *Argv0) { 141 WasmOptTable().PrintHelp(outs(), Argv0, "LLVM Linker", false); 142 } 143 144 WasmOptTable::WasmOptTable() : OptTable(OptInfo) {} 145 146 opt::InputArgList WasmOptTable::parse(ArrayRef<const char *> Argv) { 147 SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size()); 148 149 unsigned MissingIndex; 150 unsigned MissingCount; 151 opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount); 152 153 handleColorDiagnostics(Args); 154 for (auto *Arg : Args.filtered(OPT_UNKNOWN)) 155 error("unknown argument: " + Arg->getSpelling()); 156 return Args; 157 } 158 159 // Currently we allow a ".imports" to live alongside a library. This can 160 // be used to specify a list of symbols which can be undefined at link 161 // time (imported from the environment. For example libc.a include an 162 // import file that lists the syscall functions it relies on at runtime. 163 // In the long run this information would be better stored as a symbol 164 // attribute/flag in the object file itself. 165 // See: https://github.com/WebAssembly/tool-conventions/issues/35 166 static void readImportFile(StringRef Filename) { 167 if (Optional<MemoryBufferRef> Buf = readFile(Filename)) 168 for (StringRef Sym : args::getLines(*Buf)) 169 Config->AllowUndefinedSymbols.insert(Sym); 170 } 171 172 void LinkerDriver::addFile(StringRef Path) { 173 Optional<MemoryBufferRef> Buffer = readFile(Path); 174 if (!Buffer.hasValue()) 175 return; 176 MemoryBufferRef MBRef = *Buffer; 177 178 if (identify_magic(MBRef.getBuffer()) == file_magic::archive) { 179 SmallString<128> ImportFile = Path; 180 path::replace_extension(ImportFile, ".imports"); 181 if (fs::exists(ImportFile)) 182 readImportFile(ImportFile.str()); 183 184 Files.push_back(make<ArchiveFile>(MBRef)); 185 return; 186 } 187 188 Files.push_back(make<ObjFile>(MBRef)); 189 } 190 191 // Add a given library by searching it from input search paths. 192 void LinkerDriver::addLibrary(StringRef Name) { 193 for (StringRef Dir : Config->SearchPaths) { 194 if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".a")) { 195 addFile(*S); 196 return; 197 } 198 } 199 200 error("unable to find library -l" + Name); 201 } 202 203 void LinkerDriver::createFiles(opt::InputArgList &Args) { 204 for (auto *Arg : Args) { 205 switch (Arg->getOption().getUnaliasedOption().getID()) { 206 case OPT_l: 207 addLibrary(Arg->getValue()); 208 break; 209 case OPT_INPUT: 210 addFile(Arg->getValue()); 211 break; 212 } 213 } 214 215 if (Files.empty()) 216 error("no input files"); 217 } 218 219 static StringRef getEntry(opt::InputArgList &Args, StringRef Default) { 220 auto *Arg = Args.getLastArg(OPT_entry, OPT_no_entry); 221 if (!Arg) 222 return Default; 223 if (Arg->getOption().getID() == OPT_no_entry) 224 return ""; 225 return Arg->getValue(); 226 } 227 228 void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { 229 WasmOptTable Parser; 230 opt::InputArgList Args = Parser.parse(ArgsArr.slice(1)); 231 232 // Handle --help 233 if (Args.hasArg(OPT_help)) { 234 printHelp(ArgsArr[0]); 235 return; 236 } 237 238 // Parse and evaluate -mllvm options. 239 std::vector<const char *> V; 240 V.push_back("wasm-ld (LLVM option parsing)"); 241 for (auto *Arg : Args.filtered(OPT_mllvm)) 242 V.push_back(Arg->getValue()); 243 cl::ParseCommandLineOptions(V.size(), V.data()); 244 245 errorHandler().ErrorLimit = args::getInteger(Args, OPT_error_limit, 20); 246 247 if (Args.hasArg(OPT_version) || Args.hasArg(OPT_v)) { 248 outs() << getLLDVersion() << "\n"; 249 return; 250 } 251 252 Config->AllowUndefined = Args.hasArg(OPT_allow_undefined); 253 Config->CheckSignatures = 254 Args.hasFlag(OPT_check_signatures, OPT_no_check_signatures, false); 255 Config->Entry = getEntry(Args, Args.hasArg(OPT_relocatable) ? "" : "_start"); 256 Config->ImportMemory = Args.hasArg(OPT_import_memory); 257 Config->OutputFile = Args.getLastArgValue(OPT_o); 258 Config->Relocatable = Args.hasArg(OPT_relocatable); 259 Config->GcSections = 260 Args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, !Config->Relocatable); 261 Config->PrintGcSections = 262 Args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false); 263 Config->SearchPaths = args::getStrings(Args, OPT_L); 264 Config->StripAll = Args.hasArg(OPT_strip_all); 265 Config->StripDebug = Args.hasArg(OPT_strip_debug); 266 errorHandler().Verbose = Args.hasArg(OPT_verbose); 267 ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true); 268 269 Config->InitialMemory = args::getInteger(Args, OPT_initial_memory, 0); 270 Config->GlobalBase = args::getInteger(Args, OPT_global_base, 1024); 271 Config->MaxMemory = args::getInteger(Args, OPT_max_memory, 0); 272 Config->ZStackSize = 273 args::getZOptionValue(Args, OPT_z, "stack-size", WasmPageSize); 274 275 if (auto *Arg = Args.getLastArg(OPT_allow_undefined_file)) 276 readImportFile(Arg->getValue()); 277 278 if (Config->OutputFile.empty()) 279 error("no output file specified"); 280 281 if (!Args.hasArg(OPT_INPUT)) 282 error("no input files"); 283 284 if (Config->Relocatable) { 285 if (!Config->Entry.empty()) 286 error("entry point specified for relocatable output file"); 287 if (Config->GcSections) 288 error("-r and --gc-sections may not be used together"); 289 if (Args.hasArg(OPT_undefined)) 290 error("-r -and --undefined may not be used together"); 291 } 292 293 Symbol *EntrySym = nullptr; 294 if (!Config->Relocatable) { 295 static WasmSignature Signature = {{}, WASM_TYPE_NORESULT}; 296 if (!Config->Entry.empty()) 297 EntrySym = Symtab->addUndefinedFunction(Config->Entry, &Signature); 298 299 // Handle the `--undefined <sym>` options. 300 for (auto* Arg : Args.filtered(OPT_undefined)) 301 Symtab->addUndefinedFunction(Arg->getValue(), nullptr); 302 WasmSym::CallCtors = Symtab->addDefinedFunction( 303 "__wasm_call_ctors", &Signature, WASM_SYMBOL_VISIBILITY_HIDDEN); 304 WasmSym::StackPointer = Symtab->addDefinedGlobal("__stack_pointer"); 305 WasmSym::HeapBase = Symtab->addDefinedGlobal("__heap_base"); 306 WasmSym::DsoHandle = Symtab->addDefinedGlobal("__dso_handle"); 307 WasmSym::DataEnd = Symtab->addDefinedGlobal("__data_end"); 308 } 309 310 createFiles(Args); 311 if (errorCount()) 312 return; 313 314 // Add all files to the symbol table. This will add almost all 315 // symbols that we need to the symbol table. 316 for (InputFile *F : Files) 317 Symtab->addFile(F); 318 319 // Make sure we have resolved all symbols. 320 if (!Config->Relocatable && !Config->AllowUndefined) { 321 Symtab->reportRemainingUndefines(); 322 } else { 323 // When we allow undefined symbols we cannot include those defined in 324 // -u/--undefined since these undefined symbols have only names and no 325 // function signature, which means they cannot be written to the final 326 // output. 327 for (auto* Arg : Args.filtered(OPT_undefined)) { 328 Symbol *Sym = Symtab->find(Arg->getValue()); 329 if (!Sym->isDefined()) 330 error("function forced with --undefined not found: " + Sym->getName()); 331 } 332 } 333 if (errorCount()) 334 return; 335 336 for (auto *Arg : Args.filtered(OPT_export)) { 337 Symbol *Sym = Symtab->find(Arg->getValue()); 338 if (!Sym || !Sym->isDefined()) 339 error("symbol exported via --export not found: " + 340 Twine(Arg->getValue())); 341 else 342 Sym->setHidden(false); 343 } 344 345 if (EntrySym) 346 EntrySym->setHidden(false); 347 348 if (errorCount()) 349 return; 350 351 // Do size optimizations: garbage collection 352 markLive(); 353 354 // Write the result to the file. 355 writeResult(); 356 } 357