brintos

brintos / llvm-project-archived public Read only

0
0
Text · 35.0 KiB · 81d7645 Raw
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 &section = 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 = &section;576    } else if (section.Type == WASM_SEC_DATA) {577      assert(!dataSection);578      dataSection = &section;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