| 1 | //===- SyntheticSections.cpp ----------------------------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // This file contains linker-synthesized sections. |
| 10 | // |
| 11 | //===----------------------------------------------------------------------===// |
| 12 | |
| 13 | #include "SyntheticSections.h" |
| 14 | |
| 15 | #include "InputChunks.h" |
| 16 | #include "InputElement.h" |
| 17 | #include "OutputSegment.h" |
| 18 | #include "SymbolTable.h" |
| 19 | #include "llvm/BinaryFormat/Wasm.h" |
| 20 | #include "llvm/Support/Path.h" |
| 21 | #include <optional> |
| 22 | |
| 23 | using namespace llvm; |
| 24 | using namespace llvm::wasm; |
| 25 | |
| 26 | namespace lld::wasm { |
| 27 | |
| 28 | OutStruct out; |
| 29 | |
| 30 | namespace { |
| 31 | |
| 32 | // Some synthetic sections (e.g. "name" and "linking") have subsections. |
| 33 | // Just like the synthetic sections themselves these need to be created before |
| 34 | // they can be written out (since they are preceded by their length). This |
| 35 | // class is used to create subsections and then write them into the stream |
| 36 | // of the parent section. |
| 37 | class SubSection { |
| 38 | public: |
| 39 | explicit SubSection(uint32_t type) : type(type) {} |
| 40 | |
| 41 | void writeTo(raw_ostream &to) { |
| 42 | writeUleb128(os&: to, number: type, msg: "subsection type" ); |
| 43 | writeUleb128(os&: to, number: body.size(), msg: "subsection size" ); |
| 44 | to.write(Ptr: body.data(), Size: body.size()); |
| 45 | } |
| 46 | |
| 47 | private: |
| 48 | uint32_t type; |
| 49 | std::string body; |
| 50 | |
| 51 | public: |
| 52 | raw_string_ostream os{body}; |
| 53 | }; |
| 54 | |
| 55 | } // namespace |
| 56 | |
| 57 | bool DylinkSection::isNeeded() const { |
| 58 | return ctx.isPic || |
| 59 | ctx.arg.unresolvedSymbols == UnresolvedPolicy::ImportDynamic || |
| 60 | !ctx.sharedFiles.empty(); |
| 61 | } |
| 62 | |
| 63 | void DylinkSection::writeBody() { |
| 64 | raw_ostream &os = bodyOutputStream; |
| 65 | |
| 66 | { |
| 67 | SubSection sub(WASM_DYLINK_MEM_INFO); |
| 68 | writeUleb128(os&: sub.os, number: memSize, msg: "MemSize" ); |
| 69 | writeUleb128(os&: sub.os, number: memAlign, msg: "MemAlign" ); |
| 70 | writeUleb128(os&: sub.os, number: out.elemSec->numEntries(), msg: "TableSize" ); |
| 71 | writeUleb128(os&: sub.os, number: 0, msg: "TableAlign" ); |
| 72 | sub.writeTo(to&: os); |
| 73 | } |
| 74 | |
| 75 | if (ctx.sharedFiles.size()) { |
| 76 | SubSection sub(WASM_DYLINK_NEEDED); |
| 77 | writeUleb128(os&: sub.os, number: ctx.sharedFiles.size(), msg: "Needed" ); |
| 78 | for (auto *so : ctx.sharedFiles) |
| 79 | writeStr(os&: sub.os, string: llvm::sys::path::filename(path: so->getName()), msg: "so name" ); |
| 80 | sub.writeTo(to&: os); |
| 81 | } |
| 82 | |
| 83 | // Under certain circumstances we need to include extra information about our |
| 84 | // exports and/or imports to the dynamic linker. |
| 85 | // For exports we need to notify the linker when an export is TLS since the |
| 86 | // exported value is relative to __tls_base rather than __memory_base. |
| 87 | // For imports we need to notify the dynamic linker when an import is weak |
| 88 | // so that knows not to report an error for such symbols. |
| 89 | std::vector<const Symbol *> importInfo; |
| 90 | std::vector<const Symbol *> exportInfo; |
| 91 | for (const Symbol *sym : symtab->symbols()) { |
| 92 | if (sym->isLive()) { |
| 93 | if (sym->isExported() && sym->isTLS() && isa<DefinedData>(Val: sym)) { |
| 94 | exportInfo.push_back(x: sym); |
| 95 | } |
| 96 | if (sym->isUndefWeak()) { |
| 97 | importInfo.push_back(x: sym); |
| 98 | } |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | if (!exportInfo.empty()) { |
| 103 | SubSection sub(WASM_DYLINK_EXPORT_INFO); |
| 104 | writeUleb128(os&: sub.os, number: exportInfo.size(), msg: "num exports" ); |
| 105 | |
| 106 | for (const Symbol *sym : exportInfo) { |
| 107 | LLVM_DEBUG(llvm::dbgs() << "export info: " << toString(*sym) << "\n" ); |
| 108 | StringRef name = sym->getName(); |
| 109 | if (auto *f = dyn_cast<DefinedFunction>(Val: sym)) { |
| 110 | if (std::optional<StringRef> exportName = |
| 111 | f->function->getExportName()) { |
| 112 | name = *exportName; |
| 113 | } |
| 114 | } |
| 115 | writeStr(os&: sub.os, string: name, msg: "sym name" ); |
| 116 | writeUleb128(os&: sub.os, number: sym->flags, msg: "sym flags" ); |
| 117 | } |
| 118 | |
| 119 | sub.writeTo(to&: os); |
| 120 | } |
| 121 | |
| 122 | if (!importInfo.empty()) { |
| 123 | SubSection sub(WASM_DYLINK_IMPORT_INFO); |
| 124 | writeUleb128(os&: sub.os, number: importInfo.size(), msg: "num imports" ); |
| 125 | |
| 126 | for (const Symbol *sym : importInfo) { |
| 127 | LLVM_DEBUG(llvm::dbgs() << "imports info: " << toString(*sym) << "\n" ); |
| 128 | StringRef module = sym->importModule.value_or(u&: defaultModule); |
| 129 | StringRef name = sym->importName.value_or(u: sym->getName()); |
| 130 | writeStr(os&: sub.os, string: module, msg: "import module" ); |
| 131 | writeStr(os&: sub.os, string: name, msg: "import name" ); |
| 132 | writeUleb128(os&: sub.os, number: sym->flags, msg: "sym flags" ); |
| 133 | } |
| 134 | |
| 135 | sub.writeTo(to&: os); |
| 136 | } |
| 137 | |
| 138 | if (!ctx.arg.rpath.empty()) { |
| 139 | SubSection sub(WASM_DYLINK_RUNTIME_PATH); |
| 140 | writeUleb128(os&: sub.os, number: ctx.arg.rpath.size(), msg: "num rpath entries" ); |
| 141 | for (const auto ref : ctx.arg.rpath) |
| 142 | writeStr(os&: sub.os, string: ref, msg: "rpath entry" ); |
| 143 | sub.writeTo(to&: os); |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | uint32_t TypeSection::registerType(const WasmSignature &sig) { |
| 148 | auto pair = typeIndices.insert(KV: std::make_pair(x: sig, y: types.size())); |
| 149 | if (pair.second) { |
| 150 | LLVM_DEBUG(llvm::dbgs() << "registerType " << toString(sig) << "\n" ); |
| 151 | types.push_back(x: &sig); |
| 152 | } |
| 153 | return pair.first->second; |
| 154 | } |
| 155 | |
| 156 | uint32_t TypeSection::lookupType(const WasmSignature &sig) { |
| 157 | auto it = typeIndices.find(Val: sig); |
| 158 | if (it == typeIndices.end()) { |
| 159 | error(msg: "type not found: " + toString(sig)); |
| 160 | return 0; |
| 161 | } |
| 162 | return it->second; |
| 163 | } |
| 164 | |
| 165 | void TypeSection::writeBody() { |
| 166 | writeUleb128(os&: bodyOutputStream, number: types.size(), msg: "type count" ); |
| 167 | for (const WasmSignature *sig : types) |
| 168 | writeSig(os&: bodyOutputStream, sig: *sig); |
| 169 | } |
| 170 | |
| 171 | uint32_t ImportSection::getNumImports() const { |
| 172 | assert(isSealed); |
| 173 | uint32_t numImports = importedSymbols.size() + gotSymbols.size(); |
| 174 | if (ctx.arg.memoryImport.has_value()) |
| 175 | ++numImports; |
| 176 | return numImports; |
| 177 | } |
| 178 | |
| 179 | void ImportSection::addGOTEntry(Symbol *sym) { |
| 180 | assert(!isSealed); |
| 181 | if (sym->hasGOTIndex()) |
| 182 | return; |
| 183 | LLVM_DEBUG(dbgs() << "addGOTEntry: " << toString(*sym) << "\n" ); |
| 184 | sym->setGOTIndex(numImportedGlobals++); |
| 185 | if (ctx.isPic) { |
| 186 | // Any symbol that is assigned an normal GOT entry must be exported |
| 187 | // otherwise the dynamic linker won't be able create the entry that contains |
| 188 | // it. |
| 189 | sym->forceExport = true; |
| 190 | } |
| 191 | gotSymbols.push_back(x: sym); |
| 192 | } |
| 193 | |
| 194 | void ImportSection::addImport(Symbol *sym) { |
| 195 | assert(!isSealed); |
| 196 | StringRef module = sym->importModule.value_or(u&: defaultModule); |
| 197 | StringRef name = sym->importName.value_or(u: sym->getName()); |
| 198 | if (auto *f = dyn_cast<FunctionSymbol>(Val: sym)) { |
| 199 | ImportKey<WasmSignature> key(*(f->getSignature()), module, name); |
| 200 | auto entry = importedFunctions.try_emplace(Key: key, Args&: numImportedFunctions); |
| 201 | if (entry.second) { |
| 202 | importedSymbols.emplace_back(args&: sym); |
| 203 | f->setFunctionIndex(numImportedFunctions++); |
| 204 | } else { |
| 205 | f->setFunctionIndex(entry.first->second); |
| 206 | } |
| 207 | } else if (auto *g = dyn_cast<GlobalSymbol>(Val: sym)) { |
| 208 | ImportKey<WasmGlobalType> key(*(g->getGlobalType()), module, name); |
| 209 | auto entry = importedGlobals.try_emplace(Key: key, Args&: numImportedGlobals); |
| 210 | if (entry.second) { |
| 211 | importedSymbols.emplace_back(args&: sym); |
| 212 | g->setGlobalIndex(numImportedGlobals++); |
| 213 | } else { |
| 214 | g->setGlobalIndex(entry.first->second); |
| 215 | } |
| 216 | } else if (auto *t = dyn_cast<TagSymbol>(Val: sym)) { |
| 217 | ImportKey<WasmSignature> key(*(t->getSignature()), module, name); |
| 218 | auto entry = importedTags.try_emplace(Key: key, Args&: numImportedTags); |
| 219 | if (entry.second) { |
| 220 | importedSymbols.emplace_back(args&: sym); |
| 221 | t->setTagIndex(numImportedTags++); |
| 222 | } else { |
| 223 | t->setTagIndex(entry.first->second); |
| 224 | } |
| 225 | } else { |
| 226 | assert(TableSymbol::classof(sym)); |
| 227 | auto *table = cast<TableSymbol>(Val: sym); |
| 228 | ImportKey<WasmTableType> key(*(table->getTableType()), module, name); |
| 229 | auto entry = importedTables.try_emplace(Key: key, Args&: numImportedTables); |
| 230 | if (entry.second) { |
| 231 | importedSymbols.emplace_back(args&: sym); |
| 232 | table->setTableNumber(numImportedTables++); |
| 233 | } else { |
| 234 | table->setTableNumber(entry.first->second); |
| 235 | } |
| 236 | } |
| 237 | } |
| 238 | |
| 239 | void ImportSection::writeBody() { |
| 240 | raw_ostream &os = bodyOutputStream; |
| 241 | |
| 242 | writeUleb128(os, number: getNumImports(), msg: "import count" ); |
| 243 | |
| 244 | bool is64 = ctx.arg.is64.value_or(u: false); |
| 245 | |
| 246 | if (ctx.arg.memoryImport) { |
| 247 | WasmImport import; |
| 248 | import.Module = ctx.arg.memoryImport->first; |
| 249 | import.Field = ctx.arg.memoryImport->second; |
| 250 | import.Kind = WASM_EXTERNAL_MEMORY; |
| 251 | import.Memory.Flags = 0; |
| 252 | import.Memory.Minimum = out.memorySec->numMemoryPages; |
| 253 | if (out.memorySec->maxMemoryPages != 0 || ctx.arg.sharedMemory) { |
| 254 | import.Memory.Flags |= WASM_LIMITS_FLAG_HAS_MAX; |
| 255 | import.Memory.Maximum = out.memorySec->maxMemoryPages; |
| 256 | } |
| 257 | if (ctx.arg.sharedMemory) |
| 258 | import.Memory.Flags |= WASM_LIMITS_FLAG_IS_SHARED; |
| 259 | if (is64) |
| 260 | import.Memory.Flags |= WASM_LIMITS_FLAG_IS_64; |
| 261 | writeImport(os, import); |
| 262 | } |
| 263 | |
| 264 | for (const Symbol *sym : importedSymbols) { |
| 265 | WasmImport import; |
| 266 | import.Field = sym->importName.value_or(u: sym->getName()); |
| 267 | import.Module = sym->importModule.value_or(u&: defaultModule); |
| 268 | |
| 269 | if (auto *functionSym = dyn_cast<FunctionSymbol>(Val: sym)) { |
| 270 | import.Kind = WASM_EXTERNAL_FUNCTION; |
| 271 | import.SigIndex = out.typeSec->lookupType(sig: *functionSym->signature); |
| 272 | } else if (auto *globalSym = dyn_cast<GlobalSymbol>(Val: sym)) { |
| 273 | import.Kind = WASM_EXTERNAL_GLOBAL; |
| 274 | import.Global = *globalSym->getGlobalType(); |
| 275 | } else if (auto *tagSym = dyn_cast<TagSymbol>(Val: sym)) { |
| 276 | import.Kind = WASM_EXTERNAL_TAG; |
| 277 | import.SigIndex = out.typeSec->lookupType(sig: *tagSym->signature); |
| 278 | } else { |
| 279 | auto *tableSym = cast<TableSymbol>(Val: sym); |
| 280 | import.Kind = WASM_EXTERNAL_TABLE; |
| 281 | import.Table = *tableSym->getTableType(); |
| 282 | } |
| 283 | writeImport(os, import); |
| 284 | } |
| 285 | |
| 286 | for (const Symbol *sym : gotSymbols) { |
| 287 | WasmImport import; |
| 288 | import.Kind = WASM_EXTERNAL_GLOBAL; |
| 289 | auto ptrType = is64 ? WASM_TYPE_I64 : WASM_TYPE_I32; |
| 290 | import.Global = {.Type: static_cast<uint8_t>(ptrType), .Mutable: true}; |
| 291 | if (isa<DataSymbol>(Val: sym)) |
| 292 | import.Module = "GOT.mem" ; |
| 293 | else |
| 294 | import.Module = "GOT.func" ; |
| 295 | import.Field = sym->getName(); |
| 296 | writeImport(os, import); |
| 297 | } |
| 298 | } |
| 299 | |
| 300 | void FunctionSection::writeBody() { |
| 301 | raw_ostream &os = bodyOutputStream; |
| 302 | |
| 303 | writeUleb128(os, number: inputFunctions.size(), msg: "function count" ); |
| 304 | for (const InputFunction *func : inputFunctions) |
| 305 | writeUleb128(os, number: out.typeSec->lookupType(sig: func->signature), msg: "sig index" ); |
| 306 | } |
| 307 | |
| 308 | void FunctionSection::addFunction(InputFunction *func) { |
| 309 | if (!func->live) |
| 310 | return; |
| 311 | uint32_t functionIndex = |
| 312 | out.importSec->getNumImportedFunctions() + inputFunctions.size(); |
| 313 | inputFunctions.emplace_back(args&: func); |
| 314 | func->setFunctionIndex(functionIndex); |
| 315 | } |
| 316 | |
| 317 | void TableSection::writeBody() { |
| 318 | raw_ostream &os = bodyOutputStream; |
| 319 | |
| 320 | writeUleb128(os, number: inputTables.size(), msg: "table count" ); |
| 321 | for (const InputTable *table : inputTables) |
| 322 | writeTableType(os, type: table->getType()); |
| 323 | } |
| 324 | |
| 325 | void TableSection::addTable(InputTable *table) { |
| 326 | if (!table->live) |
| 327 | return; |
| 328 | // Some inputs require that the indirect function table be assigned to table |
| 329 | // number 0. |
| 330 | if (ctx.legacyFunctionTable && |
| 331 | isa<DefinedTable>(Val: ctx.sym.indirectFunctionTable) && |
| 332 | cast<DefinedTable>(Val: ctx.sym.indirectFunctionTable)->table == table) { |
| 333 | if (out.importSec->getNumImportedTables()) { |
| 334 | // Alack! Some other input imported a table, meaning that we are unable |
| 335 | // to assign table number 0 to the indirect function table. |
| 336 | for (const auto *culprit : out.importSec->importedSymbols) { |
| 337 | if (isa<UndefinedTable>(Val: culprit)) { |
| 338 | error(msg: "object file not built with 'reference-types' or " |
| 339 | "'call-indirect-overlong' feature conflicts with import of " |
| 340 | "table " + |
| 341 | culprit->getName() + " by file " + |
| 342 | toString(file: culprit->getFile())); |
| 343 | return; |
| 344 | } |
| 345 | } |
| 346 | llvm_unreachable("failed to find conflicting table import" ); |
| 347 | } |
| 348 | inputTables.insert(position: inputTables.begin(), x: table); |
| 349 | return; |
| 350 | } |
| 351 | inputTables.push_back(x: table); |
| 352 | } |
| 353 | |
| 354 | void TableSection::assignIndexes() { |
| 355 | uint32_t tableNumber = out.importSec->getNumImportedTables(); |
| 356 | for (InputTable *t : inputTables) |
| 357 | t->assignIndex(index: tableNumber++); |
| 358 | } |
| 359 | |
| 360 | void MemorySection::writeBody() { |
| 361 | raw_ostream &os = bodyOutputStream; |
| 362 | |
| 363 | bool hasMax = maxMemoryPages != 0 || ctx.arg.sharedMemory; |
| 364 | writeUleb128(os, number: 1, msg: "memory count" ); |
| 365 | unsigned flags = 0; |
| 366 | if (hasMax) |
| 367 | flags |= WASM_LIMITS_FLAG_HAS_MAX; |
| 368 | if (ctx.arg.sharedMemory) |
| 369 | flags |= WASM_LIMITS_FLAG_IS_SHARED; |
| 370 | if (ctx.arg.is64.value_or(u: false)) |
| 371 | flags |= WASM_LIMITS_FLAG_IS_64; |
| 372 | if (ctx.arg.pageSize != WasmDefaultPageSize) |
| 373 | flags |= WASM_LIMITS_FLAG_HAS_PAGE_SIZE; |
| 374 | writeUleb128(os, number: flags, msg: "memory limits flags" ); |
| 375 | writeUleb128(os, number: numMemoryPages, msg: "initial pages" ); |
| 376 | if (hasMax) |
| 377 | writeUleb128(os, number: maxMemoryPages, msg: "max pages" ); |
| 378 | if (ctx.arg.pageSize != WasmDefaultPageSize) |
| 379 | writeUleb128(os, number: llvm::Log2_64(Value: ctx.arg.pageSize), msg: "page size" ); |
| 380 | } |
| 381 | |
| 382 | void TagSection::writeBody() { |
| 383 | raw_ostream &os = bodyOutputStream; |
| 384 | |
| 385 | writeUleb128(os, number: inputTags.size(), msg: "tag count" ); |
| 386 | for (InputTag *t : inputTags) { |
| 387 | writeUleb128(os, number: 0, msg: "tag attribute" ); // Reserved "attribute" field |
| 388 | writeUleb128(os, number: out.typeSec->lookupType(sig: t->signature), msg: "sig index" ); |
| 389 | } |
| 390 | } |
| 391 | |
| 392 | void TagSection::addTag(InputTag *tag) { |
| 393 | if (!tag->live) |
| 394 | return; |
| 395 | uint32_t tagIndex = out.importSec->getNumImportedTags() + inputTags.size(); |
| 396 | LLVM_DEBUG(dbgs() << "addTag: " << tagIndex << "\n" ); |
| 397 | tag->assignIndex(index: tagIndex); |
| 398 | inputTags.push_back(x: tag); |
| 399 | } |
| 400 | |
| 401 | void GlobalSection::assignIndexes() { |
| 402 | uint32_t globalIndex = out.importSec->getNumImportedGlobals(); |
| 403 | for (InputGlobal *g : inputGlobals) |
| 404 | g->assignIndex(index: globalIndex++); |
| 405 | for (Symbol *sym : internalGotSymbols) |
| 406 | sym->setGOTIndex(globalIndex++); |
| 407 | isSealed = true; |
| 408 | } |
| 409 | |
| 410 | static void ensureIndirectFunctionTable() { |
| 411 | if (!ctx.sym.indirectFunctionTable) |
| 412 | ctx.sym.indirectFunctionTable = |
| 413 | symtab->resolveIndirectFunctionTable(/*required =*/true); |
| 414 | } |
| 415 | |
| 416 | void GlobalSection::addInternalGOTEntry(Symbol *sym) { |
| 417 | assert(!isSealed); |
| 418 | if (sym->requiresGOT) |
| 419 | return; |
| 420 | LLVM_DEBUG(dbgs() << "addInternalGOTEntry: " << sym->getName() << " " |
| 421 | << toString(sym->kind()) << "\n" ); |
| 422 | sym->requiresGOT = true; |
| 423 | if (auto *F = dyn_cast<FunctionSymbol>(Val: sym)) { |
| 424 | ensureIndirectFunctionTable(); |
| 425 | out.elemSec->addEntry(sym: F); |
| 426 | } |
| 427 | internalGotSymbols.push_back(x: sym); |
| 428 | } |
| 429 | |
| 430 | void GlobalSection::generateRelocationCode(raw_ostream &os, bool TLS) const { |
| 431 | assert(!ctx.arg.extendedConst); |
| 432 | bool is64 = ctx.arg.is64.value_or(u: false); |
| 433 | unsigned opcode_ptr_const = is64 ? WASM_OPCODE_I64_CONST |
| 434 | : WASM_OPCODE_I32_CONST; |
| 435 | unsigned opcode_ptr_add = is64 ? WASM_OPCODE_I64_ADD |
| 436 | : WASM_OPCODE_I32_ADD; |
| 437 | |
| 438 | for (const Symbol *sym : internalGotSymbols) { |
| 439 | if (TLS != sym->isTLS()) |
| 440 | continue; |
| 441 | |
| 442 | if (auto *d = dyn_cast<DefinedData>(Val: sym)) { |
| 443 | // Get __memory_base |
| 444 | writeU8(os, byte: WASM_OPCODE_GLOBAL_GET, msg: "GLOBAL_GET" ); |
| 445 | if (sym->isTLS()) |
| 446 | writeUleb128(os, number: ctx.sym.tlsBase->getGlobalIndex(), msg: "__tls_base" ); |
| 447 | else |
| 448 | writeUleb128(os, number: ctx.sym.memoryBase->getGlobalIndex(), msg: "__memory_base" ); |
| 449 | |
| 450 | // Add the virtual address of the data symbol |
| 451 | writeU8(os, byte: opcode_ptr_const, msg: "CONST" ); |
| 452 | writeSleb128(os, number: d->getVA(), msg: "offset" ); |
| 453 | } else if (auto *f = dyn_cast<FunctionSymbol>(Val: sym)) { |
| 454 | if (f->isStub) |
| 455 | continue; |
| 456 | // Get __table_base |
| 457 | writeU8(os, byte: WASM_OPCODE_GLOBAL_GET, msg: "GLOBAL_GET" ); |
| 458 | writeUleb128(os, number: ctx.sym.tableBase->getGlobalIndex(), msg: "__table_base" ); |
| 459 | |
| 460 | // Add the table index to __table_base |
| 461 | writeU8(os, byte: opcode_ptr_const, msg: "CONST" ); |
| 462 | writeSleb128(os, number: f->getTableIndex(), msg: "offset" ); |
| 463 | } else { |
| 464 | assert(isa<UndefinedData>(sym) || isa<SharedData>(sym)); |
| 465 | continue; |
| 466 | } |
| 467 | writeU8(os, byte: opcode_ptr_add, msg: "ADD" ); |
| 468 | writeU8(os, byte: WASM_OPCODE_GLOBAL_SET, msg: "GLOBAL_SET" ); |
| 469 | writeUleb128(os, number: sym->getGOTIndex(), msg: "got_entry" ); |
| 470 | } |
| 471 | } |
| 472 | |
| 473 | void GlobalSection::writeBody() { |
| 474 | raw_ostream &os = bodyOutputStream; |
| 475 | |
| 476 | writeUleb128(os, number: numGlobals(), msg: "global count" ); |
| 477 | for (InputGlobal *g : inputGlobals) { |
| 478 | writeGlobalType(os, type: g->getType()); |
| 479 | writeInitExpr(os, initExpr: g->getInitExpr()); |
| 480 | } |
| 481 | bool is64 = ctx.arg.is64.value_or(u: false); |
| 482 | uint8_t itype = is64 ? WASM_TYPE_I64 : WASM_TYPE_I32; |
| 483 | for (const Symbol *sym : internalGotSymbols) { |
| 484 | bool mutable_ = false; |
| 485 | if (!sym->isStub) { |
| 486 | // In the case of dynamic linking, unless we have 'extended-const' |
| 487 | // available, these global must to be mutable since they get updated to |
| 488 | // the correct runtime value during `__wasm_apply_global_relocs`. |
| 489 | if (!ctx.arg.extendedConst && ctx.isPic && !sym->isTLS()) |
| 490 | mutable_ = true; |
| 491 | // With multi-theadeding any TLS globals must be mutable since they get |
| 492 | // set during `__wasm_apply_global_tls_relocs` |
| 493 | if (ctx.arg.sharedMemory && sym->isTLS()) |
| 494 | mutable_ = true; |
| 495 | } |
| 496 | WasmGlobalType type{.Type: itype, .Mutable: mutable_}; |
| 497 | writeGlobalType(os, type); |
| 498 | |
| 499 | bool useExtendedConst = false; |
| 500 | uint32_t globalIdx; |
| 501 | int64_t offset; |
| 502 | if (ctx.arg.extendedConst && ctx.isPic) { |
| 503 | if (auto *d = dyn_cast<DefinedData>(Val: sym)) { |
| 504 | if (!sym->isTLS()) { |
| 505 | globalIdx = ctx.sym.memoryBase->getGlobalIndex(); |
| 506 | offset = d->getVA(); |
| 507 | useExtendedConst = true; |
| 508 | } |
| 509 | } else if (auto *f = dyn_cast<FunctionSymbol>(Val: sym)) { |
| 510 | if (!sym->isStub) { |
| 511 | globalIdx = ctx.sym.tableBase->getGlobalIndex(); |
| 512 | offset = f->getTableIndex(); |
| 513 | useExtendedConst = true; |
| 514 | } |
| 515 | } |
| 516 | } |
| 517 | if (useExtendedConst) { |
| 518 | // We can use an extended init expression to add a constant |
| 519 | // offset of __memory_base/__table_base. |
| 520 | writeU8(os, byte: WASM_OPCODE_GLOBAL_GET, msg: "global get" ); |
| 521 | writeUleb128(os, number: globalIdx, msg: "literal (global index)" ); |
| 522 | if (offset) { |
| 523 | writePtrConst(os, number: offset, is64, msg: "offset" ); |
| 524 | writeU8(os, byte: is64 ? WASM_OPCODE_I64_ADD : WASM_OPCODE_I32_ADD, msg: "add" ); |
| 525 | } |
| 526 | writeU8(os, byte: WASM_OPCODE_END, msg: "opcode:end" ); |
| 527 | } else { |
| 528 | WasmInitExpr initExpr; |
| 529 | if (auto *d = dyn_cast<DefinedData>(Val: sym)) |
| 530 | // In the sharedMemory case TLS globals are set during |
| 531 | // `__wasm_apply_global_tls_relocs`, but in the non-shared case |
| 532 | // we know the absolute value at link time. |
| 533 | initExpr = intConst(value: d->getVA(/*absolute=*/!ctx.arg.sharedMemory), is64); |
| 534 | else if (auto *f = dyn_cast<FunctionSymbol>(Val: sym)) |
| 535 | initExpr = intConst(value: f->isStub ? 0 : f->getTableIndex(), is64); |
| 536 | else { |
| 537 | assert(isa<UndefinedData>(sym) || isa<SharedData>(sym)); |
| 538 | initExpr = intConst(value: 0, is64); |
| 539 | } |
| 540 | writeInitExpr(os, initExpr); |
| 541 | } |
| 542 | } |
| 543 | for (const DefinedData *sym : dataAddressGlobals) { |
| 544 | WasmGlobalType type{.Type: itype, .Mutable: false}; |
| 545 | writeGlobalType(os, type); |
| 546 | writeInitExpr(os, initExpr: intConst(value: sym->getVA(), is64)); |
| 547 | } |
| 548 | } |
| 549 | |
| 550 | void GlobalSection::addGlobal(InputGlobal *global) { |
| 551 | assert(!isSealed); |
| 552 | if (!global->live) |
| 553 | return; |
| 554 | inputGlobals.push_back(x: global); |
| 555 | } |
| 556 | |
| 557 | void ExportSection::writeBody() { |
| 558 | raw_ostream &os = bodyOutputStream; |
| 559 | |
| 560 | writeUleb128(os, number: exports.size(), msg: "export count" ); |
| 561 | for (const WasmExport &export_ : exports) |
| 562 | writeExport(os, export_); |
| 563 | } |
| 564 | |
| 565 | bool StartSection::isNeeded() const { return ctx.sym.startFunction != nullptr; } |
| 566 | |
| 567 | void StartSection::writeBody() { |
| 568 | raw_ostream &os = bodyOutputStream; |
| 569 | writeUleb128(os, number: ctx.sym.startFunction->getFunctionIndex(), msg: "function index" ); |
| 570 | } |
| 571 | |
| 572 | void ElemSection::addEntry(FunctionSymbol *sym) { |
| 573 | // Don't add stub functions to the wasm table. The address of all stub |
| 574 | // functions should be zero and they should they don't appear in the table. |
| 575 | // They only exist so that the calls to missing functions can validate. |
| 576 | if (sym->hasTableIndex() || sym->isStub) |
| 577 | return; |
| 578 | sym->setTableIndex(ctx.arg.tableBase + indirectFunctions.size()); |
| 579 | indirectFunctions.emplace_back(args&: sym); |
| 580 | } |
| 581 | |
| 582 | void ElemSection::writeBody() { |
| 583 | raw_ostream &os = bodyOutputStream; |
| 584 | |
| 585 | assert(ctx.sym.indirectFunctionTable); |
| 586 | writeUleb128(os, number: 1, msg: "segment count" ); |
| 587 | uint32_t tableNumber = ctx.sym.indirectFunctionTable->getTableNumber(); |
| 588 | uint32_t flags = 0; |
| 589 | if (tableNumber) |
| 590 | flags |= WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER; |
| 591 | writeUleb128(os, number: flags, msg: "elem segment flags" ); |
| 592 | if (flags & WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER) |
| 593 | writeUleb128(os, number: tableNumber, msg: "table number" ); |
| 594 | |
| 595 | WasmInitExpr initExpr; |
| 596 | initExpr.Extended = false; |
| 597 | if (ctx.isPic) { |
| 598 | initExpr.Inst.Opcode = WASM_OPCODE_GLOBAL_GET; |
| 599 | initExpr.Inst.Value.Global = ctx.sym.tableBase->getGlobalIndex(); |
| 600 | } else { |
| 601 | bool is64 = ctx.arg.is64.value_or(u: false); |
| 602 | initExpr = intConst(value: ctx.arg.tableBase, is64); |
| 603 | } |
| 604 | writeInitExpr(os, initExpr); |
| 605 | |
| 606 | if (flags & WASM_ELEM_SEGMENT_MASK_HAS_ELEM_DESC) { |
| 607 | // We only write active function table initializers, for which the elem kind |
| 608 | // is specified to be written as 0x00 and interpreted to mean "funcref". |
| 609 | const uint8_t elemKind = 0; |
| 610 | writeU8(os, byte: elemKind, msg: "elem kind" ); |
| 611 | } |
| 612 | |
| 613 | writeUleb128(os, number: indirectFunctions.size(), msg: "elem count" ); |
| 614 | uint32_t tableIndex = ctx.arg.tableBase; |
| 615 | for (const FunctionSymbol *sym : indirectFunctions) { |
| 616 | assert(sym->getTableIndex() == tableIndex); |
| 617 | (void) tableIndex; |
| 618 | writeUleb128(os, number: sym->getFunctionIndex(), msg: "function index" ); |
| 619 | ++tableIndex; |
| 620 | } |
| 621 | } |
| 622 | |
| 623 | DataCountSection::DataCountSection(ArrayRef<OutputSegment *> segments) |
| 624 | : SyntheticSection(llvm::wasm::WASM_SEC_DATACOUNT), |
| 625 | numSegments(llvm::count_if(Range&: segments, P: [](OutputSegment *const segment) { |
| 626 | return segment->requiredInBinary(); |
| 627 | })) {} |
| 628 | |
| 629 | void DataCountSection::writeBody() { |
| 630 | writeUleb128(os&: bodyOutputStream, number: numSegments, msg: "data count" ); |
| 631 | } |
| 632 | |
| 633 | bool DataCountSection::isNeeded() const { |
| 634 | return numSegments && ctx.arg.sharedMemory; |
| 635 | } |
| 636 | |
| 637 | void LinkingSection::writeBody() { |
| 638 | raw_ostream &os = bodyOutputStream; |
| 639 | |
| 640 | writeUleb128(os, number: WasmMetadataVersion, msg: "Version" ); |
| 641 | |
| 642 | if (!symtabEntries.empty()) { |
| 643 | SubSection sub(WASM_SYMBOL_TABLE); |
| 644 | writeUleb128(os&: sub.os, number: symtabEntries.size(), msg: "num symbols" ); |
| 645 | |
| 646 | for (const Symbol *sym : symtabEntries) { |
| 647 | assert(sym->isDefined() || sym->isUndefined()); |
| 648 | WasmSymbolType kind = sym->getWasmType(); |
| 649 | uint32_t flags = sym->flags; |
| 650 | |
| 651 | writeU8(os&: sub.os, byte: kind, msg: "sym kind" ); |
| 652 | writeUleb128(os&: sub.os, number: flags, msg: "sym flags" ); |
| 653 | |
| 654 | if (auto *f = dyn_cast<FunctionSymbol>(Val: sym)) { |
| 655 | if (auto *d = dyn_cast<DefinedFunction>(Val: sym)) { |
| 656 | writeUleb128(os&: sub.os, number: d->getExportedFunctionIndex(), msg: "index" ); |
| 657 | } else { |
| 658 | writeUleb128(os&: sub.os, number: f->getFunctionIndex(), msg: "index" ); |
| 659 | } |
| 660 | if (sym->isDefined() || (flags & WASM_SYMBOL_EXPLICIT_NAME) != 0) |
| 661 | writeStr(os&: sub.os, string: sym->getName(), msg: "sym name" ); |
| 662 | } else if (auto *g = dyn_cast<GlobalSymbol>(Val: sym)) { |
| 663 | writeUleb128(os&: sub.os, number: g->getGlobalIndex(), msg: "index" ); |
| 664 | if (sym->isDefined() || (flags & WASM_SYMBOL_EXPLICIT_NAME) != 0) |
| 665 | writeStr(os&: sub.os, string: sym->getName(), msg: "sym name" ); |
| 666 | } else if (auto *t = dyn_cast<TagSymbol>(Val: sym)) { |
| 667 | writeUleb128(os&: sub.os, number: t->getTagIndex(), msg: "index" ); |
| 668 | if (sym->isDefined() || (flags & WASM_SYMBOL_EXPLICIT_NAME) != 0) |
| 669 | writeStr(os&: sub.os, string: sym->getName(), msg: "sym name" ); |
| 670 | } else if (auto *t = dyn_cast<TableSymbol>(Val: sym)) { |
| 671 | writeUleb128(os&: sub.os, number: t->getTableNumber(), msg: "table number" ); |
| 672 | if (sym->isDefined() || (flags & WASM_SYMBOL_EXPLICIT_NAME) != 0) |
| 673 | writeStr(os&: sub.os, string: sym->getName(), msg: "sym name" ); |
| 674 | } else if (isa<DataSymbol>(Val: sym)) { |
| 675 | writeStr(os&: sub.os, string: sym->getName(), msg: "sym name" ); |
| 676 | if (auto *dataSym = dyn_cast<DefinedData>(Val: sym)) { |
| 677 | if (dataSym->segment) { |
| 678 | writeUleb128(os&: sub.os, number: dataSym->getOutputSegmentIndex(), msg: "index" ); |
| 679 | writeUleb128(os&: sub.os, number: dataSym->getOutputSegmentOffset(), |
| 680 | msg: "data offset" ); |
| 681 | } else { |
| 682 | writeUleb128(os&: sub.os, number: 0, msg: "index" ); |
| 683 | writeUleb128(os&: sub.os, number: dataSym->getVA(), msg: "data offset" ); |
| 684 | } |
| 685 | writeUleb128(os&: sub.os, number: dataSym->getSize(), msg: "data size" ); |
| 686 | } |
| 687 | } else { |
| 688 | auto *s = cast<OutputSectionSymbol>(Val: sym); |
| 689 | writeUleb128(os&: sub.os, number: s->section->sectionIndex, msg: "sym section index" ); |
| 690 | } |
| 691 | } |
| 692 | |
| 693 | sub.writeTo(to&: os); |
| 694 | } |
| 695 | |
| 696 | if (dataSegments.size()) { |
| 697 | SubSection sub(WASM_SEGMENT_INFO); |
| 698 | writeUleb128(os&: sub.os, number: dataSegments.size(), msg: "num data segments" ); |
| 699 | for (const OutputSegment *s : dataSegments) { |
| 700 | writeStr(os&: sub.os, string: s->name, msg: "segment name" ); |
| 701 | writeUleb128(os&: sub.os, number: s->alignment, msg: "alignment" ); |
| 702 | writeUleb128(os&: sub.os, number: s->linkingFlags, msg: "flags" ); |
| 703 | } |
| 704 | sub.writeTo(to&: os); |
| 705 | } |
| 706 | |
| 707 | if (!initFunctions.empty()) { |
| 708 | SubSection sub(WASM_INIT_FUNCS); |
| 709 | writeUleb128(os&: sub.os, number: initFunctions.size(), msg: "num init functions" ); |
| 710 | for (const WasmInitEntry &f : initFunctions) { |
| 711 | writeUleb128(os&: sub.os, number: f.priority, msg: "priority" ); |
| 712 | writeUleb128(os&: sub.os, number: f.sym->getOutputSymbolIndex(), msg: "function index" ); |
| 713 | } |
| 714 | sub.writeTo(to&: os); |
| 715 | } |
| 716 | |
| 717 | struct ComdatEntry { |
| 718 | unsigned kind; |
| 719 | uint32_t index; |
| 720 | }; |
| 721 | std::map<StringRef, std::vector<ComdatEntry>> comdats; |
| 722 | |
| 723 | for (const InputFunction *f : out.functionSec->inputFunctions) { |
| 724 | StringRef comdat = f->getComdatName(); |
| 725 | if (!comdat.empty()) |
| 726 | comdats[comdat].emplace_back( |
| 727 | args: ComdatEntry{.kind: WASM_COMDAT_FUNCTION, .index: f->getFunctionIndex()}); |
| 728 | } |
| 729 | for (uint32_t i = 0; i < dataSegments.size(); ++i) { |
| 730 | const auto &inputSegments = dataSegments[i]->inputSegments; |
| 731 | if (inputSegments.empty()) |
| 732 | continue; |
| 733 | StringRef comdat = inputSegments[0]->getComdatName(); |
| 734 | #ifndef NDEBUG |
| 735 | for (const InputChunk *isec : inputSegments) |
| 736 | assert(isec->getComdatName() == comdat); |
| 737 | #endif |
| 738 | if (!comdat.empty()) |
| 739 | comdats[comdat].emplace_back(args: ComdatEntry{.kind: WASM_COMDAT_DATA, .index: i}); |
| 740 | } |
| 741 | |
| 742 | if (!comdats.empty()) { |
| 743 | SubSection sub(WASM_COMDAT_INFO); |
| 744 | writeUleb128(os&: sub.os, number: comdats.size(), msg: "num comdats" ); |
| 745 | for (const auto &c : comdats) { |
| 746 | writeStr(os&: sub.os, string: c.first, msg: "comdat name" ); |
| 747 | writeUleb128(os&: sub.os, number: 0, msg: "comdat flags" ); // flags for future use |
| 748 | writeUleb128(os&: sub.os, number: c.second.size(), msg: "num entries" ); |
| 749 | for (const ComdatEntry &entry : c.second) { |
| 750 | writeU8(os&: sub.os, byte: entry.kind, msg: "entry kind" ); |
| 751 | writeUleb128(os&: sub.os, number: entry.index, msg: "entry index" ); |
| 752 | } |
| 753 | } |
| 754 | sub.writeTo(to&: os); |
| 755 | } |
| 756 | } |
| 757 | |
| 758 | void LinkingSection::addToSymtab(Symbol *sym) { |
| 759 | sym->setOutputSymbolIndex(symtabEntries.size()); |
| 760 | symtabEntries.emplace_back(args&: sym); |
| 761 | } |
| 762 | |
| 763 | unsigned NameSection::numNamedFunctions() const { |
| 764 | unsigned numNames = out.importSec->getNumImportedFunctions(); |
| 765 | |
| 766 | for (const InputFunction *f : out.functionSec->inputFunctions) |
| 767 | if (!f->name.empty() || !f->debugName.empty()) |
| 768 | ++numNames; |
| 769 | |
| 770 | return numNames; |
| 771 | } |
| 772 | |
| 773 | unsigned NameSection::numNamedGlobals() const { |
| 774 | unsigned numNames = out.importSec->getNumImportedGlobals(); |
| 775 | |
| 776 | for (const InputGlobal *g : out.globalSec->inputGlobals) |
| 777 | if (!g->getName().empty()) |
| 778 | ++numNames; |
| 779 | |
| 780 | numNames += out.globalSec->internalGotSymbols.size(); |
| 781 | return numNames; |
| 782 | } |
| 783 | |
| 784 | unsigned NameSection::numNamedDataSegments() const { |
| 785 | unsigned numNames = 0; |
| 786 | |
| 787 | for (const OutputSegment *s : segments) |
| 788 | if (!s->name.empty() && s->requiredInBinary()) |
| 789 | ++numNames; |
| 790 | |
| 791 | return numNames; |
| 792 | } |
| 793 | |
| 794 | // Create the custom "name" section containing debug symbol names. |
| 795 | void NameSection::writeBody() { |
| 796 | { |
| 797 | SubSection sub(WASM_NAMES_MODULE); |
| 798 | StringRef moduleName = ctx.arg.soName; |
| 799 | if (ctx.arg.soName.empty()) |
| 800 | moduleName = llvm::sys::path::filename(path: ctx.arg.outputFile); |
| 801 | writeStr(os&: sub.os, string: moduleName, msg: "module name" ); |
| 802 | sub.writeTo(to&: bodyOutputStream); |
| 803 | } |
| 804 | |
| 805 | unsigned count = numNamedFunctions(); |
| 806 | if (count) { |
| 807 | SubSection sub(WASM_NAMES_FUNCTION); |
| 808 | writeUleb128(os&: sub.os, number: count, msg: "name count" ); |
| 809 | |
| 810 | // Function names appear in function index order. As it happens |
| 811 | // importedSymbols and inputFunctions are numbered in order with imported |
| 812 | // functions coming first. |
| 813 | for (const Symbol *s : out.importSec->importedSymbols) { |
| 814 | if (auto *f = dyn_cast<FunctionSymbol>(Val: s)) { |
| 815 | writeUleb128(os&: sub.os, number: f->getFunctionIndex(), msg: "func index" ); |
| 816 | writeStr(os&: sub.os, string: toString(sym: *s), msg: "symbol name" ); |
| 817 | } |
| 818 | } |
| 819 | for (const InputFunction *f : out.functionSec->inputFunctions) { |
| 820 | if (!f->name.empty()) { |
| 821 | writeUleb128(os&: sub.os, number: f->getFunctionIndex(), msg: "func index" ); |
| 822 | if (!f->debugName.empty()) { |
| 823 | writeStr(os&: sub.os, string: f->debugName, msg: "symbol name" ); |
| 824 | } else { |
| 825 | writeStr(os&: sub.os, string: maybeDemangleSymbol(name: f->name), msg: "symbol name" ); |
| 826 | } |
| 827 | } |
| 828 | } |
| 829 | sub.writeTo(to&: bodyOutputStream); |
| 830 | } |
| 831 | |
| 832 | count = numNamedGlobals(); |
| 833 | if (count) { |
| 834 | SubSection sub(WASM_NAMES_GLOBAL); |
| 835 | writeUleb128(os&: sub.os, number: count, msg: "name count" ); |
| 836 | |
| 837 | for (const Symbol *s : out.importSec->importedSymbols) { |
| 838 | if (auto *g = dyn_cast<GlobalSymbol>(Val: s)) { |
| 839 | writeUleb128(os&: sub.os, number: g->getGlobalIndex(), msg: "global index" ); |
| 840 | writeStr(os&: sub.os, string: toString(sym: *s), msg: "symbol name" ); |
| 841 | } |
| 842 | } |
| 843 | for (const Symbol *s : out.importSec->gotSymbols) { |
| 844 | writeUleb128(os&: sub.os, number: s->getGOTIndex(), msg: "global index" ); |
| 845 | writeStr(os&: sub.os, string: toString(sym: *s), msg: "symbol name" ); |
| 846 | } |
| 847 | for (const InputGlobal *g : out.globalSec->inputGlobals) { |
| 848 | if (!g->getName().empty()) { |
| 849 | writeUleb128(os&: sub.os, number: g->getAssignedIndex(), msg: "global index" ); |
| 850 | writeStr(os&: sub.os, string: maybeDemangleSymbol(name: g->getName()), msg: "symbol name" ); |
| 851 | } |
| 852 | } |
| 853 | for (Symbol *s : out.globalSec->internalGotSymbols) { |
| 854 | writeUleb128(os&: sub.os, number: s->getGOTIndex(), msg: "global index" ); |
| 855 | if (isa<FunctionSymbol>(Val: s)) |
| 856 | writeStr(os&: sub.os, string: "GOT.func.internal." + toString(sym: *s), msg: "symbol name" ); |
| 857 | else |
| 858 | writeStr(os&: sub.os, string: "GOT.data.internal." + toString(sym: *s), msg: "symbol name" ); |
| 859 | } |
| 860 | |
| 861 | sub.writeTo(to&: bodyOutputStream); |
| 862 | } |
| 863 | |
| 864 | count = numNamedDataSegments(); |
| 865 | if (count) { |
| 866 | SubSection sub(WASM_NAMES_DATA_SEGMENT); |
| 867 | writeUleb128(os&: sub.os, number: count, msg: "name count" ); |
| 868 | |
| 869 | for (OutputSegment *s : segments) { |
| 870 | if (!s->name.empty() && s->requiredInBinary()) { |
| 871 | writeUleb128(os&: sub.os, number: s->index, msg: "global index" ); |
| 872 | writeStr(os&: sub.os, string: s->name, msg: "segment name" ); |
| 873 | } |
| 874 | } |
| 875 | |
| 876 | sub.writeTo(to&: bodyOutputStream); |
| 877 | } |
| 878 | } |
| 879 | |
| 880 | void ProducersSection::(const WasmProducerInfo &info) { |
| 881 | for (auto &producers : |
| 882 | {std::make_pair(x: &info.Languages, y: &languages), |
| 883 | std::make_pair(x: &info.Tools, y: &tools), std::make_pair(x: &info.SDKs, y: &sDKs)}) |
| 884 | for (auto &producer : *producers.first) |
| 885 | if (llvm::none_of(Range&: *producers.second, |
| 886 | P: [&](std::pair<std::string, std::string> seen) { |
| 887 | return seen.first == producer.first; |
| 888 | })) |
| 889 | producers.second->push_back(Elt: producer); |
| 890 | } |
| 891 | |
| 892 | void ProducersSection::writeBody() { |
| 893 | auto &os = bodyOutputStream; |
| 894 | writeUleb128(os, number: fieldCount(), msg: "field count" ); |
| 895 | for (auto &field : |
| 896 | {std::make_pair(x: "language" , y&: languages), |
| 897 | std::make_pair(x: "processed-by" , y&: tools), std::make_pair(x: "sdk" , y&: sDKs)}) { |
| 898 | if (field.second.empty()) |
| 899 | continue; |
| 900 | writeStr(os, string: field.first, msg: "field name" ); |
| 901 | writeUleb128(os, number: field.second.size(), msg: "number of entries" ); |
| 902 | for (auto &entry : field.second) { |
| 903 | writeStr(os, string: entry.first, msg: "producer name" ); |
| 904 | writeStr(os, string: entry.second, msg: "producer version" ); |
| 905 | } |
| 906 | } |
| 907 | } |
| 908 | |
| 909 | void TargetFeaturesSection::writeBody() { |
| 910 | SmallVector<std::string, 8> emitted(features.begin(), features.end()); |
| 911 | llvm::sort(C&: emitted); |
| 912 | auto &os = bodyOutputStream; |
| 913 | writeUleb128(os, number: emitted.size(), msg: "feature count" ); |
| 914 | for (auto &feature : emitted) { |
| 915 | writeU8(os, byte: WASM_FEATURE_PREFIX_USED, msg: "feature used prefix" ); |
| 916 | writeStr(os, string: feature, msg: "feature name" ); |
| 917 | } |
| 918 | } |
| 919 | |
| 920 | void RelocSection::writeBody() { |
| 921 | uint32_t count = sec->getNumRelocations(); |
| 922 | assert(sec->sectionIndex != UINT32_MAX); |
| 923 | writeUleb128(os&: bodyOutputStream, number: sec->sectionIndex, msg: "reloc section" ); |
| 924 | writeUleb128(os&: bodyOutputStream, number: count, msg: "reloc count" ); |
| 925 | sec->writeRelocations(os&: bodyOutputStream); |
| 926 | } |
| 927 | |
| 928 | static size_t getHashSize() { |
| 929 | switch (ctx.arg.buildId) { |
| 930 | case BuildIdKind::Fast: |
| 931 | case BuildIdKind::Uuid: |
| 932 | return 16; |
| 933 | case BuildIdKind::Sha1: |
| 934 | return 20; |
| 935 | case BuildIdKind::Hexstring: |
| 936 | return ctx.arg.buildIdVector.size(); |
| 937 | case BuildIdKind::None: |
| 938 | return 0; |
| 939 | } |
| 940 | llvm_unreachable("build id kind not implemented" ); |
| 941 | } |
| 942 | |
| 943 | BuildIdSection::BuildIdSection() |
| 944 | : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, buildIdSectionName), |
| 945 | hashSize(getHashSize()) {} |
| 946 | |
| 947 | void BuildIdSection::writeBody() { |
| 948 | LLVM_DEBUG(llvm::dbgs() << "BuildId writebody\n" ); |
| 949 | // Write hash size |
| 950 | auto &os = bodyOutputStream; |
| 951 | writeUleb128(os, number: hashSize, msg: "build id size" ); |
| 952 | writeBytes(os, bytes: std::vector<char>(hashSize, ' ').data(), count: hashSize, |
| 953 | msg: "placeholder" ); |
| 954 | } |
| 955 | |
| 956 | void BuildIdSection::writeBuildId(llvm::ArrayRef<uint8_t> buf) { |
| 957 | assert(buf.size() == hashSize); |
| 958 | LLVM_DEBUG(dbgs() << "buildid write " << buf.size() << " " |
| 959 | << hashPlaceholderPtr << '\n'); |
| 960 | memcpy(dest: hashPlaceholderPtr, src: buf.data(), n: hashSize); |
| 961 | } |
| 962 | |
| 963 | } // namespace wasm::lld |
| 964 | |