947 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "InputFiles.h"10#include "Config.h"11#include "InputChunks.h"12#include "InputElement.h"13#include "OutputSegment.h"14#include "SymbolTable.h"15#include "lld/Common/CommonLinkerContext.h"16#include "lld/Common/Reproduce.h"17#include "llvm/BinaryFormat/Wasm.h"18#include "llvm/Object/Binary.h"19#include "llvm/Object/Wasm.h"20#include "llvm/ProfileData/InstrProf.h"21#include "llvm/Support/Path.h"22#include "llvm/Support/TarWriter.h"23#include "llvm/Support/raw_ostream.h"24#include <optional>25 26#define DEBUG_TYPE "lld"27 28using namespace llvm;29using namespace llvm::object;30using namespace llvm::wasm;31using namespace llvm::sys;32 33namespace lld {34 35// Returns a string in the format of "foo.o" or "foo.a(bar.o)".36std::string toString(const wasm::InputFile *file) {37 if (!file)38 return "<internal>";39 40 if (file->archiveName.empty())41 return std::string(file->getName());42 43 return (file->archiveName + "(" + file->getName() + ")").str();44}45 46namespace wasm {47 48std::string replaceThinLTOSuffix(StringRef path) {49 auto [suffix, repl] = ctx.arg.thinLTOObjectSuffixReplace;50 if (path.consume_back(suffix))51 return (path + repl).str();52 return std::string(path);53}54 55void InputFile::checkArch(Triple::ArchType arch) const {56 bool is64 = arch == Triple::wasm64;57 if (is64 && !ctx.arg.is64) {58 fatal(toString(this) +59 ": must specify -mwasm64 to process wasm64 object files");60 } else if (ctx.arg.is64.value_or(false) != is64) {61 fatal(toString(this) +62 ": wasm32 object file can't be linked in wasm64 mode");63 }64}65 66std::unique_ptr<llvm::TarWriter> tar;67 68std::optional<MemoryBufferRef> readFile(StringRef path) {69 log("Loading: " + path);70 71 auto mbOrErr = MemoryBuffer::getFile(path);72 if (auto ec = mbOrErr.getError()) {73 error("cannot open " + path + ": " + ec.message());74 return std::nullopt;75 }76 std::unique_ptr<MemoryBuffer> &mb = *mbOrErr;77 MemoryBufferRef mbref = mb->getMemBufferRef();78 make<std::unique_ptr<MemoryBuffer>>(std::move(mb)); // take MB ownership79 80 if (tar)81 tar->append(relativeToRoot(path), mbref.getBuffer());82 return mbref;83}84 85InputFile *createObjectFile(MemoryBufferRef mb, StringRef archiveName,86 uint64_t offsetInArchive, bool lazy) {87 file_magic magic = identify_magic(mb.getBuffer());88 if (magic == file_magic::wasm_object) {89 std::unique_ptr<Binary> bin =90 CHECK(createBinary(mb), mb.getBufferIdentifier());91 auto *obj = cast<WasmObjectFile>(bin.get());92 if (obj->hasUnmodeledTypes())93 fatal(toString(mb.getBufferIdentifier()) +94 "file has unmodeled reference or GC types");95 if (obj->isSharedObject())96 return make<SharedFile>(mb);97 return make<ObjFile>(mb, archiveName, lazy);98 }99 100 assert(magic == file_magic::bitcode);101 return make<BitcodeFile>(mb, archiveName, offsetInArchive, lazy);102}103 104// Relocations contain either symbol or type indices. This function takes a105// relocation and returns relocated index (i.e. translates from the input106// symbol/type space to the output symbol/type space).107uint32_t ObjFile::calcNewIndex(const WasmRelocation &reloc) const {108 if (reloc.Type == R_WASM_TYPE_INDEX_LEB) {109 assert(typeIsUsed[reloc.Index]);110 return typeMap[reloc.Index];111 }112 const Symbol *sym = symbols[reloc.Index];113 if (auto *ss = dyn_cast<SectionSymbol>(sym))114 sym = ss->getOutputSectionSymbol();115 return sym->getOutputSymbolIndex();116}117 118// Relocations can contain addend for combined sections. This function takes a119// relocation and returns updated addend by offset in the output section.120int64_t ObjFile::calcNewAddend(const WasmRelocation &reloc) const {121 switch (reloc.Type) {122 case R_WASM_MEMORY_ADDR_LEB:123 case R_WASM_MEMORY_ADDR_LEB64:124 case R_WASM_MEMORY_ADDR_SLEB64:125 case R_WASM_MEMORY_ADDR_SLEB:126 case R_WASM_MEMORY_ADDR_REL_SLEB:127 case R_WASM_MEMORY_ADDR_REL_SLEB64:128 case R_WASM_MEMORY_ADDR_I32:129 case R_WASM_MEMORY_ADDR_I64:130 case R_WASM_MEMORY_ADDR_TLS_SLEB:131 case R_WASM_MEMORY_ADDR_TLS_SLEB64:132 case R_WASM_FUNCTION_OFFSET_I32:133 case R_WASM_FUNCTION_OFFSET_I64:134 case R_WASM_MEMORY_ADDR_LOCREL_I32:135 return reloc.Addend;136 case R_WASM_SECTION_OFFSET_I32:137 return getSectionSymbol(reloc.Index)->section->getOffset(reloc.Addend);138 default:139 llvm_unreachable("unexpected relocation type");140 }141}142 143// Translate from the relocation's index into the final linked output value.144uint64_t ObjFile::calcNewValue(const WasmRelocation &reloc, uint64_t tombstone,145 const InputChunk *chunk) const {146 const Symbol* sym = nullptr;147 if (reloc.Type != R_WASM_TYPE_INDEX_LEB) {148 sym = symbols[reloc.Index];149 150 // We can end up with relocations against non-live symbols. For example151 // in debug sections. We return a tombstone value in debug symbol sections152 // so this will not produce a valid range conflicting with ranges of actual153 // code. In other sections we return reloc.Addend.154 155 if (!isa<SectionSymbol>(sym) && !sym->isLive())156 return tombstone ? tombstone : reloc.Addend;157 }158 159 switch (reloc.Type) {160 case R_WASM_TABLE_INDEX_I32:161 case R_WASM_TABLE_INDEX_I64:162 case R_WASM_TABLE_INDEX_SLEB:163 case R_WASM_TABLE_INDEX_SLEB64:164 case R_WASM_TABLE_INDEX_REL_SLEB:165 case R_WASM_TABLE_INDEX_REL_SLEB64: {166 if (!getFunctionSymbol(reloc.Index)->hasTableIndex())167 return 0;168 uint32_t index = getFunctionSymbol(reloc.Index)->getTableIndex();169 if (reloc.Type == R_WASM_TABLE_INDEX_REL_SLEB ||170 reloc.Type == R_WASM_TABLE_INDEX_REL_SLEB64)171 index -= ctx.arg.tableBase;172 return index;173 }174 case R_WASM_MEMORY_ADDR_LEB:175 case R_WASM_MEMORY_ADDR_LEB64:176 case R_WASM_MEMORY_ADDR_SLEB:177 case R_WASM_MEMORY_ADDR_SLEB64:178 case R_WASM_MEMORY_ADDR_REL_SLEB:179 case R_WASM_MEMORY_ADDR_REL_SLEB64:180 case R_WASM_MEMORY_ADDR_I32:181 case R_WASM_MEMORY_ADDR_I64:182 case R_WASM_MEMORY_ADDR_TLS_SLEB:183 case R_WASM_MEMORY_ADDR_TLS_SLEB64:184 case R_WASM_MEMORY_ADDR_LOCREL_I32: {185 // glibc/wasm32 (HWJS-B-1): after commit 12776b692, a strong undefined-DATA186 // reference (e.g. the RHS of a GNU-as alias `memset = __GI_memset`, which187 // MC necessarily types DATA) can resolve to a real FUNCTION definition of188 // the same name. When a memory-address relocation then *takes the address*189 // of that symbol, the wasm function-pointer value is its index in190 // __indirect_function_table -- exactly the value a normal191 // R_WASM_TABLE_INDEX_* relocation computes -- not a data VA. Compute that192 // here instead of crashing in cast<DefinedData>()/getVA() on a symbol that193 // has no data layout. scanRelocations() registers such a function in the194 // indirect function table so a real table index exists.195 if (auto *f = dyn_cast<FunctionSymbol>(sym)) {196 switch (reloc.Type) {197 case R_WASM_MEMORY_ADDR_LEB:198 case R_WASM_MEMORY_ADDR_LEB64:199 case R_WASM_MEMORY_ADDR_SLEB:200 case R_WASM_MEMORY_ADDR_SLEB64:201 case R_WASM_MEMORY_ADDR_I32:202 case R_WASM_MEMORY_ADDR_I64:203 // A plain absolute address slot holds the function pointer (table204 // index). A stub/undefined function has no table entry and its205 // address is the null function pointer (table index 0); this mirrors206 // the R_WASM_TABLE_INDEX_* path exactly.207 if (!f->hasTableIndex())208 return 0;209 return f->getTableIndex() + reloc.Addend;210 default:211 // The memory-base-relative (REL), TLS, and LOCREL forms are relative212 // to __memory_base/__tls_base or PC, none of which can represent a213 // function pointer (which is __table_base-relative). Never silently214 // emit a wrong/zero value -- diagnose loudly instead.215 error(toString(this) + ": relocation " + relocTypeToString(reloc.Type) +216 " cannot take the address of function `" + toString(*sym) +217 "`; a function pointer is a table index, not a memory address");218 return 0;219 }220 }221 if (isa<UndefinedData>(sym) || sym->isShared() || sym->isUndefWeak())222 return 0;223 auto D = cast<DefinedData>(sym);224 uint64_t value = D->getVA() + reloc.Addend;225 if (reloc.Type == R_WASM_MEMORY_ADDR_LOCREL_I32) {226 const auto *segment = cast<InputSegment>(chunk);227 uint64_t p = segment->outputSeg->startVA + segment->outputSegmentOffset +228 reloc.Offset - segment->getInputSectionOffset();229 value -= p;230 }231 return value;232 }233 case R_WASM_TYPE_INDEX_LEB:234 return typeMap[reloc.Index];235 case R_WASM_FUNCTION_INDEX_LEB:236 case R_WASM_FUNCTION_INDEX_I32: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_TAG_INDEX_LEB:244 return getTagSymbol(reloc.Index)->getTagIndex();245 case R_WASM_FUNCTION_OFFSET_I32:246 case R_WASM_FUNCTION_OFFSET_I64: {247 if (isa<UndefinedFunction>(sym)) {248 return tombstone ? tombstone : reloc.Addend;249 }250 auto *f = cast<DefinedFunction>(sym);251 return f->function->getOffset(f->function->getFunctionCodeOffset() +252 reloc.Addend);253 }254 case R_WASM_SECTION_OFFSET_I32:255 return getSectionSymbol(reloc.Index)->section->getOffset(reloc.Addend);256 case R_WASM_TABLE_NUMBER_LEB:257 return getTableSymbol(reloc.Index)->getTableNumber();258 default:259 llvm_unreachable("unknown relocation type");260 }261}262 263template <class T>264static void setRelocs(const std::vector<T *> &chunks,265 const WasmSection *section) {266 if (!section)267 return;268 269 ArrayRef<WasmRelocation> relocs = section->Relocations;270 assert(llvm::is_sorted(271 relocs, [](const WasmRelocation &r1, const WasmRelocation &r2) {272 return r1.Offset < r2.Offset;273 }));274 assert(llvm::is_sorted(chunks, [](InputChunk *c1, InputChunk *c2) {275 return c1->getInputSectionOffset() < c2->getInputSectionOffset();276 }));277 278 auto relocsNext = relocs.begin();279 auto relocsEnd = relocs.end();280 auto relocLess = [](const WasmRelocation &r, uint32_t val) {281 return r.Offset < val;282 };283 for (InputChunk *c : chunks) {284 auto relocsStart = std::lower_bound(relocsNext, relocsEnd,285 c->getInputSectionOffset(), relocLess);286 relocsNext = std::lower_bound(287 relocsStart, relocsEnd, c->getInputSectionOffset() + c->getInputSize(),288 relocLess);289 c->setRelocations(ArrayRef<WasmRelocation>(relocsStart, relocsNext));290 }291}292 293// An object file can have two approaches to tables. With the294// reference-types feature or call-indirect-overlong feature enabled295// (explicitly, or implied by the reference-types feature), input files that296// define or use tables declare the tables using symbols, and record each use297// with a relocation. This way when the linker combines inputs, it can collate298// the tables used by the inputs, assigning them distinct table numbers, and299// renumber all the uses as appropriate. At the same time, the linker has300// special logic to build the indirect function table if it is needed.301//302// However, MVP object files (those that target WebAssembly 1.0, the "minimum303// viable product" version of WebAssembly) neither write table symbols nor304// record relocations. These files can have at most one table, the indirect305// function table used by call_indirect and which is the address space for306// function pointers. If this table is present, it is always an import. If we307// have a file with a table import but no table symbols, it is an MVP object308// file. synthesizeMVPIndirectFunctionTableSymbolIfNeeded serves as a shim when309// loading these input files, defining the missing symbol to allow the indirect310// function table to be built.311//312// As indirect function table table usage in MVP objects cannot be relocated,313// the linker must ensure that this table gets assigned index zero.314void ObjFile::addLegacyIndirectFunctionTableIfNeeded(315 uint32_t tableSymbolCount) {316 uint32_t tableCount = wasmObj->getNumImportedTables() + tables.size();317 318 // If there are symbols for all tables, then all is good.319 if (tableCount == tableSymbolCount)320 return;321 322 // It's possible for an input to define tables and also use the indirect323 // function table, but forget to compile with -mattr=+call-indirect-overlong324 // or -mattr=+reference-types. For these newer files, we require symbols for325 // all tables, and relocations for all of their uses.326 if (tableSymbolCount != 0) {327 error(toString(this) +328 ": expected one symbol table entry for each of the " +329 Twine(tableCount) + " table(s) present, but got " +330 Twine(tableSymbolCount) + " symbol(s) instead.");331 return;332 }333 334 // An MVP object file can have up to one table import, for the indirect335 // function table, but will have no table definitions.336 if (tables.size()) {337 error(toString(this) +338 ": unexpected table definition(s) without corresponding "339 "symbol-table entries.");340 return;341 }342 343 // An MVP object file can have only one table import.344 if (tableCount != 1) {345 error(toString(this) +346 ": multiple table imports, but no corresponding symbol-table "347 "entries.");348 return;349 }350 351 const WasmImport *tableImport = nullptr;352 for (const auto &import : wasmObj->imports()) {353 if (import.Kind == WASM_EXTERNAL_TABLE) {354 assert(!tableImport);355 tableImport = &import;356 }357 }358 assert(tableImport);359 360 // We can only synthesize a symtab entry for the indirect function table; if361 // it has an unexpected name or type, assume that it's not actually the362 // indirect function table.363 if (tableImport->Field != functionTableName ||364 tableImport->Table.ElemType != ValType::FUNCREF) {365 error(toString(this) + ": table import " + Twine(tableImport->Field) +366 " is missing a symbol table entry.");367 return;368 }369 370 WasmSymbolInfo info;371 info.Name = tableImport->Field;372 info.Kind = WASM_SYMBOL_TYPE_TABLE;373 info.ImportModule = tableImport->Module;374 info.ImportName = tableImport->Field;375 info.Flags = WASM_SYMBOL_UNDEFINED | WASM_SYMBOL_NO_STRIP;376 info.ElementIndex = 0;377 LLVM_DEBUG(dbgs() << "Synthesizing symbol for table import: " << info.Name378 << "\n");379 const WasmGlobalType *globalType = nullptr;380 const WasmSignature *signature = nullptr;381 auto *wasmSym =382 make<WasmSymbol>(info, globalType, &tableImport->Table, signature);383 Symbol *sym = createUndefined(*wasmSym, false);384 // We're only sure it's a TableSymbol if the createUndefined succeeded.385 if (errorCount())386 return;387 symbols.push_back(sym);388 // Because there are no TABLE_NUMBER relocs, we can't compute accurate389 // liveness info; instead, just mark the symbol as always live.390 sym->markLive();391 392 // We assume that this compilation unit has unrelocatable references to393 // this table.394 ctx.legacyFunctionTable = true;395}396 397static bool shouldMerge(const WasmSection &sec) {398 if (ctx.arg.optimize == 0)399 return false;400 // Sadly we don't have section attributes yet for custom sections, so we401 // currently go by the name alone.402 // TODO(sbc): Add ability for wasm sections to carry flags so we don't403 // need to use names here.404 // For now, keep in sync with uses of wasm::WASM_SEG_FLAG_STRINGS in405 // MCObjectFileInfo::initWasmMCObjectFileInfo which creates these custom406 // sections.407 return sec.Name == ".debug_str" || sec.Name == ".debug_str.dwo" ||408 sec.Name == ".debug_line_str";409}410 411static bool shouldMerge(const WasmSegment &seg) {412 // As of now we only support merging strings, and only with single byte413 // alignment (2^0).414 if (!(seg.Data.LinkingFlags & WASM_SEG_FLAG_STRINGS) ||415 (seg.Data.Alignment != 0))416 return false;417 418 // On a regular link we don't merge sections if -O0 (default is -O1). This419 // sometimes makes the linker significantly faster, although the output will420 // be bigger.421 if (ctx.arg.optimize == 0)422 return false;423 424 // A mergeable section with size 0 is useless because they don't have425 // any data to merge. A mergeable string section with size 0 can be426 // argued as invalid because it doesn't end with a null character.427 // We'll avoid a mess by handling them as if they were non-mergeable.428 if (seg.Data.Content.size() == 0)429 return false;430 431 return true;432}433 434void ObjFile::parseLazy() {435 LLVM_DEBUG(dbgs() << "ObjFile::parseLazy: " << toString(this) << " "436 << wasmObj.get() << "\n");437 for (const SymbolRef &sym : wasmObj->symbols()) {438 const WasmSymbol &wasmSym = wasmObj->getWasmSymbol(sym.getRawDataRefImpl());439 if (wasmSym.isUndefined() || wasmSym.isBindingLocal())440 continue;441 symtab->addLazy(wasmSym.Info.Name, this);442 // addLazy() may trigger this->extract() if an existing symbol is an443 // undefined symbol. If that happens, this function has served its purpose,444 // and we can exit from the loop early.445 if (!lazy)446 break;447 }448}449 450ObjFile::ObjFile(MemoryBufferRef m, StringRef archiveName, bool lazy)451 : WasmFileBase(ObjectKind, m) {452 this->lazy = lazy;453 this->archiveName = std::string(archiveName);454 455 // Currently we only do this check for regular object file, and not for shared456 // object files. This is because architecture detection for shared objects is457 // currently based on a heuristic, which is fallable:458 // https://github.com/llvm/llvm-project/issues/98778459 checkArch(wasmObj->getArch());460 461 // Unless we are processing this as a lazy object file (e.g. part of an462 // archive file or within `--start-lib`/`--end-lib`, it's eagerly linked, so463 // mark it live.464 if (!lazy)465 markLive();466}467 468void SharedFile::parse() {469 assert(wasmObj->isSharedObject());470 471 for (const SymbolRef &sym : wasmObj->symbols()) {472 const WasmSymbol &wasmSym = wasmObj->getWasmSymbol(sym.getRawDataRefImpl());473 if (wasmSym.isDefined()) {474 StringRef name = wasmSym.Info.Name;475 // Certain shared library exports are known to be DSO-local so we476 // don't want to add them to the symbol table.477 // TODO(sbc): Instead of hardcoding these here perhaps we could add478 // this as extra metadata in the `dylink` section.479 if (name == "__wasm_apply_data_relocs" || name == "__wasm_call_ctors" ||480 name.starts_with("__start_") || name.starts_with("__stop_"))481 continue;482 uint32_t flags = wasmSym.Info.Flags;483 Symbol *s;484 LLVM_DEBUG(dbgs() << "shared symbol: " << name << "\n");485 switch (wasmSym.Info.Kind) {486 case WASM_SYMBOL_TYPE_FUNCTION:487 s = symtab->addSharedFunction(name, flags, this, wasmSym.Signature);488 break;489 case WASM_SYMBOL_TYPE_DATA:490 s = symtab->addSharedData(name, flags, this);491 break;492 default:493 continue;494 }495 symbols.push_back(s);496 }497 }498}499 500// Returns the alignment for a custom section. This is used to concatenate501// custom sections with the same name into a single custom section.502static uint32_t getCustomSectionAlignment(const WasmSection &sec) {503 // TODO: Add a section attribute for alignment in the linking spec.504 if (sec.Name == getInstrProfSectionName(IPSK_covfun, Triple::Wasm) ||505 sec.Name == getInstrProfSectionName(IPSK_covmap, Triple::Wasm)) {506 // llvm-cov assumes that coverage metadata sections are 8-byte aligned.507 return 8;508 }509 return 1;510}511 512WasmFileBase::WasmFileBase(Kind k, MemoryBufferRef m) : InputFile(k, m) {513 // Parse a memory buffer as a wasm file.514 LLVM_DEBUG(dbgs() << "Reading object: " << toString(this) << "\n");515 std::unique_ptr<Binary> bin = CHECK(createBinary(mb), toString(this));516 517 auto *obj = dyn_cast<WasmObjectFile>(bin.get());518 if (!obj)519 fatal(toString(this) + ": not a wasm file");520 521 bin.release();522 wasmObj.reset(obj);523}524 525void ObjFile::parse(bool ignoreComdats) {526 // Parse a memory buffer as a wasm file.527 LLVM_DEBUG(dbgs() << "ObjFile::parse: " << toString(this) << "\n");528 529 if (!wasmObj->isRelocatableObject())530 fatal(toString(this) + ": not a relocatable wasm file");531 532 // Build up a map of function indices to table indices for use when533 // verifying the existing table index relocations534 uint32_t totalFunctions =535 wasmObj->getNumImportedFunctions() + wasmObj->functions().size();536 tableEntriesRel.resize(totalFunctions);537 tableEntries.resize(totalFunctions);538 for (const WasmElemSegment &seg : wasmObj->elements()) {539 int64_t offset;540 if (seg.Offset.Extended)541 fatal(toString(this) + ": extended init exprs not supported");542 else if (seg.Offset.Inst.Opcode == WASM_OPCODE_I32_CONST)543 offset = seg.Offset.Inst.Value.Int32;544 else if (seg.Offset.Inst.Opcode == WASM_OPCODE_I64_CONST)545 offset = seg.Offset.Inst.Value.Int64;546 else547 fatal(toString(this) + ": invalid table elements");548 for (size_t index = 0; index < seg.Functions.size(); index++) {549 auto functionIndex = seg.Functions[index];550 tableEntriesRel[functionIndex] = index;551 tableEntries[functionIndex] = offset + index;552 }553 }554 555 ArrayRef<StringRef> comdats = wasmObj->linkingData().Comdats;556 for (StringRef comdat : comdats) {557 bool isNew = ignoreComdats || symtab->addComdat(comdat);558 keptComdats.push_back(isNew);559 }560 561 uint32_t sectionIndex = 0;562 563 // Bool for each symbol, true if called directly. This allows us to implement564 // a weaker form of signature checking where undefined functions that are not565 // called directly (i.e. only address taken) don't have to match the defined566 // function's signature. We cannot do this for directly called functions567 // because those signatures are checked at validation times.568 // See https://github.com/llvm/llvm-project/issues/39758569 std::vector<bool> isCalledDirectly(wasmObj->getNumberOfSymbols(), false);570 for (const SectionRef &sec : wasmObj->sections()) {571 const WasmSection §ion = wasmObj->getWasmSection(sec);572 // Wasm objects can have at most one code and one data section.573 if (section.Type == WASM_SEC_CODE) {574 assert(!codeSection);575 codeSection = §ion;576 } else if (section.Type == WASM_SEC_DATA) {577 assert(!dataSection);578 dataSection = §ion;579 } else if (section.Type == WASM_SEC_CUSTOM) {580 InputChunk *customSec;581 uint32_t alignment = getCustomSectionAlignment(section);582 if (shouldMerge(section))583 customSec = make<MergeInputChunk>(section, this, alignment);584 else585 customSec = make<InputSection>(section, this, alignment);586 customSec->discarded = isExcludedByComdat(customSec);587 customSections.emplace_back(customSec);588 customSections.back()->setRelocations(section.Relocations);589 customSectionsByIndex[sectionIndex] = customSections.back();590 }591 sectionIndex++;592 // Scans relocations to determine if a function symbol is called directly.593 for (const WasmRelocation &reloc : section.Relocations)594 if (reloc.Type == R_WASM_FUNCTION_INDEX_LEB)595 isCalledDirectly[reloc.Index] = true;596 }597 598 typeMap.resize(getWasmObj()->types().size());599 typeIsUsed.resize(getWasmObj()->types().size(), false);600 601 602 // Populate `Segments`.603 for (const WasmSegment &s : wasmObj->dataSegments()) {604 InputChunk *seg;605 if (shouldMerge(s))606 seg = make<MergeInputChunk>(s, this);607 else608 seg = make<InputSegment>(s, this);609 seg->discarded = isExcludedByComdat(seg);610 // Older object files did not include WASM_SEG_FLAG_TLS and instead611 // relied on the naming convention. To maintain compat with such objects612 // we still imply the TLS flag based on the name of the segment.613 if (!seg->isTLS() &&614 (seg->name.starts_with(".tdata") || seg->name.starts_with(".tbss")))615 seg->flags |= WASM_SEG_FLAG_TLS;616 segments.emplace_back(seg);617 }618 setRelocs(segments, dataSection);619 620 // Populate `Functions`.621 ArrayRef<WasmFunction> funcs = wasmObj->functions();622 ArrayRef<WasmSignature> types = wasmObj->types();623 functions.reserve(funcs.size());624 625 for (auto &f : funcs) {626 auto *func = make<InputFunction>(types[f.SigIndex], &f, this);627 func->discarded = isExcludedByComdat(func);628 functions.emplace_back(func);629 }630 setRelocs(functions, codeSection);631 632 // Populate `Tables`.633 for (const WasmTable &t : wasmObj->tables())634 tables.emplace_back(make<InputTable>(t, this));635 636 // Populate `Globals`.637 for (const WasmGlobal &g : wasmObj->globals())638 globals.emplace_back(make<InputGlobal>(g, this));639 640 // Populate `Tags`.641 for (const WasmTag &t : wasmObj->tags())642 tags.emplace_back(make<InputTag>(types[t.SigIndex], t, this));643 644 // Populate `Symbols` based on the symbols in the object.645 symbols.reserve(wasmObj->getNumberOfSymbols());646 uint32_t tableSymbolCount = 0;647 for (const SymbolRef &sym : wasmObj->symbols()) {648 const WasmSymbol &wasmSym = wasmObj->getWasmSymbol(sym.getRawDataRefImpl());649 if (wasmSym.isTypeTable())650 tableSymbolCount++;651 if (wasmSym.isDefined()) {652 // createDefined may fail if the symbol is comdat excluded in which case653 // we fall back to creating an undefined symbol654 if (Symbol *d = createDefined(wasmSym)) {655 symbols.push_back(d);656 continue;657 }658 }659 size_t idx = symbols.size();660 symbols.push_back(createUndefined(wasmSym, isCalledDirectly[idx]));661 }662 663 addLegacyIndirectFunctionTableIfNeeded(tableSymbolCount);664}665 666bool ObjFile::isExcludedByComdat(const InputChunk *chunk) const {667 uint32_t c = chunk->getComdat();668 if (c == UINT32_MAX)669 return false;670 return !keptComdats[c];671}672 673FunctionSymbol *ObjFile::getFunctionSymbol(uint32_t index) const {674 return cast<FunctionSymbol>(symbols[index]);675}676 677GlobalSymbol *ObjFile::getGlobalSymbol(uint32_t index) const {678 return cast<GlobalSymbol>(symbols[index]);679}680 681TagSymbol *ObjFile::getTagSymbol(uint32_t index) const {682 return cast<TagSymbol>(symbols[index]);683}684 685TableSymbol *ObjFile::getTableSymbol(uint32_t index) const {686 return cast<TableSymbol>(symbols[index]);687}688 689SectionSymbol *ObjFile::getSectionSymbol(uint32_t index) const {690 return cast<SectionSymbol>(symbols[index]);691}692 693DataSymbol *ObjFile::getDataSymbol(uint32_t index) const {694 return cast<DataSymbol>(symbols[index]);695}696 697Symbol *ObjFile::createDefined(const WasmSymbol &sym) {698 StringRef name = sym.Info.Name;699 uint32_t flags = sym.Info.Flags;700 701 switch (sym.Info.Kind) {702 case WASM_SYMBOL_TYPE_FUNCTION: {703 InputFunction *func =704 functions[sym.Info.ElementIndex - wasmObj->getNumImportedFunctions()];705 if (sym.isBindingLocal())706 return make<DefinedFunction>(name, flags, this, func);707 if (func->discarded)708 return nullptr;709 return symtab->addDefinedFunction(name, flags, this, func);710 }711 case WASM_SYMBOL_TYPE_DATA: {712 InputChunk *seg = segments[sym.Info.DataRef.Segment];713 auto offset = sym.Info.DataRef.Offset;714 auto size = sym.Info.DataRef.Size;715 // Support older (e.g. llvm 13) object files that pre-date the per-symbol716 // TLS flag, and symbols were assumed to be TLS by being defined in a TLS717 // segment.718 if (!(flags & WASM_SYMBOL_TLS) && seg->isTLS())719 flags |= WASM_SYMBOL_TLS;720 if (sym.isBindingLocal())721 return make<DefinedData>(name, flags, this, seg, offset, size);722 if (seg->discarded)723 return nullptr;724 return symtab->addDefinedData(name, flags, this, seg, offset, size);725 }726 case WASM_SYMBOL_TYPE_GLOBAL: {727 InputGlobal *global =728 globals[sym.Info.ElementIndex - wasmObj->getNumImportedGlobals()];729 if (sym.isBindingLocal())730 return make<DefinedGlobal>(name, flags, this, global);731 return symtab->addDefinedGlobal(name, flags, this, global);732 }733 case WASM_SYMBOL_TYPE_SECTION: {734 InputChunk *section = customSectionsByIndex[sym.Info.ElementIndex];735 assert(sym.isBindingLocal());736 // Need to return null if discarded here? data and func only do that when737 // binding is not local.738 if (section->discarded)739 return nullptr;740 return make<SectionSymbol>(flags, section, this);741 }742 case WASM_SYMBOL_TYPE_TAG: {743 InputTag *tag = tags[sym.Info.ElementIndex - wasmObj->getNumImportedTags()];744 if (sym.isBindingLocal())745 return make<DefinedTag>(name, flags, this, tag);746 return symtab->addDefinedTag(name, flags, this, tag);747 }748 case WASM_SYMBOL_TYPE_TABLE: {749 InputTable *table =750 tables[sym.Info.ElementIndex - wasmObj->getNumImportedTables()];751 if (sym.isBindingLocal())752 return make<DefinedTable>(name, flags, this, table);753 return symtab->addDefinedTable(name, flags, this, table);754 }755 }756 llvm_unreachable("unknown symbol kind");757}758 759Symbol *ObjFile::createUndefined(const WasmSymbol &sym, bool isCalledDirectly) {760 StringRef name = sym.Info.Name;761 uint32_t flags = sym.Info.Flags | WASM_SYMBOL_UNDEFINED;762 763 switch (sym.Info.Kind) {764 case WASM_SYMBOL_TYPE_FUNCTION:765 if (sym.isBindingLocal())766 return make<UndefinedFunction>(name, sym.Info.ImportName,767 sym.Info.ImportModule, flags, this,768 sym.Signature, isCalledDirectly);769 return symtab->addUndefinedFunction(name, sym.Info.ImportName,770 sym.Info.ImportModule, flags, this,771 sym.Signature, isCalledDirectly);772 case WASM_SYMBOL_TYPE_DATA:773 if (sym.isBindingLocal())774 return make<UndefinedData>(name, flags, this);775 return symtab->addUndefinedData(name, flags, this);776 case WASM_SYMBOL_TYPE_GLOBAL:777 if (sym.isBindingLocal())778 return make<UndefinedGlobal>(name, sym.Info.ImportName,779 sym.Info.ImportModule, flags, this,780 sym.GlobalType);781 return symtab->addUndefinedGlobal(name, sym.Info.ImportName,782 sym.Info.ImportModule, flags, this,783 sym.GlobalType);784 case WASM_SYMBOL_TYPE_TABLE:785 if (sym.isBindingLocal())786 return make<UndefinedTable>(name, sym.Info.ImportName,787 sym.Info.ImportModule, flags, this,788 sym.TableType);789 return symtab->addUndefinedTable(name, sym.Info.ImportName,790 sym.Info.ImportModule, flags, this,791 sym.TableType);792 case WASM_SYMBOL_TYPE_TAG:793 if (sym.isBindingLocal())794 return make<UndefinedTag>(name, sym.Info.ImportName,795 sym.Info.ImportModule, flags, this,796 sym.Signature);797 return symtab->addUndefinedTag(name, sym.Info.ImportName,798 sym.Info.ImportModule, flags, this,799 sym.Signature);800 case WASM_SYMBOL_TYPE_SECTION:801 llvm_unreachable("section symbols cannot be undefined");802 }803 llvm_unreachable("unknown symbol kind");804}805 806static StringRef strip(StringRef s) { return s.trim(' '); }807 808void StubFile::parse() {809 bool first = true;810 811 SmallVector<StringRef> lines;812 mb.getBuffer().split(lines, '\n');813 for (StringRef line : lines) {814 line = line.trim();815 816 // File must begin with #STUB817 if (first) {818 assert(line == "#STUB");819 first = false;820 }821 822 // Lines starting with # are considered comments823 if (line.starts_with("#") || !line.size())824 continue;825 826 StringRef sym;827 StringRef rest;828 std::tie(sym, rest) = line.split(':');829 sym = strip(sym);830 rest = strip(rest);831 832 symbolDependencies[sym] = {};833 834 while (rest.size()) {835 StringRef dep;836 std::tie(dep, rest) = rest.split(',');837 dep = strip(dep);838 symbolDependencies[sym].push_back(dep);839 }840 }841}842 843static uint8_t mapVisibility(GlobalValue::VisibilityTypes gvVisibility) {844 switch (gvVisibility) {845 case GlobalValue::DefaultVisibility:846 return WASM_SYMBOL_VISIBILITY_DEFAULT;847 case GlobalValue::HiddenVisibility:848 case GlobalValue::ProtectedVisibility:849 return WASM_SYMBOL_VISIBILITY_HIDDEN;850 }851 llvm_unreachable("unknown visibility");852}853 854static Symbol *createBitcodeSymbol(const std::vector<bool> &keptComdats,855 const lto::InputFile::Symbol &objSym,856 BitcodeFile &f) {857 StringRef name = saver().save(objSym.getName());858 859 uint32_t flags = objSym.isWeak() ? WASM_SYMBOL_BINDING_WEAK : 0;860 flags |= mapVisibility(objSym.getVisibility());861 862 int c = objSym.getComdatIndex();863 bool excludedByComdat = c != -1 && !keptComdats[c];864 865 if (objSym.isUndefined() || excludedByComdat) {866 flags |= WASM_SYMBOL_UNDEFINED;867 if (objSym.isExecutable())868 return symtab->addUndefinedFunction(name, std::nullopt, std::nullopt,869 flags, &f, nullptr, true);870 return symtab->addUndefinedData(name, flags, &f);871 }872 873 if (objSym.isExecutable())874 return symtab->addDefinedFunction(name, flags, &f, nullptr);875 return symtab->addDefinedData(name, flags, &f, nullptr, 0, 0);876}877 878BitcodeFile::BitcodeFile(MemoryBufferRef m, StringRef archiveName,879 uint64_t offsetInArchive, bool lazy)880 : InputFile(BitcodeKind, m) {881 this->lazy = lazy;882 this->archiveName = std::string(archiveName);883 884 std::string path = mb.getBufferIdentifier().str();885 if (ctx.arg.thinLTOIndexOnly)886 path = replaceThinLTOSuffix(mb.getBufferIdentifier());887 888 // ThinLTO assumes that all MemoryBufferRefs given to it have a unique889 // name. If two archives define two members with the same name, this890 // causes a collision which result in only one of the objects being taken891 // into consideration at LTO time (which very likely causes undefined892 // symbols later in the link stage). So we append file offset to make893 // filename unique.894 StringRef name = archiveName.empty()895 ? saver().save(path)896 : saver().save(archiveName + "(" + path::filename(path) +897 " at " + utostr(offsetInArchive) + ")");898 MemoryBufferRef mbref(mb.getBuffer(), name);899 900 obj = check(lto::InputFile::create(mbref));901 902 // If this isn't part of an archive, it's eagerly linked, so mark it live.903 if (archiveName.empty())904 markLive();905}906 907bool BitcodeFile::doneLTO = false;908 909void BitcodeFile::parseLazy() {910 for (auto [i, irSym] : llvm::enumerate(obj->symbols())) {911 if (irSym.isUndefined())912 continue;913 StringRef name = saver().save(irSym.getName());914 symtab->addLazy(name, this);915 // addLazy() may trigger this->extract() if an existing symbol is an916 // undefined symbol. If that happens, this function has served its purpose,917 // and we can exit from the loop early.918 if (!lazy)919 break;920 }921}922 923void BitcodeFile::parse(StringRef symName) {924 if (doneLTO) {925 error(toString(this) + ": attempt to add bitcode file after LTO (" + symName + ")");926 return;927 }928 929 Triple t(obj->getTargetTriple());930 if (!t.isWasm()) {931 error(toString(this) + ": machine type must be wasm32 or wasm64");932 return;933 }934 checkArch(t.getArch());935 std::vector<bool> keptComdats;936 // TODO Support nodeduplicate937 // https://github.com/llvm/llvm-project/issues/49875938 for (std::pair<StringRef, Comdat::SelectionKind> s : obj->getComdatTable())939 keptComdats.push_back(symtab->addComdat(s.first));940 941 for (const lto::InputFile::Symbol &objSym : obj->symbols())942 symbols.push_back(createBitcodeSymbol(keptComdats, objSym, *this));943}944 945} // namespace wasm946} // namespace lld947