1 //===- InputFiles.cpp -----------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "InputFiles.h" 10 #include "Config.h" 11 #include "InputChunks.h" 12 #include "InputEvent.h" 13 #include "InputGlobal.h" 14 #include "SymbolTable.h" 15 #include "lld/Common/ErrorHandler.h" 16 #include "lld/Common/Memory.h" 17 #include "lld/Common/Reproduce.h" 18 #include "llvm/Object/Binary.h" 19 #include "llvm/Object/Wasm.h" 20 #include "llvm/Support/TarWriter.h" 21 #include "llvm/Support/raw_ostream.h" 22 23 #define DEBUG_TYPE "lld" 24 25 using namespace llvm; 26 using namespace llvm::object; 27 using namespace llvm::wasm; 28 29 namespace lld { 30 31 // Returns a string in the format of "foo.o" or "foo.a(bar.o)". 32 std::string toString(const wasm::InputFile *file) { 33 if (!file) 34 return "<internal>"; 35 36 if (file->archiveName.empty()) 37 return std::string(file->getName()); 38 39 return (file->archiveName + "(" + file->getName() + ")").str(); 40 } 41 42 namespace wasm { 43 44 void InputFile::checkArch(Triple::ArchType arch) const { 45 bool is64 = arch == Triple::wasm64; 46 if (is64 && !config->is64.hasValue()) { 47 fatal(toString(this) + 48 ": must specify -mwasm64 to process wasm64 object files"); 49 } else if (config->is64.getValueOr(false) != is64) { 50 fatal(toString(this) + 51 ": wasm32 object file can't be linked in wasm64 mode"); 52 } 53 } 54 55 std::unique_ptr<llvm::TarWriter> tar; 56 57 Optional<MemoryBufferRef> readFile(StringRef path) { 58 log("Loading: " + path); 59 60 auto mbOrErr = MemoryBuffer::getFile(path); 61 if (auto ec = mbOrErr.getError()) { 62 error("cannot open " + path + ": " + ec.message()); 63 return None; 64 } 65 std::unique_ptr<MemoryBuffer> &mb = *mbOrErr; 66 MemoryBufferRef mbref = mb->getMemBufferRef(); 67 make<std::unique_ptr<MemoryBuffer>>(std::move(mb)); // take MB ownership 68 69 if (tar) 70 tar->append(relativeToRoot(path), mbref.getBuffer()); 71 return mbref; 72 } 73 74 InputFile *createObjectFile(MemoryBufferRef mb, StringRef archiveName) { 75 file_magic magic = identify_magic(mb.getBuffer()); 76 if (magic == file_magic::wasm_object) { 77 std::unique_ptr<Binary> bin = 78 CHECK(createBinary(mb), mb.getBufferIdentifier()); 79 auto *obj = cast<WasmObjectFile>(bin.get()); 80 if (obj->isSharedObject()) 81 return make<SharedFile>(mb); 82 return make<ObjFile>(mb, archiveName); 83 } 84 85 if (magic == file_magic::bitcode) 86 return make<BitcodeFile>(mb, archiveName); 87 88 fatal("unknown file type: " + mb.getBufferIdentifier()); 89 } 90 91 void ObjFile::dumpInfo() const { 92 log("info for: " + toString(this) + 93 "\n Symbols : " + Twine(symbols.size()) + 94 "\n Function Imports : " + Twine(wasmObj->getNumImportedFunctions()) + 95 "\n Global Imports : " + Twine(wasmObj->getNumImportedGlobals()) + 96 "\n Event Imports : " + Twine(wasmObj->getNumImportedEvents())); 97 } 98 99 // Relocations contain either symbol or type indices. This function takes a 100 // relocation and returns relocated index (i.e. translates from the input 101 // symbol/type space to the output symbol/type space). 102 uint32_t ObjFile::calcNewIndex(const WasmRelocation &reloc) const { 103 if (reloc.Type == R_WASM_TYPE_INDEX_LEB) { 104 assert(typeIsUsed[reloc.Index]); 105 return typeMap[reloc.Index]; 106 } 107 const Symbol *sym = symbols[reloc.Index]; 108 if (auto *ss = dyn_cast<SectionSymbol>(sym)) 109 sym = ss->getOutputSectionSymbol(); 110 return sym->getOutputSymbolIndex(); 111 } 112 113 // Relocations can contain addend for combined sections. This function takes a 114 // relocation and returns updated addend by offset in the output section. 115 uint64_t ObjFile::calcNewAddend(const WasmRelocation &reloc) const { 116 switch (reloc.Type) { 117 case R_WASM_MEMORY_ADDR_LEB: 118 case R_WASM_MEMORY_ADDR_LEB64: 119 case R_WASM_MEMORY_ADDR_SLEB64: 120 case R_WASM_MEMORY_ADDR_SLEB: 121 case R_WASM_MEMORY_ADDR_REL_SLEB: 122 case R_WASM_MEMORY_ADDR_REL_SLEB64: 123 case R_WASM_MEMORY_ADDR_I32: 124 case R_WASM_MEMORY_ADDR_I64: 125 case R_WASM_FUNCTION_OFFSET_I32: 126 return reloc.Addend; 127 case R_WASM_SECTION_OFFSET_I32: 128 return getSectionSymbol(reloc.Index)->section->outputOffset + reloc.Addend; 129 default: 130 llvm_unreachable("unexpected relocation type"); 131 } 132 } 133 134 // Calculate the value we expect to find at the relocation location. 135 // This is used as a sanity check before applying a relocation to a given 136 // location. It is useful for catching bugs in the compiler and linker. 137 uint64_t ObjFile::calcExpectedValue(const WasmRelocation &reloc) const { 138 switch (reloc.Type) { 139 case R_WASM_TABLE_INDEX_I32: 140 case R_WASM_TABLE_INDEX_I64: 141 case R_WASM_TABLE_INDEX_SLEB: 142 case R_WASM_TABLE_INDEX_SLEB64: { 143 const WasmSymbol &sym = wasmObj->syms()[reloc.Index]; 144 return tableEntries[sym.Info.ElementIndex]; 145 } 146 case R_WASM_TABLE_INDEX_REL_SLEB: { 147 const WasmSymbol &sym = wasmObj->syms()[reloc.Index]; 148 return tableEntriesRel[sym.Info.ElementIndex]; 149 } 150 case R_WASM_MEMORY_ADDR_LEB: 151 case R_WASM_MEMORY_ADDR_LEB64: 152 case R_WASM_MEMORY_ADDR_SLEB: 153 case R_WASM_MEMORY_ADDR_SLEB64: 154 case R_WASM_MEMORY_ADDR_REL_SLEB: 155 case R_WASM_MEMORY_ADDR_REL_SLEB64: 156 case R_WASM_MEMORY_ADDR_I32: 157 case R_WASM_MEMORY_ADDR_I64: { 158 const WasmSymbol &sym = wasmObj->syms()[reloc.Index]; 159 if (sym.isUndefined()) 160 return 0; 161 const WasmSegment &segment = 162 wasmObj->dataSegments()[sym.Info.DataRef.Segment]; 163 if (segment.Data.Offset.Opcode == WASM_OPCODE_I32_CONST) 164 return segment.Data.Offset.Value.Int32 + sym.Info.DataRef.Offset + 165 reloc.Addend; 166 else if (segment.Data.Offset.Opcode == WASM_OPCODE_I64_CONST) 167 return segment.Data.Offset.Value.Int64 + sym.Info.DataRef.Offset + 168 reloc.Addend; 169 else 170 llvm_unreachable("unknown init expr opcode"); 171 } 172 case R_WASM_FUNCTION_OFFSET_I32: { 173 const WasmSymbol &sym = wasmObj->syms()[reloc.Index]; 174 InputFunction *f = 175 functions[sym.Info.ElementIndex - wasmObj->getNumImportedFunctions()]; 176 return f->getFunctionInputOffset() + f->getFunctionCodeOffset() + 177 reloc.Addend; 178 } 179 case R_WASM_SECTION_OFFSET_I32: 180 return reloc.Addend; 181 case R_WASM_TYPE_INDEX_LEB: 182 return reloc.Index; 183 case R_WASM_FUNCTION_INDEX_LEB: 184 case R_WASM_GLOBAL_INDEX_LEB: 185 case R_WASM_GLOBAL_INDEX_I32: 186 case R_WASM_EVENT_INDEX_LEB: { 187 const WasmSymbol &sym = wasmObj->syms()[reloc.Index]; 188 return sym.Info.ElementIndex; 189 } 190 default: 191 llvm_unreachable("unknown relocation type"); 192 } 193 } 194 195 // Translate from the relocation's index into the final linked output value. 196 uint64_t ObjFile::calcNewValue(const WasmRelocation &reloc) const { 197 const Symbol* sym = nullptr; 198 if (reloc.Type != R_WASM_TYPE_INDEX_LEB) { 199 sym = symbols[reloc.Index]; 200 201 // We can end up with relocations against non-live symbols. For example 202 // in debug sections. We return reloc.Addend because always returning zero 203 // causes the generation of spurious range-list terminators in the 204 // .debug_ranges section. 205 if ((isa<FunctionSymbol>(sym) || isa<DataSymbol>(sym)) && !sym->isLive()) 206 return reloc.Addend; 207 } 208 209 switch (reloc.Type) { 210 case R_WASM_TABLE_INDEX_I32: 211 case R_WASM_TABLE_INDEX_I64: 212 case R_WASM_TABLE_INDEX_SLEB: 213 case R_WASM_TABLE_INDEX_SLEB64: 214 case R_WASM_TABLE_INDEX_REL_SLEB: { 215 if (!getFunctionSymbol(reloc.Index)->hasTableIndex()) 216 return 0; 217 uint32_t index = getFunctionSymbol(reloc.Index)->getTableIndex(); 218 if (reloc.Type == R_WASM_TABLE_INDEX_REL_SLEB) 219 index -= config->tableBase; 220 return index; 221 222 } 223 case R_WASM_MEMORY_ADDR_LEB: 224 case R_WASM_MEMORY_ADDR_LEB64: 225 case R_WASM_MEMORY_ADDR_SLEB: 226 case R_WASM_MEMORY_ADDR_SLEB64: 227 case R_WASM_MEMORY_ADDR_REL_SLEB: 228 case R_WASM_MEMORY_ADDR_REL_SLEB64: 229 case R_WASM_MEMORY_ADDR_I32: 230 case R_WASM_MEMORY_ADDR_I64: 231 if (isa<UndefinedData>(sym) || sym->isUndefWeak()) 232 return 0; 233 return cast<DefinedData>(sym)->getVirtualAddress() + reloc.Addend; 234 case R_WASM_TYPE_INDEX_LEB: 235 return typeMap[reloc.Index]; 236 case R_WASM_FUNCTION_INDEX_LEB: 237 return getFunctionSymbol(reloc.Index)->getFunctionIndex(); 238 case R_WASM_GLOBAL_INDEX_LEB: 239 case R_WASM_GLOBAL_INDEX_I32: 240 if (auto gs = dyn_cast<GlobalSymbol>(sym)) 241 return gs->getGlobalIndex(); 242 return sym->getGOTIndex(); 243 case R_WASM_EVENT_INDEX_LEB: 244 return getEventSymbol(reloc.Index)->getEventIndex(); 245 case R_WASM_FUNCTION_OFFSET_I32: { 246 auto *f = cast<DefinedFunction>(sym); 247 return f->function->outputOffset + 248 (f->function->getFunctionCodeOffset() + reloc.Addend); 249 } 250 case R_WASM_SECTION_OFFSET_I32: 251 return getSectionSymbol(reloc.Index)->section->outputOffset + reloc.Addend; 252 default: 253 llvm_unreachable("unknown relocation type"); 254 } 255 } 256 257 template <class T> 258 static void setRelocs(const std::vector<T *> &chunks, 259 const WasmSection *section) { 260 if (!section) 261 return; 262 263 ArrayRef<WasmRelocation> relocs = section->Relocations; 264 assert(llvm::is_sorted( 265 relocs, [](const WasmRelocation &r1, const WasmRelocation &r2) { 266 return r1.Offset < r2.Offset; 267 })); 268 assert(llvm::is_sorted(chunks, [](InputChunk *c1, InputChunk *c2) { 269 return c1->getInputSectionOffset() < c2->getInputSectionOffset(); 270 })); 271 272 auto relocsNext = relocs.begin(); 273 auto relocsEnd = relocs.end(); 274 auto relocLess = [](const WasmRelocation &r, uint32_t val) { 275 return r.Offset < val; 276 }; 277 for (InputChunk *c : chunks) { 278 auto relocsStart = std::lower_bound(relocsNext, relocsEnd, 279 c->getInputSectionOffset(), relocLess); 280 relocsNext = std::lower_bound( 281 relocsStart, relocsEnd, c->getInputSectionOffset() + c->getInputSize(), 282 relocLess); 283 c->setRelocations(ArrayRef<WasmRelocation>(relocsStart, relocsNext)); 284 } 285 } 286 287 void ObjFile::parse(bool ignoreComdats) { 288 // Parse a memory buffer as a wasm file. 289 LLVM_DEBUG(dbgs() << "Parsing object: " << toString(this) << "\n"); 290 std::unique_ptr<Binary> bin = CHECK(createBinary(mb), toString(this)); 291 292 auto *obj = dyn_cast<WasmObjectFile>(bin.get()); 293 if (!obj) 294 fatal(toString(this) + ": not a wasm file"); 295 if (!obj->isRelocatableObject()) 296 fatal(toString(this) + ": not a relocatable wasm file"); 297 298 bin.release(); 299 wasmObj.reset(obj); 300 301 checkArch(obj->getArch()); 302 303 // Build up a map of function indices to table indices for use when 304 // verifying the existing table index relocations 305 uint32_t totalFunctions = 306 wasmObj->getNumImportedFunctions() + wasmObj->functions().size(); 307 tableEntriesRel.resize(totalFunctions); 308 tableEntries.resize(totalFunctions); 309 for (const WasmElemSegment &seg : wasmObj->elements()) { 310 int64_t offset; 311 if (seg.Offset.Opcode == WASM_OPCODE_I32_CONST) 312 offset = seg.Offset.Value.Int32; 313 else if (seg.Offset.Opcode == WASM_OPCODE_I64_CONST) 314 offset = seg.Offset.Value.Int64; 315 else 316 fatal(toString(this) + ": invalid table elements"); 317 for (size_t index = 0; index < seg.Functions.size(); index++) { 318 auto functionIndex = seg.Functions[index]; 319 tableEntriesRel[functionIndex] = index; 320 tableEntries[functionIndex] = offset + index; 321 } 322 } 323 324 uint32_t sectionIndex = 0; 325 326 // Bool for each symbol, true if called directly. This allows us to implement 327 // a weaker form of signature checking where undefined functions that are not 328 // called directly (i.e. only address taken) don't have to match the defined 329 // function's signature. We cannot do this for directly called functions 330 // because those signatures are checked at validation times. 331 // See https://bugs.llvm.org/show_bug.cgi?id=40412 332 std::vector<bool> isCalledDirectly(wasmObj->getNumberOfSymbols(), false); 333 for (const SectionRef &sec : wasmObj->sections()) { 334 const WasmSection §ion = wasmObj->getWasmSection(sec); 335 // Wasm objects can have at most one code and one data section. 336 if (section.Type == WASM_SEC_CODE) { 337 assert(!codeSection); 338 codeSection = §ion; 339 } else if (section.Type == WASM_SEC_DATA) { 340 assert(!dataSection); 341 dataSection = §ion; 342 } else if (section.Type == WASM_SEC_CUSTOM) { 343 customSections.emplace_back(make<InputSection>(section, this)); 344 customSections.back()->setRelocations(section.Relocations); 345 customSectionsByIndex[sectionIndex] = customSections.back(); 346 } 347 sectionIndex++; 348 // Scans relocations to determine if a function symbol is called directly. 349 for (const WasmRelocation &reloc : section.Relocations) 350 if (reloc.Type == R_WASM_FUNCTION_INDEX_LEB) 351 isCalledDirectly[reloc.Index] = true; 352 } 353 354 typeMap.resize(getWasmObj()->types().size()); 355 typeIsUsed.resize(getWasmObj()->types().size(), false); 356 357 ArrayRef<StringRef> comdats = wasmObj->linkingData().Comdats; 358 for (StringRef comdat : comdats) { 359 bool isNew = ignoreComdats || symtab->addComdat(comdat); 360 keptComdats.push_back(isNew); 361 } 362 363 // Populate `Segments`. 364 for (const WasmSegment &s : wasmObj->dataSegments()) { 365 auto* seg = make<InputSegment>(s, this); 366 seg->discarded = isExcludedByComdat(seg); 367 segments.emplace_back(seg); 368 } 369 setRelocs(segments, dataSection); 370 371 // Populate `Functions`. 372 ArrayRef<WasmFunction> funcs = wasmObj->functions(); 373 ArrayRef<uint32_t> funcTypes = wasmObj->functionTypes(); 374 ArrayRef<WasmSignature> types = wasmObj->types(); 375 functions.reserve(funcs.size()); 376 377 for (size_t i = 0, e = funcs.size(); i != e; ++i) { 378 auto* func = make<InputFunction>(types[funcTypes[i]], &funcs[i], this); 379 func->discarded = isExcludedByComdat(func); 380 functions.emplace_back(func); 381 } 382 setRelocs(functions, codeSection); 383 384 // Populate `Globals`. 385 for (const WasmGlobal &g : wasmObj->globals()) 386 globals.emplace_back(make<InputGlobal>(g, this)); 387 388 // Populate `Events`. 389 for (const WasmEvent &e : wasmObj->events()) 390 events.emplace_back(make<InputEvent>(types[e.Type.SigIndex], e, this)); 391 392 // Populate `Symbols` based on the symbols in the object. 393 symbols.reserve(wasmObj->getNumberOfSymbols()); 394 for (const SymbolRef &sym : wasmObj->symbols()) { 395 const WasmSymbol &wasmSym = wasmObj->getWasmSymbol(sym.getRawDataRefImpl()); 396 if (wasmSym.isDefined()) { 397 // createDefined may fail if the symbol is comdat excluded in which case 398 // we fall back to creating an undefined symbol 399 if (Symbol *d = createDefined(wasmSym)) { 400 symbols.push_back(d); 401 continue; 402 } 403 } 404 size_t idx = symbols.size(); 405 symbols.push_back(createUndefined(wasmSym, isCalledDirectly[idx])); 406 } 407 } 408 409 bool ObjFile::isExcludedByComdat(InputChunk *chunk) const { 410 uint32_t c = chunk->getComdat(); 411 if (c == UINT32_MAX) 412 return false; 413 return !keptComdats[c]; 414 } 415 416 FunctionSymbol *ObjFile::getFunctionSymbol(uint32_t index) const { 417 return cast<FunctionSymbol>(symbols[index]); 418 } 419 420 GlobalSymbol *ObjFile::getGlobalSymbol(uint32_t index) const { 421 return cast<GlobalSymbol>(symbols[index]); 422 } 423 424 EventSymbol *ObjFile::getEventSymbol(uint32_t index) const { 425 return cast<EventSymbol>(symbols[index]); 426 } 427 428 SectionSymbol *ObjFile::getSectionSymbol(uint32_t index) const { 429 return cast<SectionSymbol>(symbols[index]); 430 } 431 432 DataSymbol *ObjFile::getDataSymbol(uint32_t index) const { 433 return cast<DataSymbol>(symbols[index]); 434 } 435 436 Symbol *ObjFile::createDefined(const WasmSymbol &sym) { 437 StringRef name = sym.Info.Name; 438 uint32_t flags = sym.Info.Flags; 439 440 switch (sym.Info.Kind) { 441 case WASM_SYMBOL_TYPE_FUNCTION: { 442 InputFunction *func = 443 functions[sym.Info.ElementIndex - wasmObj->getNumImportedFunctions()]; 444 if (sym.isBindingLocal()) 445 return make<DefinedFunction>(name, flags, this, func); 446 if (func->discarded) 447 return nullptr; 448 return symtab->addDefinedFunction(name, flags, this, func); 449 } 450 case WASM_SYMBOL_TYPE_DATA: { 451 InputSegment *seg = segments[sym.Info.DataRef.Segment]; 452 auto offset = sym.Info.DataRef.Offset; 453 auto size = sym.Info.DataRef.Size; 454 if (sym.isBindingLocal()) 455 return make<DefinedData>(name, flags, this, seg, offset, size); 456 if (seg->discarded) 457 return nullptr; 458 return symtab->addDefinedData(name, flags, this, seg, offset, size); 459 } 460 case WASM_SYMBOL_TYPE_GLOBAL: { 461 InputGlobal *global = 462 globals[sym.Info.ElementIndex - wasmObj->getNumImportedGlobals()]; 463 if (sym.isBindingLocal()) 464 return make<DefinedGlobal>(name, flags, this, global); 465 return symtab->addDefinedGlobal(name, flags, this, global); 466 } 467 case WASM_SYMBOL_TYPE_SECTION: { 468 InputSection *section = customSectionsByIndex[sym.Info.ElementIndex]; 469 assert(sym.isBindingLocal()); 470 return make<SectionSymbol>(flags, section, this); 471 } 472 case WASM_SYMBOL_TYPE_EVENT: { 473 InputEvent *event = 474 events[sym.Info.ElementIndex - wasmObj->getNumImportedEvents()]; 475 if (sym.isBindingLocal()) 476 return make<DefinedEvent>(name, flags, this, event); 477 return symtab->addDefinedEvent(name, flags, this, event); 478 } 479 } 480 llvm_unreachable("unknown symbol kind"); 481 } 482 483 Symbol *ObjFile::createUndefined(const WasmSymbol &sym, bool isCalledDirectly) { 484 StringRef name = sym.Info.Name; 485 uint32_t flags = sym.Info.Flags | WASM_SYMBOL_UNDEFINED; 486 487 switch (sym.Info.Kind) { 488 case WASM_SYMBOL_TYPE_FUNCTION: 489 if (sym.isBindingLocal()) 490 return make<UndefinedFunction>(name, sym.Info.ImportName, 491 sym.Info.ImportModule, flags, this, 492 sym.Signature, isCalledDirectly); 493 return symtab->addUndefinedFunction(name, sym.Info.ImportName, 494 sym.Info.ImportModule, flags, this, 495 sym.Signature, isCalledDirectly); 496 case WASM_SYMBOL_TYPE_DATA: 497 if (sym.isBindingLocal()) 498 return make<UndefinedData>(name, flags, this); 499 return symtab->addUndefinedData(name, flags, this); 500 case WASM_SYMBOL_TYPE_GLOBAL: 501 if (sym.isBindingLocal()) 502 return make<UndefinedGlobal>(name, sym.Info.ImportName, 503 sym.Info.ImportModule, flags, this, 504 sym.GlobalType); 505 return symtab->addUndefinedGlobal(name, sym.Info.ImportName, 506 sym.Info.ImportModule, flags, this, 507 sym.GlobalType); 508 case WASM_SYMBOL_TYPE_SECTION: 509 llvm_unreachable("section symbols cannot be undefined"); 510 } 511 llvm_unreachable("unknown symbol kind"); 512 } 513 514 void ArchiveFile::parse() { 515 // Parse a MemoryBufferRef as an archive file. 516 LLVM_DEBUG(dbgs() << "Parsing library: " << toString(this) << "\n"); 517 file = CHECK(Archive::create(mb), toString(this)); 518 519 // Read the symbol table to construct Lazy symbols. 520 int count = 0; 521 for (const Archive::Symbol &sym : file->symbols()) { 522 symtab->addLazy(this, &sym); 523 ++count; 524 } 525 LLVM_DEBUG(dbgs() << "Read " << count << " symbols\n"); 526 } 527 528 void ArchiveFile::addMember(const Archive::Symbol *sym) { 529 const Archive::Child &c = 530 CHECK(sym->getMember(), 531 "could not get the member for symbol " + sym->getName()); 532 533 // Don't try to load the same member twice (this can happen when members 534 // mutually reference each other). 535 if (!seen.insert(c.getChildOffset()).second) 536 return; 537 538 LLVM_DEBUG(dbgs() << "loading lazy: " << sym->getName() << "\n"); 539 LLVM_DEBUG(dbgs() << "from archive: " << toString(this) << "\n"); 540 541 MemoryBufferRef mb = 542 CHECK(c.getMemoryBufferRef(), 543 "could not get the buffer for the member defining symbol " + 544 sym->getName()); 545 546 InputFile *obj = createObjectFile(mb, getName()); 547 symtab->addFile(obj); 548 } 549 550 static uint8_t mapVisibility(GlobalValue::VisibilityTypes gvVisibility) { 551 switch (gvVisibility) { 552 case GlobalValue::DefaultVisibility: 553 return WASM_SYMBOL_VISIBILITY_DEFAULT; 554 case GlobalValue::HiddenVisibility: 555 case GlobalValue::ProtectedVisibility: 556 return WASM_SYMBOL_VISIBILITY_HIDDEN; 557 } 558 llvm_unreachable("unknown visibility"); 559 } 560 561 static Symbol *createBitcodeSymbol(const std::vector<bool> &keptComdats, 562 const lto::InputFile::Symbol &objSym, 563 BitcodeFile &f) { 564 StringRef name = saver.save(objSym.getName()); 565 566 uint32_t flags = objSym.isWeak() ? WASM_SYMBOL_BINDING_WEAK : 0; 567 flags |= mapVisibility(objSym.getVisibility()); 568 569 int c = objSym.getComdatIndex(); 570 bool excludedByComdat = c != -1 && !keptComdats[c]; 571 572 if (objSym.isUndefined() || excludedByComdat) { 573 flags |= WASM_SYMBOL_UNDEFINED; 574 if (objSym.isExecutable()) 575 return symtab->addUndefinedFunction(name, None, None, flags, &f, nullptr, 576 true); 577 return symtab->addUndefinedData(name, flags, &f); 578 } 579 580 if (objSym.isExecutable()) 581 return symtab->addDefinedFunction(name, flags, &f, nullptr); 582 return symtab->addDefinedData(name, flags, &f, nullptr, 0, 0); 583 } 584 585 bool BitcodeFile::doneLTO = false; 586 587 void BitcodeFile::parse() { 588 if (doneLTO) { 589 error(toString(this) + ": attempt to add bitcode file after LTO."); 590 return; 591 } 592 593 obj = check(lto::InputFile::create(MemoryBufferRef( 594 mb.getBuffer(), saver.save(archiveName + mb.getBufferIdentifier())))); 595 Triple t(obj->getTargetTriple()); 596 if (!t.isWasm()) { 597 error(toString(this) + ": machine type must be wasm32 or wasm64"); 598 return; 599 } 600 checkArch(t.getArch()); 601 std::vector<bool> keptComdats; 602 for (StringRef s : obj->getComdatTable()) 603 keptComdats.push_back(symtab->addComdat(s)); 604 605 for (const lto::InputFile::Symbol &objSym : obj->symbols()) 606 symbols.push_back(createBitcodeSymbol(keptComdats, objSym, *this)); 607 } 608 609 } // namespace wasm 610 } // namespace lld 611