|  | //===- SyntheticSections.cpp ----------------------------------------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This file contains linker-synthesized sections. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "SyntheticSections.h" | 
|  |  | 
|  | #include "InputChunks.h" | 
|  | #include "InputElement.h" | 
|  | #include "OutputSegment.h" | 
|  | #include "SymbolTable.h" | 
|  | #include "llvm/BinaryFormat/Wasm.h" | 
|  | #include "llvm/Support/Path.h" | 
|  | #include <optional> | 
|  |  | 
|  | using namespace llvm; | 
|  | using namespace llvm::wasm; | 
|  |  | 
|  | namespace lld::wasm { | 
|  |  | 
|  | OutStruct out; | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | // Some synthetic sections (e.g. "name" and "linking") have subsections. | 
|  | // Just like the synthetic sections themselves these need to be created before | 
|  | // they can be written out (since they are preceded by their length). This | 
|  | // class is used to create subsections and then write them into the stream | 
|  | // of the parent section. | 
|  | class SubSection { | 
|  | public: | 
|  | explicit SubSection(uint32_t type) : type(type) {} | 
|  |  | 
|  | void writeTo(raw_ostream &to) { | 
|  | writeUleb128(to, type, "subsection type"); | 
|  | writeUleb128(to, body.size(), "subsection size"); | 
|  | to.write(body.data(), body.size()); | 
|  | } | 
|  |  | 
|  | private: | 
|  | uint32_t type; | 
|  | std::string body; | 
|  |  | 
|  | public: | 
|  | raw_string_ostream os{body}; | 
|  | }; | 
|  |  | 
|  | } // namespace | 
|  |  | 
|  | bool DylinkSection::isNeeded() const { | 
|  | return ctx.isPic || | 
|  | ctx.arg.unresolvedSymbols == UnresolvedPolicy::ImportDynamic || | 
|  | !ctx.sharedFiles.empty(); | 
|  | } | 
|  |  | 
|  | void DylinkSection::writeBody() { | 
|  | raw_ostream &os = bodyOutputStream; | 
|  |  | 
|  | { | 
|  | SubSection sub(WASM_DYLINK_MEM_INFO); | 
|  | writeUleb128(sub.os, memSize, "MemSize"); | 
|  | writeUleb128(sub.os, memAlign, "MemAlign"); | 
|  | writeUleb128(sub.os, out.elemSec->numEntries(), "TableSize"); | 
|  | writeUleb128(sub.os, 0, "TableAlign"); | 
|  | sub.writeTo(os); | 
|  | } | 
|  |  | 
|  | if (ctx.sharedFiles.size()) { | 
|  | SubSection sub(WASM_DYLINK_NEEDED); | 
|  | writeUleb128(sub.os, ctx.sharedFiles.size(), "Needed"); | 
|  | for (auto *so : ctx.sharedFiles) | 
|  | writeStr(sub.os, llvm::sys::path::filename(so->getName()), "so name"); | 
|  | sub.writeTo(os); | 
|  | } | 
|  |  | 
|  | // Under certain circumstances we need to include extra information about our | 
|  | // exports and/or imports to the dynamic linker. | 
|  | // For exports we need to notify the linker when an export is TLS since the | 
|  | // exported value is relative to __tls_base rather than __memory_base. | 
|  | // For imports we need to notify the dynamic linker when an import is weak | 
|  | // so that knows not to report an error for such symbols. | 
|  | std::vector<const Symbol *> importInfo; | 
|  | std::vector<const Symbol *> exportInfo; | 
|  | for (const Symbol *sym : symtab->symbols()) { | 
|  | if (sym->isLive()) { | 
|  | if (sym->isExported() && sym->isTLS() && isa<DefinedData>(sym)) { | 
|  | exportInfo.push_back(sym); | 
|  | } | 
|  | if (sym->isUndefWeak()) { | 
|  | importInfo.push_back(sym); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!exportInfo.empty()) { | 
|  | SubSection sub(WASM_DYLINK_EXPORT_INFO); | 
|  | writeUleb128(sub.os, exportInfo.size(), "num exports"); | 
|  |  | 
|  | for (const Symbol *sym : exportInfo) { | 
|  | LLVM_DEBUG(llvm::dbgs() << "export info: " << toString(*sym) << "\n"); | 
|  | StringRef name = sym->getName(); | 
|  | if (auto *f = dyn_cast<DefinedFunction>(sym)) { | 
|  | if (std::optional<StringRef> exportName = | 
|  | f->function->getExportName()) { | 
|  | name = *exportName; | 
|  | } | 
|  | } | 
|  | writeStr(sub.os, name, "sym name"); | 
|  | writeUleb128(sub.os, sym->flags, "sym flags"); | 
|  | } | 
|  |  | 
|  | sub.writeTo(os); | 
|  | } | 
|  |  | 
|  | if (!importInfo.empty()) { | 
|  | SubSection sub(WASM_DYLINK_IMPORT_INFO); | 
|  | writeUleb128(sub.os, importInfo.size(), "num imports"); | 
|  |  | 
|  | for (const Symbol *sym : importInfo) { | 
|  | LLVM_DEBUG(llvm::dbgs() << "imports info: " << toString(*sym) << "\n"); | 
|  | StringRef module = sym->importModule.value_or(defaultModule); | 
|  | StringRef name = sym->importName.value_or(sym->getName()); | 
|  | writeStr(sub.os, module, "import module"); | 
|  | writeStr(sub.os, name, "import name"); | 
|  | writeUleb128(sub.os, sym->flags, "sym flags"); | 
|  | } | 
|  |  | 
|  | sub.writeTo(os); | 
|  | } | 
|  |  | 
|  | if (!ctx.arg.rpath.empty()) { | 
|  | SubSection sub(WASM_DYLINK_RUNTIME_PATH); | 
|  | writeUleb128(sub.os, ctx.arg.rpath.size(), "num rpath entries"); | 
|  | for (const auto ref : ctx.arg.rpath) | 
|  | writeStr(sub.os, ref, "rpath entry"); | 
|  | sub.writeTo(os); | 
|  | } | 
|  | } | 
|  |  | 
|  | uint32_t TypeSection::registerType(const WasmSignature &sig) { | 
|  | auto pair = typeIndices.insert(std::make_pair(sig, types.size())); | 
|  | if (pair.second) { | 
|  | LLVM_DEBUG(llvm::dbgs() << "registerType " << toString(sig) << "\n"); | 
|  | types.push_back(&sig); | 
|  | } | 
|  | return pair.first->second; | 
|  | } | 
|  |  | 
|  | uint32_t TypeSection::lookupType(const WasmSignature &sig) { | 
|  | auto it = typeIndices.find(sig); | 
|  | if (it == typeIndices.end()) { | 
|  | error("type not found: " + toString(sig)); | 
|  | return 0; | 
|  | } | 
|  | return it->second; | 
|  | } | 
|  |  | 
|  | void TypeSection::writeBody() { | 
|  | writeUleb128(bodyOutputStream, types.size(), "type count"); | 
|  | for (const WasmSignature *sig : types) | 
|  | writeSig(bodyOutputStream, *sig); | 
|  | } | 
|  |  | 
|  | uint32_t ImportSection::getNumImports() const { | 
|  | assert(isSealed); | 
|  | uint32_t numImports = importedSymbols.size() + gotSymbols.size(); | 
|  | if (ctx.arg.memoryImport.has_value()) | 
|  | ++numImports; | 
|  | return numImports; | 
|  | } | 
|  |  | 
|  | void ImportSection::addGOTEntry(Symbol *sym) { | 
|  | assert(!isSealed); | 
|  | if (sym->hasGOTIndex()) | 
|  | return; | 
|  | LLVM_DEBUG(dbgs() << "addGOTEntry: " << toString(*sym) << "\n"); | 
|  | sym->setGOTIndex(numImportedGlobals++); | 
|  | if (ctx.isPic) { | 
|  | // Any symbol that is assigned an normal GOT entry must be exported | 
|  | // otherwise the dynamic linker won't be able create the entry that contains | 
|  | // it. | 
|  | sym->forceExport = true; | 
|  | } | 
|  | gotSymbols.push_back(sym); | 
|  | } | 
|  |  | 
|  | void ImportSection::addImport(Symbol *sym) { | 
|  | assert(!isSealed); | 
|  | StringRef module = sym->importModule.value_or(defaultModule); | 
|  | StringRef name = sym->importName.value_or(sym->getName()); | 
|  | if (auto *f = dyn_cast<FunctionSymbol>(sym)) { | 
|  | ImportKey<WasmSignature> key(*(f->getSignature()), module, name); | 
|  | auto entry = importedFunctions.try_emplace(key, numImportedFunctions); | 
|  | if (entry.second) { | 
|  | importedSymbols.emplace_back(sym); | 
|  | f->setFunctionIndex(numImportedFunctions++); | 
|  | } else { | 
|  | f->setFunctionIndex(entry.first->second); | 
|  | } | 
|  | } else if (auto *g = dyn_cast<GlobalSymbol>(sym)) { | 
|  | ImportKey<WasmGlobalType> key(*(g->getGlobalType()), module, name); | 
|  | auto entry = importedGlobals.try_emplace(key, numImportedGlobals); | 
|  | if (entry.second) { | 
|  | importedSymbols.emplace_back(sym); | 
|  | g->setGlobalIndex(numImportedGlobals++); | 
|  | } else { | 
|  | g->setGlobalIndex(entry.first->second); | 
|  | } | 
|  | } else if (auto *t = dyn_cast<TagSymbol>(sym)) { | 
|  | ImportKey<WasmSignature> key(*(t->getSignature()), module, name); | 
|  | auto entry = importedTags.try_emplace(key, numImportedTags); | 
|  | if (entry.second) { | 
|  | importedSymbols.emplace_back(sym); | 
|  | t->setTagIndex(numImportedTags++); | 
|  | } else { | 
|  | t->setTagIndex(entry.first->second); | 
|  | } | 
|  | } else { | 
|  | assert(TableSymbol::classof(sym)); | 
|  | auto *table = cast<TableSymbol>(sym); | 
|  | ImportKey<WasmTableType> key(*(table->getTableType()), module, name); | 
|  | auto entry = importedTables.try_emplace(key, numImportedTables); | 
|  | if (entry.second) { | 
|  | importedSymbols.emplace_back(sym); | 
|  | table->setTableNumber(numImportedTables++); | 
|  | } else { | 
|  | table->setTableNumber(entry.first->second); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void ImportSection::writeBody() { | 
|  | raw_ostream &os = bodyOutputStream; | 
|  |  | 
|  | writeUleb128(os, getNumImports(), "import count"); | 
|  |  | 
|  | bool is64 = ctx.arg.is64.value_or(false); | 
|  |  | 
|  | if (ctx.arg.memoryImport) { | 
|  | WasmImport import; | 
|  | import.Module = ctx.arg.memoryImport->first; | 
|  | import.Field = ctx.arg.memoryImport->second; | 
|  | import.Kind = WASM_EXTERNAL_MEMORY; | 
|  | import.Memory.Flags = 0; | 
|  | import.Memory.Minimum = out.memorySec->numMemoryPages; | 
|  | if (out.memorySec->maxMemoryPages != 0 || ctx.arg.sharedMemory) { | 
|  | import.Memory.Flags |= WASM_LIMITS_FLAG_HAS_MAX; | 
|  | import.Memory.Maximum = out.memorySec->maxMemoryPages; | 
|  | } | 
|  | if (ctx.arg.sharedMemory) | 
|  | import.Memory.Flags |= WASM_LIMITS_FLAG_IS_SHARED; | 
|  | if (is64) | 
|  | import.Memory.Flags |= WASM_LIMITS_FLAG_IS_64; | 
|  | if (ctx.arg.pageSize != WasmDefaultPageSize) { | 
|  | import.Memory.Flags |= WASM_LIMITS_FLAG_HAS_PAGE_SIZE; | 
|  | import.Memory.PageSize = ctx.arg.pageSize; | 
|  | } | 
|  | writeImport(os, import); | 
|  | } | 
|  |  | 
|  | for (const Symbol *sym : importedSymbols) { | 
|  | WasmImport import; | 
|  | import.Field = sym->importName.value_or(sym->getName()); | 
|  | import.Module = sym->importModule.value_or(defaultModule); | 
|  |  | 
|  | if (auto *functionSym = dyn_cast<FunctionSymbol>(sym)) { | 
|  | import.Kind = WASM_EXTERNAL_FUNCTION; | 
|  | import.SigIndex = out.typeSec->lookupType(*functionSym->signature); | 
|  | } else if (auto *globalSym = dyn_cast<GlobalSymbol>(sym)) { | 
|  | import.Kind = WASM_EXTERNAL_GLOBAL; | 
|  | import.Global = *globalSym->getGlobalType(); | 
|  | } else if (auto *tagSym = dyn_cast<TagSymbol>(sym)) { | 
|  | import.Kind = WASM_EXTERNAL_TAG; | 
|  | import.SigIndex = out.typeSec->lookupType(*tagSym->signature); | 
|  | } else { | 
|  | auto *tableSym = cast<TableSymbol>(sym); | 
|  | import.Kind = WASM_EXTERNAL_TABLE; | 
|  | import.Table = *tableSym->getTableType(); | 
|  | } | 
|  | writeImport(os, import); | 
|  | } | 
|  |  | 
|  | for (const Symbol *sym : gotSymbols) { | 
|  | WasmImport import; | 
|  | import.Kind = WASM_EXTERNAL_GLOBAL; | 
|  | auto ptrType = is64 ? WASM_TYPE_I64 : WASM_TYPE_I32; | 
|  | import.Global = {static_cast<uint8_t>(ptrType), true}; | 
|  | if (isa<DataSymbol>(sym)) | 
|  | import.Module = "GOT.mem"; | 
|  | else | 
|  | import.Module = "GOT.func"; | 
|  | import.Field = sym->getName(); | 
|  | writeImport(os, import); | 
|  | } | 
|  | } | 
|  |  | 
|  | void FunctionSection::writeBody() { | 
|  | raw_ostream &os = bodyOutputStream; | 
|  |  | 
|  | writeUleb128(os, inputFunctions.size(), "function count"); | 
|  | for (const InputFunction *func : inputFunctions) | 
|  | writeUleb128(os, out.typeSec->lookupType(func->signature), "sig index"); | 
|  | } | 
|  |  | 
|  | void FunctionSection::addFunction(InputFunction *func) { | 
|  | if (!func->live) | 
|  | return; | 
|  | uint32_t functionIndex = | 
|  | out.importSec->getNumImportedFunctions() + inputFunctions.size(); | 
|  | inputFunctions.emplace_back(func); | 
|  | func->setFunctionIndex(functionIndex); | 
|  | } | 
|  |  | 
|  | void TableSection::writeBody() { | 
|  | raw_ostream &os = bodyOutputStream; | 
|  |  | 
|  | writeUleb128(os, inputTables.size(), "table count"); | 
|  | for (const InputTable *table : inputTables) | 
|  | writeTableType(os, table->getType()); | 
|  | } | 
|  |  | 
|  | void TableSection::addTable(InputTable *table) { | 
|  | if (!table->live) | 
|  | return; | 
|  | // Some inputs require that the indirect function table be assigned to table | 
|  | // number 0. | 
|  | if (ctx.legacyFunctionTable && | 
|  | isa<DefinedTable>(ctx.sym.indirectFunctionTable) && | 
|  | cast<DefinedTable>(ctx.sym.indirectFunctionTable)->table == table) { | 
|  | if (out.importSec->getNumImportedTables()) { | 
|  | // Alack!  Some other input imported a table, meaning that we are unable | 
|  | // to assign table number 0 to the indirect function table. | 
|  | for (const auto *culprit : out.importSec->importedSymbols) { | 
|  | if (isa<UndefinedTable>(culprit)) { | 
|  | error("object file not built with 'reference-types' or " | 
|  | "'call-indirect-overlong' feature conflicts with import of " | 
|  | "table " + | 
|  | culprit->getName() + " by file " + | 
|  | toString(culprit->getFile())); | 
|  | return; | 
|  | } | 
|  | } | 
|  | llvm_unreachable("failed to find conflicting table import"); | 
|  | } | 
|  | inputTables.insert(inputTables.begin(), table); | 
|  | return; | 
|  | } | 
|  | inputTables.push_back(table); | 
|  | } | 
|  |  | 
|  | void TableSection::assignIndexes() { | 
|  | uint32_t tableNumber = out.importSec->getNumImportedTables(); | 
|  | for (InputTable *t : inputTables) | 
|  | t->assignIndex(tableNumber++); | 
|  | } | 
|  |  | 
|  | void MemorySection::writeBody() { | 
|  | raw_ostream &os = bodyOutputStream; | 
|  |  | 
|  | bool hasMax = maxMemoryPages != 0 || ctx.arg.sharedMemory; | 
|  | writeUleb128(os, 1, "memory count"); | 
|  | unsigned flags = 0; | 
|  | if (hasMax) | 
|  | flags |= WASM_LIMITS_FLAG_HAS_MAX; | 
|  | if (ctx.arg.sharedMemory) | 
|  | flags |= WASM_LIMITS_FLAG_IS_SHARED; | 
|  | if (ctx.arg.is64.value_or(false)) | 
|  | flags |= WASM_LIMITS_FLAG_IS_64; | 
|  | if (ctx.arg.pageSize != WasmDefaultPageSize) | 
|  | flags |= WASM_LIMITS_FLAG_HAS_PAGE_SIZE; | 
|  | writeUleb128(os, flags, "memory limits flags"); | 
|  | writeUleb128(os, numMemoryPages, "initial pages"); | 
|  | if (hasMax) | 
|  | writeUleb128(os, maxMemoryPages, "max pages"); | 
|  | if (ctx.arg.pageSize != WasmDefaultPageSize) | 
|  | writeUleb128(os, llvm::Log2_64(ctx.arg.pageSize), "page size"); | 
|  | } | 
|  |  | 
|  | void TagSection::writeBody() { | 
|  | raw_ostream &os = bodyOutputStream; | 
|  |  | 
|  | writeUleb128(os, inputTags.size(), "tag count"); | 
|  | for (InputTag *t : inputTags) { | 
|  | writeUleb128(os, 0, "tag attribute"); // Reserved "attribute" field | 
|  | writeUleb128(os, out.typeSec->lookupType(t->signature), "sig index"); | 
|  | } | 
|  | } | 
|  |  | 
|  | void TagSection::addTag(InputTag *tag) { | 
|  | if (!tag->live) | 
|  | return; | 
|  | uint32_t tagIndex = out.importSec->getNumImportedTags() + inputTags.size(); | 
|  | LLVM_DEBUG(dbgs() << "addTag: " << tagIndex << "\n"); | 
|  | tag->assignIndex(tagIndex); | 
|  | inputTags.push_back(tag); | 
|  | } | 
|  |  | 
|  | void GlobalSection::assignIndexes() { | 
|  | uint32_t globalIndex = out.importSec->getNumImportedGlobals(); | 
|  | for (InputGlobal *g : inputGlobals) | 
|  | g->assignIndex(globalIndex++); | 
|  | for (Symbol *sym : internalGotSymbols) | 
|  | sym->setGOTIndex(globalIndex++); | 
|  | isSealed = true; | 
|  | } | 
|  |  | 
|  | static void ensureIndirectFunctionTable() { | 
|  | if (!ctx.sym.indirectFunctionTable) | 
|  | ctx.sym.indirectFunctionTable = | 
|  | symtab->resolveIndirectFunctionTable(/*required =*/true); | 
|  | } | 
|  |  | 
|  | void GlobalSection::addInternalGOTEntry(Symbol *sym) { | 
|  | assert(!isSealed); | 
|  | if (sym->requiresGOT) | 
|  | return; | 
|  | LLVM_DEBUG(dbgs() << "addInternalGOTEntry: " << sym->getName() << " " | 
|  | << toString(sym->kind()) << "\n"); | 
|  | sym->requiresGOT = true; | 
|  | if (auto *F = dyn_cast<FunctionSymbol>(sym)) { | 
|  | ensureIndirectFunctionTable(); | 
|  | out.elemSec->addEntry(F); | 
|  | } | 
|  | internalGotSymbols.push_back(sym); | 
|  | } | 
|  |  | 
|  | void GlobalSection::generateRelocationCode(raw_ostream &os, bool TLS) const { | 
|  | assert(!ctx.arg.extendedConst); | 
|  | bool is64 = ctx.arg.is64.value_or(false); | 
|  | unsigned opcode_ptr_const = is64 ? WASM_OPCODE_I64_CONST | 
|  | : WASM_OPCODE_I32_CONST; | 
|  | unsigned opcode_ptr_add = is64 ? WASM_OPCODE_I64_ADD | 
|  | : WASM_OPCODE_I32_ADD; | 
|  |  | 
|  | for (const Symbol *sym : internalGotSymbols) { | 
|  | if (TLS != sym->isTLS()) | 
|  | continue; | 
|  |  | 
|  | if (auto *d = dyn_cast<DefinedData>(sym)) { | 
|  | // Get __memory_base | 
|  | writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET"); | 
|  | if (sym->isTLS()) | 
|  | writeUleb128(os, ctx.sym.tlsBase->getGlobalIndex(), "__tls_base"); | 
|  | else | 
|  | writeUleb128(os, ctx.sym.memoryBase->getGlobalIndex(), "__memory_base"); | 
|  |  | 
|  | // Add the virtual address of the data symbol | 
|  | writeU8(os, opcode_ptr_const, "CONST"); | 
|  | writeSleb128(os, d->getVA(), "offset"); | 
|  | } else if (auto *f = dyn_cast<FunctionSymbol>(sym)) { | 
|  | if (f->isStub) | 
|  | continue; | 
|  | // Get __table_base | 
|  | writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET"); | 
|  | writeUleb128(os, ctx.sym.tableBase->getGlobalIndex(), "__table_base"); | 
|  |  | 
|  | // Add the table index to __table_base | 
|  | writeU8(os, opcode_ptr_const, "CONST"); | 
|  | writeSleb128(os, f->getTableIndex(), "offset"); | 
|  | } else { | 
|  | assert(isa<UndefinedData>(sym) || isa<SharedData>(sym)); | 
|  | continue; | 
|  | } | 
|  | writeU8(os, opcode_ptr_add, "ADD"); | 
|  | writeU8(os, WASM_OPCODE_GLOBAL_SET, "GLOBAL_SET"); | 
|  | writeUleb128(os, sym->getGOTIndex(), "got_entry"); | 
|  | } | 
|  | } | 
|  |  | 
|  | void GlobalSection::writeBody() { | 
|  | raw_ostream &os = bodyOutputStream; | 
|  |  | 
|  | writeUleb128(os, numGlobals(), "global count"); | 
|  | for (InputGlobal *g : inputGlobals) { | 
|  | writeGlobalType(os, g->getType()); | 
|  | writeInitExpr(os, g->getInitExpr()); | 
|  | } | 
|  | bool is64 = ctx.arg.is64.value_or(false); | 
|  | uint8_t itype = is64 ? WASM_TYPE_I64 : WASM_TYPE_I32; | 
|  | for (const Symbol *sym : internalGotSymbols) { | 
|  | bool mutable_ = false; | 
|  | if (!sym->isStub) { | 
|  | // In the case of dynamic linking, unless we have 'extended-const' | 
|  | // available, these global must to be mutable since they get updated to | 
|  | // the correct runtime value during `__wasm_apply_global_relocs`. | 
|  | if (!ctx.arg.extendedConst && ctx.isPic && !sym->isTLS()) | 
|  | mutable_ = true; | 
|  | // With multi-theadeding any TLS globals must be mutable since they get | 
|  | // set during `__wasm_apply_global_tls_relocs` | 
|  | if (ctx.arg.sharedMemory && sym->isTLS()) | 
|  | mutable_ = true; | 
|  | } | 
|  | WasmGlobalType type{itype, mutable_}; | 
|  | writeGlobalType(os, type); | 
|  |  | 
|  | bool useExtendedConst = false; | 
|  | uint32_t globalIdx; | 
|  | int64_t offset; | 
|  | if (ctx.arg.extendedConst && ctx.isPic) { | 
|  | if (auto *d = dyn_cast<DefinedData>(sym)) { | 
|  | if (!sym->isTLS()) { | 
|  | globalIdx = ctx.sym.memoryBase->getGlobalIndex(); | 
|  | offset = d->getVA(); | 
|  | useExtendedConst = true; | 
|  | } | 
|  | } else if (auto *f = dyn_cast<FunctionSymbol>(sym)) { | 
|  | if (!sym->isStub) { | 
|  | globalIdx = ctx.sym.tableBase->getGlobalIndex(); | 
|  | offset = f->getTableIndex(); | 
|  | useExtendedConst = true; | 
|  | } | 
|  | } | 
|  | } | 
|  | if (useExtendedConst) { | 
|  | // We can use an extended init expression to add a constant | 
|  | // offset of __memory_base/__table_base. | 
|  | writeU8(os, WASM_OPCODE_GLOBAL_GET, "global get"); | 
|  | writeUleb128(os, globalIdx, "literal (global index)"); | 
|  | if (offset) { | 
|  | writePtrConst(os, offset, is64, "offset"); | 
|  | writeU8(os, is64 ? WASM_OPCODE_I64_ADD : WASM_OPCODE_I32_ADD, "add"); | 
|  | } | 
|  | writeU8(os, WASM_OPCODE_END, "opcode:end"); | 
|  | } else { | 
|  | WasmInitExpr initExpr; | 
|  | if (auto *d = dyn_cast<DefinedData>(sym)) | 
|  | // In the sharedMemory case TLS globals are set during | 
|  | // `__wasm_apply_global_tls_relocs`, but in the non-shared case | 
|  | // we know the absolute value at link time. | 
|  | initExpr = intConst(d->getVA(/*absolute=*/!ctx.arg.sharedMemory), is64); | 
|  | else if (auto *f = dyn_cast<FunctionSymbol>(sym)) | 
|  | initExpr = intConst(f->isStub ? 0 : f->getTableIndex(), is64); | 
|  | else { | 
|  | assert(isa<UndefinedData>(sym) || isa<SharedData>(sym)); | 
|  | initExpr = intConst(0, is64); | 
|  | } | 
|  | writeInitExpr(os, initExpr); | 
|  | } | 
|  | } | 
|  | for (const DefinedData *sym : dataAddressGlobals) { | 
|  | WasmGlobalType type{itype, false}; | 
|  | writeGlobalType(os, type); | 
|  | writeInitExpr(os, intConst(sym->getVA(), is64)); | 
|  | } | 
|  | } | 
|  |  | 
|  | void GlobalSection::addGlobal(InputGlobal *global) { | 
|  | assert(!isSealed); | 
|  | if (!global->live) | 
|  | return; | 
|  | inputGlobals.push_back(global); | 
|  | } | 
|  |  | 
|  | void ExportSection::writeBody() { | 
|  | raw_ostream &os = bodyOutputStream; | 
|  |  | 
|  | writeUleb128(os, exports.size(), "export count"); | 
|  | for (const WasmExport &export_ : exports) | 
|  | writeExport(os, export_); | 
|  | } | 
|  |  | 
|  | bool StartSection::isNeeded() const { return ctx.sym.startFunction != nullptr; } | 
|  |  | 
|  | void StartSection::writeBody() { | 
|  | raw_ostream &os = bodyOutputStream; | 
|  | writeUleb128(os, ctx.sym.startFunction->getFunctionIndex(), "function index"); | 
|  | } | 
|  |  | 
|  | void ElemSection::addEntry(FunctionSymbol *sym) { | 
|  | // Don't add stub functions to the wasm table.  The address of all stub | 
|  | // functions should be zero and they should they don't appear in the table. | 
|  | // They only exist so that the calls to missing functions can validate. | 
|  | if (sym->hasTableIndex() || sym->isStub) | 
|  | return; | 
|  | sym->setTableIndex(ctx.arg.tableBase + indirectFunctions.size()); | 
|  | indirectFunctions.emplace_back(sym); | 
|  | } | 
|  |  | 
|  | void ElemSection::writeBody() { | 
|  | raw_ostream &os = bodyOutputStream; | 
|  |  | 
|  | assert(ctx.sym.indirectFunctionTable); | 
|  | writeUleb128(os, 1, "segment count"); | 
|  | uint32_t tableNumber = ctx.sym.indirectFunctionTable->getTableNumber(); | 
|  | uint32_t flags = 0; | 
|  | if (tableNumber) | 
|  | flags |= WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER; | 
|  | writeUleb128(os, flags, "elem segment flags"); | 
|  | if (flags & WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER) | 
|  | writeUleb128(os, tableNumber, "table number"); | 
|  |  | 
|  | WasmInitExpr initExpr; | 
|  | initExpr.Extended = false; | 
|  | if (ctx.isPic) { | 
|  | initExpr.Inst.Opcode = WASM_OPCODE_GLOBAL_GET; | 
|  | initExpr.Inst.Value.Global = ctx.sym.tableBase->getGlobalIndex(); | 
|  | } else { | 
|  | bool is64 = ctx.arg.is64.value_or(false); | 
|  | initExpr = intConst(ctx.arg.tableBase, is64); | 
|  | } | 
|  | writeInitExpr(os, initExpr); | 
|  |  | 
|  | if (flags & WASM_ELEM_SEGMENT_MASK_HAS_ELEM_DESC) { | 
|  | // We only write active function table initializers, for which the elem kind | 
|  | // is specified to be written as 0x00 and interpreted to mean "funcref". | 
|  | const uint8_t elemKind = 0; | 
|  | writeU8(os, elemKind, "elem kind"); | 
|  | } | 
|  |  | 
|  | writeUleb128(os, indirectFunctions.size(), "elem count"); | 
|  | uint32_t tableIndex = ctx.arg.tableBase; | 
|  | for (const FunctionSymbol *sym : indirectFunctions) { | 
|  | assert(sym->getTableIndex() == tableIndex); | 
|  | (void) tableIndex; | 
|  | writeUleb128(os, sym->getFunctionIndex(), "function index"); | 
|  | ++tableIndex; | 
|  | } | 
|  | } | 
|  |  | 
|  | DataCountSection::DataCountSection(ArrayRef<OutputSegment *> segments) | 
|  | : SyntheticSection(llvm::wasm::WASM_SEC_DATACOUNT), | 
|  | numSegments(llvm::count_if(segments, [](OutputSegment *const segment) { | 
|  | return segment->requiredInBinary(); | 
|  | })) {} | 
|  |  | 
|  | void DataCountSection::writeBody() { | 
|  | writeUleb128(bodyOutputStream, numSegments, "data count"); | 
|  | } | 
|  |  | 
|  | bool DataCountSection::isNeeded() const { | 
|  | return numSegments && ctx.arg.sharedMemory; | 
|  | } | 
|  |  | 
|  | void LinkingSection::writeBody() { | 
|  | raw_ostream &os = bodyOutputStream; | 
|  |  | 
|  | writeUleb128(os, WasmMetadataVersion, "Version"); | 
|  |  | 
|  | if (!symtabEntries.empty()) { | 
|  | SubSection sub(WASM_SYMBOL_TABLE); | 
|  | writeUleb128(sub.os, symtabEntries.size(), "num symbols"); | 
|  |  | 
|  | for (const Symbol *sym : symtabEntries) { | 
|  | assert(sym->isDefined() || sym->isUndefined()); | 
|  | WasmSymbolType kind = sym->getWasmType(); | 
|  | uint32_t flags = sym->flags; | 
|  |  | 
|  | writeU8(sub.os, kind, "sym kind"); | 
|  | writeUleb128(sub.os, flags, "sym flags"); | 
|  |  | 
|  | if (auto *f = dyn_cast<FunctionSymbol>(sym)) { | 
|  | if (auto *d = dyn_cast<DefinedFunction>(sym)) { | 
|  | writeUleb128(sub.os, d->getExportedFunctionIndex(), "index"); | 
|  | } else { | 
|  | writeUleb128(sub.os, f->getFunctionIndex(), "index"); | 
|  | } | 
|  | if (sym->isDefined() || (flags & WASM_SYMBOL_EXPLICIT_NAME) != 0) | 
|  | writeStr(sub.os, sym->getName(), "sym name"); | 
|  | } else if (auto *g = dyn_cast<GlobalSymbol>(sym)) { | 
|  | writeUleb128(sub.os, g->getGlobalIndex(), "index"); | 
|  | if (sym->isDefined() || (flags & WASM_SYMBOL_EXPLICIT_NAME) != 0) | 
|  | writeStr(sub.os, sym->getName(), "sym name"); | 
|  | } else if (auto *t = dyn_cast<TagSymbol>(sym)) { | 
|  | writeUleb128(sub.os, t->getTagIndex(), "index"); | 
|  | if (sym->isDefined() || (flags & WASM_SYMBOL_EXPLICIT_NAME) != 0) | 
|  | writeStr(sub.os, sym->getName(), "sym name"); | 
|  | } else if (auto *t = dyn_cast<TableSymbol>(sym)) { | 
|  | writeUleb128(sub.os, t->getTableNumber(), "table number"); | 
|  | if (sym->isDefined() || (flags & WASM_SYMBOL_EXPLICIT_NAME) != 0) | 
|  | writeStr(sub.os, sym->getName(), "sym name"); | 
|  | } else if (isa<DataSymbol>(sym)) { | 
|  | writeStr(sub.os, sym->getName(), "sym name"); | 
|  | if (auto *dataSym = dyn_cast<DefinedData>(sym)) { | 
|  | if (dataSym->segment) { | 
|  | writeUleb128(sub.os, dataSym->getOutputSegmentIndex(), "index"); | 
|  | writeUleb128(sub.os, dataSym->getOutputSegmentOffset(), | 
|  | "data offset"); | 
|  | } else { | 
|  | writeUleb128(sub.os, 0, "index"); | 
|  | writeUleb128(sub.os, dataSym->getVA(), "data offset"); | 
|  | } | 
|  | writeUleb128(sub.os, dataSym->getSize(), "data size"); | 
|  | } | 
|  | } else { | 
|  | auto *s = cast<OutputSectionSymbol>(sym); | 
|  | writeUleb128(sub.os, s->section->sectionIndex, "sym section index"); | 
|  | } | 
|  | } | 
|  |  | 
|  | sub.writeTo(os); | 
|  | } | 
|  |  | 
|  | if (dataSegments.size()) { | 
|  | SubSection sub(WASM_SEGMENT_INFO); | 
|  | writeUleb128(sub.os, dataSegments.size(), "num data segments"); | 
|  | for (const OutputSegment *s : dataSegments) { | 
|  | writeStr(sub.os, s->name, "segment name"); | 
|  | writeUleb128(sub.os, s->alignment, "alignment"); | 
|  | writeUleb128(sub.os, s->linkingFlags, "flags"); | 
|  | } | 
|  | sub.writeTo(os); | 
|  | } | 
|  |  | 
|  | if (!initFunctions.empty()) { | 
|  | SubSection sub(WASM_INIT_FUNCS); | 
|  | writeUleb128(sub.os, initFunctions.size(), "num init functions"); | 
|  | for (const WasmInitEntry &f : initFunctions) { | 
|  | writeUleb128(sub.os, f.priority, "priority"); | 
|  | writeUleb128(sub.os, f.sym->getOutputSymbolIndex(), "function index"); | 
|  | } | 
|  | sub.writeTo(os); | 
|  | } | 
|  |  | 
|  | struct ComdatEntry { | 
|  | unsigned kind; | 
|  | uint32_t index; | 
|  | }; | 
|  | std::map<StringRef, std::vector<ComdatEntry>> comdats; | 
|  |  | 
|  | for (const InputFunction *f : out.functionSec->inputFunctions) { | 
|  | StringRef comdat = f->getComdatName(); | 
|  | if (!comdat.empty()) | 
|  | comdats[comdat].emplace_back( | 
|  | ComdatEntry{WASM_COMDAT_FUNCTION, f->getFunctionIndex()}); | 
|  | } | 
|  | for (uint32_t i = 0; i < dataSegments.size(); ++i) { | 
|  | const auto &inputSegments = dataSegments[i]->inputSegments; | 
|  | if (inputSegments.empty()) | 
|  | continue; | 
|  | StringRef comdat = inputSegments[0]->getComdatName(); | 
|  | #ifndef NDEBUG | 
|  | for (const InputChunk *isec : inputSegments) | 
|  | assert(isec->getComdatName() == comdat); | 
|  | #endif | 
|  | if (!comdat.empty()) | 
|  | comdats[comdat].emplace_back(ComdatEntry{WASM_COMDAT_DATA, i}); | 
|  | } | 
|  |  | 
|  | if (!comdats.empty()) { | 
|  | SubSection sub(WASM_COMDAT_INFO); | 
|  | writeUleb128(sub.os, comdats.size(), "num comdats"); | 
|  | for (const auto &c : comdats) { | 
|  | writeStr(sub.os, c.first, "comdat name"); | 
|  | writeUleb128(sub.os, 0, "comdat flags"); // flags for future use | 
|  | writeUleb128(sub.os, c.second.size(), "num entries"); | 
|  | for (const ComdatEntry &entry : c.second) { | 
|  | writeU8(sub.os, entry.kind, "entry kind"); | 
|  | writeUleb128(sub.os, entry.index, "entry index"); | 
|  | } | 
|  | } | 
|  | sub.writeTo(os); | 
|  | } | 
|  | } | 
|  |  | 
|  | void LinkingSection::addToSymtab(Symbol *sym) { | 
|  | sym->setOutputSymbolIndex(symtabEntries.size()); | 
|  | symtabEntries.emplace_back(sym); | 
|  | } | 
|  |  | 
|  | unsigned NameSection::numNamedFunctions() const { | 
|  | unsigned numNames = out.importSec->getNumImportedFunctions(); | 
|  |  | 
|  | for (const InputFunction *f : out.functionSec->inputFunctions) | 
|  | if (!f->name.empty() || !f->debugName.empty()) | 
|  | ++numNames; | 
|  |  | 
|  | return numNames; | 
|  | } | 
|  |  | 
|  | unsigned NameSection::numNamedGlobals() const { | 
|  | unsigned numNames = out.importSec->getNumImportedGlobals(); | 
|  |  | 
|  | for (const InputGlobal *g : out.globalSec->inputGlobals) | 
|  | if (!g->getName().empty()) | 
|  | ++numNames; | 
|  |  | 
|  | numNames += out.globalSec->internalGotSymbols.size(); | 
|  | return numNames; | 
|  | } | 
|  |  | 
|  | unsigned NameSection::numNamedDataSegments() const { | 
|  | unsigned numNames = 0; | 
|  |  | 
|  | for (const OutputSegment *s : segments) | 
|  | if (!s->name.empty() && s->requiredInBinary()) | 
|  | ++numNames; | 
|  |  | 
|  | return numNames; | 
|  | } | 
|  |  | 
|  | // Create the custom "name" section containing debug symbol names. | 
|  | void NameSection::writeBody() { | 
|  | { | 
|  | SubSection sub(WASM_NAMES_MODULE); | 
|  | StringRef moduleName = ctx.arg.soName; | 
|  | if (ctx.arg.soName.empty()) | 
|  | moduleName = llvm::sys::path::filename(ctx.arg.outputFile); | 
|  | writeStr(sub.os, moduleName, "module name"); | 
|  | sub.writeTo(bodyOutputStream); | 
|  | } | 
|  |  | 
|  | unsigned count = numNamedFunctions(); | 
|  | if (count) { | 
|  | SubSection sub(WASM_NAMES_FUNCTION); | 
|  | writeUleb128(sub.os, count, "name count"); | 
|  |  | 
|  | // Function names appear in function index order.  As it happens | 
|  | // importedSymbols and inputFunctions are numbered in order with imported | 
|  | // functions coming first. | 
|  | for (const Symbol *s : out.importSec->importedSymbols) { | 
|  | if (auto *f = dyn_cast<FunctionSymbol>(s)) { | 
|  | writeUleb128(sub.os, f->getFunctionIndex(), "func index"); | 
|  | writeStr(sub.os, toString(*s), "symbol name"); | 
|  | } | 
|  | } | 
|  | for (const InputFunction *f : out.functionSec->inputFunctions) { | 
|  | if (!f->name.empty()) { | 
|  | writeUleb128(sub.os, f->getFunctionIndex(), "func index"); | 
|  | if (!f->debugName.empty()) { | 
|  | writeStr(sub.os, f->debugName, "symbol name"); | 
|  | } else { | 
|  | writeStr(sub.os, maybeDemangleSymbol(f->name), "symbol name"); | 
|  | } | 
|  | } | 
|  | } | 
|  | sub.writeTo(bodyOutputStream); | 
|  | } | 
|  |  | 
|  | count = numNamedGlobals(); | 
|  | if (count) { | 
|  | SubSection sub(WASM_NAMES_GLOBAL); | 
|  | writeUleb128(sub.os, count, "name count"); | 
|  |  | 
|  | for (const Symbol *s : out.importSec->importedSymbols) { | 
|  | if (auto *g = dyn_cast<GlobalSymbol>(s)) { | 
|  | writeUleb128(sub.os, g->getGlobalIndex(), "global index"); | 
|  | writeStr(sub.os, toString(*s), "symbol name"); | 
|  | } | 
|  | } | 
|  | for (const Symbol *s : out.importSec->gotSymbols) { | 
|  | writeUleb128(sub.os, s->getGOTIndex(), "global index"); | 
|  | writeStr(sub.os, toString(*s), "symbol name"); | 
|  | } | 
|  | for (const InputGlobal *g : out.globalSec->inputGlobals) { | 
|  | if (!g->getName().empty()) { | 
|  | writeUleb128(sub.os, g->getAssignedIndex(), "global index"); | 
|  | writeStr(sub.os, maybeDemangleSymbol(g->getName()), "symbol name"); | 
|  | } | 
|  | } | 
|  | for (Symbol *s : out.globalSec->internalGotSymbols) { | 
|  | writeUleb128(sub.os, s->getGOTIndex(), "global index"); | 
|  | if (isa<FunctionSymbol>(s)) | 
|  | writeStr(sub.os, "GOT.func.internal." + toString(*s), "symbol name"); | 
|  | else | 
|  | writeStr(sub.os, "GOT.data.internal." + toString(*s), "symbol name"); | 
|  | } | 
|  |  | 
|  | sub.writeTo(bodyOutputStream); | 
|  | } | 
|  |  | 
|  | count = numNamedDataSegments(); | 
|  | if (count) { | 
|  | SubSection sub(WASM_NAMES_DATA_SEGMENT); | 
|  | writeUleb128(sub.os, count, "name count"); | 
|  |  | 
|  | for (OutputSegment *s : segments) { | 
|  | if (!s->name.empty() && s->requiredInBinary()) { | 
|  | writeUleb128(sub.os, s->index, "global index"); | 
|  | writeStr(sub.os, s->name, "segment name"); | 
|  | } | 
|  | } | 
|  |  | 
|  | sub.writeTo(bodyOutputStream); | 
|  | } | 
|  | } | 
|  |  | 
|  | void ProducersSection::addInfo(const WasmProducerInfo &info) { | 
|  | for (auto &producers : | 
|  | {std::make_pair(&info.Languages, &languages), | 
|  | std::make_pair(&info.Tools, &tools), std::make_pair(&info.SDKs, &sDKs)}) | 
|  | for (auto &producer : *producers.first) | 
|  | if (llvm::none_of(*producers.second, | 
|  | [&](std::pair<std::string, std::string> seen) { | 
|  | return seen.first == producer.first; | 
|  | })) | 
|  | producers.second->push_back(producer); | 
|  | } | 
|  |  | 
|  | void ProducersSection::writeBody() { | 
|  | auto &os = bodyOutputStream; | 
|  | writeUleb128(os, fieldCount(), "field count"); | 
|  | for (auto &field : | 
|  | {std::make_pair("language", languages), | 
|  | std::make_pair("processed-by", tools), std::make_pair("sdk", sDKs)}) { | 
|  | if (field.second.empty()) | 
|  | continue; | 
|  | writeStr(os, field.first, "field name"); | 
|  | writeUleb128(os, field.second.size(), "number of entries"); | 
|  | for (auto &entry : field.second) { | 
|  | writeStr(os, entry.first, "producer name"); | 
|  | writeStr(os, entry.second, "producer version"); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void TargetFeaturesSection::writeBody() { | 
|  | SmallVector<std::string, 8> emitted(features.begin(), features.end()); | 
|  | llvm::sort(emitted); | 
|  | auto &os = bodyOutputStream; | 
|  | writeUleb128(os, emitted.size(), "feature count"); | 
|  | for (auto &feature : emitted) { | 
|  | writeU8(os, WASM_FEATURE_PREFIX_USED, "feature used prefix"); | 
|  | writeStr(os, feature, "feature name"); | 
|  | } | 
|  | } | 
|  |  | 
|  | void RelocSection::writeBody() { | 
|  | uint32_t count = sec->getNumRelocations(); | 
|  | assert(sec->sectionIndex != UINT32_MAX); | 
|  | writeUleb128(bodyOutputStream, sec->sectionIndex, "reloc section"); | 
|  | writeUleb128(bodyOutputStream, count, "reloc count"); | 
|  | sec->writeRelocations(bodyOutputStream); | 
|  | } | 
|  |  | 
|  | static size_t getHashSize() { | 
|  | switch (ctx.arg.buildId) { | 
|  | case BuildIdKind::Fast: | 
|  | case BuildIdKind::Uuid: | 
|  | return 16; | 
|  | case BuildIdKind::Sha1: | 
|  | return 20; | 
|  | case BuildIdKind::Hexstring: | 
|  | return ctx.arg.buildIdVector.size(); | 
|  | case BuildIdKind::None: | 
|  | return 0; | 
|  | } | 
|  | llvm_unreachable("build id kind not implemented"); | 
|  | } | 
|  |  | 
|  | BuildIdSection::BuildIdSection() | 
|  | : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, buildIdSectionName), | 
|  | hashSize(getHashSize()) {} | 
|  |  | 
|  | void BuildIdSection::writeBody() { | 
|  | LLVM_DEBUG(llvm::dbgs() << "BuildId writebody\n"); | 
|  | // Write hash size | 
|  | auto &os = bodyOutputStream; | 
|  | writeUleb128(os, hashSize, "build id size"); | 
|  | writeBytes(os, std::vector<char>(hashSize, ' ').data(), hashSize, | 
|  | "placeholder"); | 
|  | } | 
|  |  | 
|  | void BuildIdSection::writeBuildId(llvm::ArrayRef<uint8_t> buf) { | 
|  | assert(buf.size() == hashSize); | 
|  | LLVM_DEBUG(dbgs() << "buildid write " << buf.size() << " " | 
|  | << hashPlaceholderPtr << '\n'); | 
|  | memcpy(hashPlaceholderPtr, buf.data(), hashSize); | 
|  | } | 
|  |  | 
|  | } // namespace wasm::lld |