| 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 | const WasmSignature *sig = f->getSignature(); |
| 200 | assert(sig && "imported functions must have a signature" ); |
| 201 | ImportKey<WasmSignature> key(*sig, module, name); |
| 202 | auto entry = importedFunctions.try_emplace(Key: key, Args&: numImportedFunctions); |
| 203 | if (entry.second) { |
| 204 | importedSymbols.emplace_back(args&: sym); |
| 205 | f->setFunctionIndex(numImportedFunctions++); |
| 206 | } else { |
| 207 | f->setFunctionIndex(entry.first->second); |
| 208 | } |
| 209 | } else if (auto *g = dyn_cast<GlobalSymbol>(Val: sym)) { |
| 210 | ImportKey<WasmGlobalType> key(*(g->getGlobalType()), module, name); |
| 211 | auto entry = importedGlobals.try_emplace(Key: key, Args&: numImportedGlobals); |
| 212 | if (entry.second) { |
| 213 | importedSymbols.emplace_back(args&: sym); |
| 214 | g->setGlobalIndex(numImportedGlobals++); |
| 215 | } else { |
| 216 | g->setGlobalIndex(entry.first->second); |
| 217 | } |
| 218 | } else if (auto *t = dyn_cast<TagSymbol>(Val: sym)) { |
| 219 | ImportKey<WasmSignature> key(*(t->getSignature()), module, name); |
| 220 | auto entry = importedTags.try_emplace(Key: key, Args&: numImportedTags); |
| 221 | if (entry.second) { |
| 222 | importedSymbols.emplace_back(args&: sym); |
| 223 | t->setTagIndex(numImportedTags++); |
| 224 | } else { |
| 225 | t->setTagIndex(entry.first->second); |
| 226 | } |
| 227 | } else { |
| 228 | assert(TableSymbol::classof(sym)); |
| 229 | auto *table = cast<TableSymbol>(Val: sym); |
| 230 | ImportKey<WasmTableType> key(*(table->getTableType()), module, name); |
| 231 | auto entry = importedTables.try_emplace(Key: key, Args&: numImportedTables); |
| 232 | if (entry.second) { |
| 233 | importedSymbols.emplace_back(args&: sym); |
| 234 | table->setTableNumber(numImportedTables++); |
| 235 | } else { |
| 236 | table->setTableNumber(entry.first->second); |
| 237 | } |
| 238 | } |
| 239 | } |
| 240 | |
| 241 | void ImportSection::writeBody() { |
| 242 | raw_ostream &os = bodyOutputStream; |
| 243 | |
| 244 | uint32_t numImports = getNumImports(); |
| 245 | writeUleb128(os, number: numImports, msg: "import count" ); |
| 246 | |
| 247 | bool is64 = ctx.arg.is64.value_or(u: false); |
| 248 | std::vector<WasmImport> imports; |
| 249 | imports.reserve(n: numImports); |
| 250 | |
| 251 | if (ctx.arg.memoryImport) { |
| 252 | WasmImport import; |
| 253 | import.Module = ctx.arg.memoryImport->first; |
| 254 | import.Field = ctx.arg.memoryImport->second; |
| 255 | import.Kind = WASM_EXTERNAL_MEMORY; |
| 256 | import.Memory.Flags = 0; |
| 257 | import.Memory.Minimum = out.memorySec->numMemoryPages; |
| 258 | if (out.memorySec->maxMemoryPages != 0 || ctx.arg.sharedMemory) { |
| 259 | import.Memory.Flags |= WASM_LIMITS_FLAG_HAS_MAX; |
| 260 | import.Memory.Maximum = out.memorySec->maxMemoryPages; |
| 261 | } |
| 262 | if (ctx.arg.sharedMemory) |
| 263 | import.Memory.Flags |= WASM_LIMITS_FLAG_IS_SHARED; |
| 264 | if (is64) |
| 265 | import.Memory.Flags |= WASM_LIMITS_FLAG_IS_64; |
| 266 | if (ctx.arg.pageSize != WasmDefaultPageSize) { |
| 267 | import.Memory.Flags |= WASM_LIMITS_FLAG_HAS_PAGE_SIZE; |
| 268 | import.Memory.PageSize = ctx.arg.pageSize; |
| 269 | } |
| 270 | imports.push_back(x: import); |
| 271 | } |
| 272 | |
| 273 | for (const Symbol *sym : importedSymbols) { |
| 274 | WasmImport import; |
| 275 | import.Field = sym->importName.value_or(u: sym->getName()); |
| 276 | import.Module = sym->importModule.value_or(u&: defaultModule); |
| 277 | |
| 278 | if (auto *functionSym = dyn_cast<FunctionSymbol>(Val: sym)) { |
| 279 | import.Kind = WASM_EXTERNAL_FUNCTION; |
| 280 | import.SigIndex = out.typeSec->lookupType(sig: *functionSym->signature); |
| 281 | } else if (auto *globalSym = dyn_cast<GlobalSymbol>(Val: sym)) { |
| 282 | import.Kind = WASM_EXTERNAL_GLOBAL; |
| 283 | import.Global = *globalSym->getGlobalType(); |
| 284 | } else if (auto *tagSym = dyn_cast<TagSymbol>(Val: sym)) { |
| 285 | import.Kind = WASM_EXTERNAL_TAG; |
| 286 | import.SigIndex = out.typeSec->lookupType(sig: *tagSym->signature); |
| 287 | } else { |
| 288 | auto *tableSym = cast<TableSymbol>(Val: sym); |
| 289 | import.Kind = WASM_EXTERNAL_TABLE; |
| 290 | import.Table = *tableSym->getTableType(); |
| 291 | } |
| 292 | imports.push_back(x: import); |
| 293 | } |
| 294 | |
| 295 | for (const Symbol *sym : gotSymbols) { |
| 296 | WasmImport import; |
| 297 | import.Kind = WASM_EXTERNAL_GLOBAL; |
| 298 | auto ptrType = is64 ? WASM_TYPE_I64 : WASM_TYPE_I32; |
| 299 | import.Global = {.Type: static_cast<uint8_t>(ptrType), .Mutable: true}; |
| 300 | if (isa<DataSymbol>(Val: sym)) |
| 301 | import.Module = "GOT.mem" ; |
| 302 | else |
| 303 | import.Module = "GOT.func" ; |
| 304 | import.Field = sym->getName(); |
| 305 | imports.push_back(x: import); |
| 306 | } |
| 307 | |
| 308 | bool hasCompactImports = |
| 309 | out.targetFeaturesSec->features.contains(V: "compact-imports" ); |
| 310 | uint32_t i = 0; |
| 311 | while (i < numImports) { |
| 312 | const WasmImport &import = imports[i]; |
| 313 | if (hasCompactImports) { |
| 314 | uint32_t groupSize = 1; |
| 315 | for (uint32_t j = i + 1; j < numImports; j++) { |
| 316 | if (imports[j].Module == import.Module) |
| 317 | groupSize++; |
| 318 | else |
| 319 | break; |
| 320 | } |
| 321 | if (groupSize > 1) { |
| 322 | writeStr(os, string: import.Module, msg: "module name" ); |
| 323 | writeStr(os, string: "" , msg: "empty field name" ); |
| 324 | writeU8(os, byte: 0x7F, msg: "compact imports encoding 1" ); |
| 325 | writeUleb128(os, number: groupSize, msg: "num compact imports" ); |
| 326 | while (groupSize--) { |
| 327 | writeCompactImport(os, import: imports[i++]); |
| 328 | } |
| 329 | continue; |
| 330 | } |
| 331 | } |
| 332 | writeImport(os, import: imports[i++]); |
| 333 | } |
| 334 | } |
| 335 | |
| 336 | void FunctionSection::writeBody() { |
| 337 | raw_ostream &os = bodyOutputStream; |
| 338 | |
| 339 | writeUleb128(os, number: inputFunctions.size(), msg: "function count" ); |
| 340 | for (const InputFunction *func : inputFunctions) |
| 341 | writeUleb128(os, number: out.typeSec->lookupType(sig: func->signature), msg: "sig index" ); |
| 342 | } |
| 343 | |
| 344 | void FunctionSection::addFunction(InputFunction *func) { |
| 345 | if (!func->live) |
| 346 | return; |
| 347 | uint32_t functionIndex = |
| 348 | out.importSec->getNumImportedFunctions() + inputFunctions.size(); |
| 349 | inputFunctions.emplace_back(args&: func); |
| 350 | func->setFunctionIndex(functionIndex); |
| 351 | } |
| 352 | |
| 353 | void TableSection::writeBody() { |
| 354 | raw_ostream &os = bodyOutputStream; |
| 355 | |
| 356 | writeUleb128(os, number: inputTables.size(), msg: "table count" ); |
| 357 | for (const InputTable *table : inputTables) |
| 358 | writeTableType(os, type: table->getType()); |
| 359 | } |
| 360 | |
| 361 | void TableSection::addTable(InputTable *table) { |
| 362 | if (!table->live) |
| 363 | return; |
| 364 | // Some inputs require that the indirect function table be assigned to table |
| 365 | // number 0. |
| 366 | if (ctx.legacyFunctionTable && |
| 367 | isa<DefinedTable>(Val: ctx.sym.indirectFunctionTable) && |
| 368 | cast<DefinedTable>(Val: ctx.sym.indirectFunctionTable)->table == table) { |
| 369 | if (out.importSec->getNumImportedTables()) { |
| 370 | // Alack! Some other input imported a table, meaning that we are unable |
| 371 | // to assign table number 0 to the indirect function table. |
| 372 | for (const auto *culprit : out.importSec->importedSymbols) { |
| 373 | if (isa<UndefinedTable>(Val: culprit)) { |
| 374 | error(msg: "object file not built with 'reference-types' or " |
| 375 | "'call-indirect-overlong' feature conflicts with import of " |
| 376 | "table " + |
| 377 | culprit->getName() + " by file " + |
| 378 | toString(file: culprit->getFile())); |
| 379 | return; |
| 380 | } |
| 381 | } |
| 382 | llvm_unreachable("failed to find conflicting table import" ); |
| 383 | } |
| 384 | inputTables.insert(position: inputTables.begin(), x: table); |
| 385 | return; |
| 386 | } |
| 387 | inputTables.push_back(x: table); |
| 388 | } |
| 389 | |
| 390 | void TableSection::assignIndexes() { |
| 391 | uint32_t tableNumber = out.importSec->getNumImportedTables(); |
| 392 | for (InputTable *t : inputTables) |
| 393 | t->assignIndex(index: tableNumber++); |
| 394 | } |
| 395 | |
| 396 | void MemorySection::writeBody() { |
| 397 | raw_ostream &os = bodyOutputStream; |
| 398 | |
| 399 | bool hasMax = maxMemoryPages != 0 || ctx.arg.sharedMemory; |
| 400 | writeUleb128(os, number: 1, msg: "memory count" ); |
| 401 | unsigned flags = 0; |
| 402 | if (hasMax) |
| 403 | flags |= WASM_LIMITS_FLAG_HAS_MAX; |
| 404 | if (ctx.arg.sharedMemory) |
| 405 | flags |= WASM_LIMITS_FLAG_IS_SHARED; |
| 406 | if (ctx.arg.is64.value_or(u: false)) |
| 407 | flags |= WASM_LIMITS_FLAG_IS_64; |
| 408 | if (ctx.arg.pageSize != WasmDefaultPageSize) |
| 409 | flags |= WASM_LIMITS_FLAG_HAS_PAGE_SIZE; |
| 410 | writeUleb128(os, number: flags, msg: "memory limits flags" ); |
| 411 | writeUleb128(os, number: numMemoryPages, msg: "initial pages" ); |
| 412 | if (hasMax) |
| 413 | writeUleb128(os, number: maxMemoryPages, msg: "max pages" ); |
| 414 | if (ctx.arg.pageSize != WasmDefaultPageSize) |
| 415 | writeUleb128(os, number: llvm::Log2_64(Value: ctx.arg.pageSize), msg: "page size" ); |
| 416 | } |
| 417 | |
| 418 | void TagSection::writeBody() { |
| 419 | raw_ostream &os = bodyOutputStream; |
| 420 | |
| 421 | writeUleb128(os, number: inputTags.size(), msg: "tag count" ); |
| 422 | for (InputTag *t : inputTags) { |
| 423 | writeUleb128(os, number: 0, msg: "tag attribute" ); // Reserved "attribute" field |
| 424 | writeUleb128(os, number: out.typeSec->lookupType(sig: t->signature), msg: "sig index" ); |
| 425 | } |
| 426 | } |
| 427 | |
| 428 | void TagSection::addTag(InputTag *tag) { |
| 429 | if (!tag->live) |
| 430 | return; |
| 431 | uint32_t tagIndex = out.importSec->getNumImportedTags() + inputTags.size(); |
| 432 | LLVM_DEBUG(dbgs() << "addTag: " << tagIndex << "\n" ); |
| 433 | tag->assignIndex(index: tagIndex); |
| 434 | inputTags.push_back(x: tag); |
| 435 | } |
| 436 | |
| 437 | void GlobalSection::assignIndexes() { |
| 438 | uint32_t globalIndex = out.importSec->getNumImportedGlobals(); |
| 439 | for (InputGlobal *g : inputGlobals) |
| 440 | g->assignIndex(index: globalIndex++); |
| 441 | for (Symbol *sym : internalGotSymbols) |
| 442 | sym->setGOTIndex(globalIndex++); |
| 443 | isSealed = true; |
| 444 | } |
| 445 | |
| 446 | static void ensureIndirectFunctionTable() { |
| 447 | if (!ctx.sym.indirectFunctionTable) |
| 448 | ctx.sym.indirectFunctionTable = |
| 449 | symtab->resolveIndirectFunctionTable(/*required =*/true); |
| 450 | } |
| 451 | |
| 452 | void GlobalSection::addInternalGOTEntry(Symbol *sym) { |
| 453 | assert(!isSealed); |
| 454 | if (sym->requiresGOT) |
| 455 | return; |
| 456 | LLVM_DEBUG(dbgs() << "addInternalGOTEntry: " << sym->getName() << " " |
| 457 | << toString(sym->kind()) << "\n" ); |
| 458 | sym->requiresGOT = true; |
| 459 | if (auto *F = dyn_cast<FunctionSymbol>(Val: sym)) { |
| 460 | ensureIndirectFunctionTable(); |
| 461 | out.elemSec->addEntry(sym: F); |
| 462 | } |
| 463 | internalGotSymbols.push_back(x: sym); |
| 464 | } |
| 465 | |
| 466 | void GlobalSection::generateRelocationCode(raw_ostream &os, bool TLS) const { |
| 467 | assert(!ctx.arg.extendedConst); |
| 468 | bool is64 = ctx.arg.is64.value_or(u: false); |
| 469 | unsigned opcode_ptr_add = is64 ? WASM_OPCODE_I64_ADD : WASM_OPCODE_I32_ADD; |
| 470 | |
| 471 | for (const Symbol *sym : internalGotSymbols) { |
| 472 | if (TLS != sym->isTLS()) |
| 473 | continue; |
| 474 | |
| 475 | if (auto *d = dyn_cast<DefinedData>(Val: sym)) { |
| 476 | // Get __memory_base |
| 477 | writeU8(os, byte: WASM_OPCODE_GLOBAL_GET, msg: "GLOBAL_GET" ); |
| 478 | if (sym->isTLS()) |
| 479 | writeUleb128(os, number: ctx.sym.tlsBase->getGlobalIndex(), msg: "__tls_base" ); |
| 480 | else |
| 481 | writeUleb128(os, number: ctx.sym.memoryBase->getGlobalIndex(), msg: "__memory_base" ); |
| 482 | |
| 483 | // Add the virtual address of the data symbol |
| 484 | writePtrConst(os, number: d->getVA(), is64, msg: "offset" ); |
| 485 | } else if (auto *f = dyn_cast<FunctionSymbol>(Val: sym)) { |
| 486 | if (f->isStub) |
| 487 | continue; |
| 488 | // Get __table_base |
| 489 | writeU8(os, byte: WASM_OPCODE_GLOBAL_GET, msg: "GLOBAL_GET" ); |
| 490 | writeUleb128(os, number: ctx.sym.tableBase->getGlobalIndex(), msg: "__table_base" ); |
| 491 | |
| 492 | // Add the table index to __table_base |
| 493 | writePtrConst(os, number: f->getTableIndex(), is64, msg: "offset" ); |
| 494 | } else { |
| 495 | assert(isa<UndefinedData>(sym) || isa<SharedData>(sym)); |
| 496 | continue; |
| 497 | } |
| 498 | writeU8(os, byte: opcode_ptr_add, msg: "ADD" ); |
| 499 | writeU8(os, byte: WASM_OPCODE_GLOBAL_SET, msg: "GLOBAL_SET" ); |
| 500 | writeUleb128(os, number: sym->getGOTIndex(), msg: "got_entry" ); |
| 501 | } |
| 502 | } |
| 503 | |
| 504 | void GlobalSection::writeBody() { |
| 505 | raw_ostream &os = bodyOutputStream; |
| 506 | |
| 507 | writeUleb128(os, number: numGlobals(), msg: "global count" ); |
| 508 | for (InputGlobal *g : inputGlobals) { |
| 509 | writeGlobalType(os, type: g->getType()); |
| 510 | writeInitExpr(os, initExpr: g->getInitExpr()); |
| 511 | } |
| 512 | bool is64 = ctx.arg.is64.value_or(u: false); |
| 513 | uint8_t itype = is64 ? WASM_TYPE_I64 : WASM_TYPE_I32; |
| 514 | for (const Symbol *sym : internalGotSymbols) { |
| 515 | bool mutable_ = false; |
| 516 | if (!sym->isStub) { |
| 517 | // In the case of dynamic linking, unless we have 'extended-const' |
| 518 | // available, these global must to be mutable since they get updated to |
| 519 | // the correct runtime value during `__wasm_apply_global_relocs`. |
| 520 | if (!ctx.arg.extendedConst && ctx.isPic && !sym->isTLS()) |
| 521 | mutable_ = true; |
| 522 | // With multi-theadeding any TLS globals must be mutable since they get |
| 523 | // set during `__wasm_apply_global_tls_relocs` |
| 524 | if (ctx.arg.sharedMemory && sym->isTLS()) |
| 525 | mutable_ = true; |
| 526 | } |
| 527 | WasmGlobalType type{.Type: itype, .Mutable: mutable_}; |
| 528 | writeGlobalType(os, type); |
| 529 | |
| 530 | bool useExtendedConst = false; |
| 531 | uint32_t globalIdx; |
| 532 | int64_t offset; |
| 533 | if (ctx.arg.extendedConst && ctx.isPic) { |
| 534 | if (auto *d = dyn_cast<DefinedData>(Val: sym)) { |
| 535 | if (!sym->isTLS()) { |
| 536 | globalIdx = ctx.sym.memoryBase->getGlobalIndex(); |
| 537 | offset = d->getVA(); |
| 538 | useExtendedConst = true; |
| 539 | } |
| 540 | } else if (auto *f = dyn_cast<FunctionSymbol>(Val: sym)) { |
| 541 | if (!sym->isStub) { |
| 542 | globalIdx = ctx.sym.tableBase->getGlobalIndex(); |
| 543 | offset = f->getTableIndex(); |
| 544 | useExtendedConst = true; |
| 545 | } |
| 546 | } |
| 547 | } |
| 548 | if (useExtendedConst) { |
| 549 | // We can use an extended init expression to add a constant |
| 550 | // offset of __memory_base/__table_base. |
| 551 | writeU8(os, byte: WASM_OPCODE_GLOBAL_GET, msg: "global get" ); |
| 552 | writeUleb128(os, number: globalIdx, msg: "literal (global index)" ); |
| 553 | if (offset) { |
| 554 | writePtrConst(os, number: offset, is64, msg: "offset" ); |
| 555 | writeU8(os, byte: is64 ? WASM_OPCODE_I64_ADD : WASM_OPCODE_I32_ADD, msg: "add" ); |
| 556 | } |
| 557 | writeU8(os, byte: WASM_OPCODE_END, msg: "opcode:end" ); |
| 558 | } else { |
| 559 | WasmInitExpr initExpr; |
| 560 | if (auto *d = dyn_cast<DefinedData>(Val: sym)) |
| 561 | // In the sharedMemory case TLS globals are set during |
| 562 | // `__wasm_apply_global_tls_relocs`, but in the non-shared case |
| 563 | // we know the absolute value at link time. |
| 564 | initExpr = intConst(value: d->getVA(/*absolute=*/!ctx.arg.sharedMemory), is64); |
| 565 | else if (auto *f = dyn_cast<FunctionSymbol>(Val: sym)) |
| 566 | initExpr = intConst(value: f->isStub ? 0 : f->getTableIndex(), is64); |
| 567 | else { |
| 568 | assert(isa<UndefinedData>(sym) || isa<SharedData>(sym)); |
| 569 | initExpr = intConst(value: 0, is64); |
| 570 | } |
| 571 | writeInitExpr(os, initExpr); |
| 572 | } |
| 573 | } |
| 574 | for (const DefinedData *sym : dataAddressGlobals) { |
| 575 | WasmGlobalType type{.Type: itype, .Mutable: false}; |
| 576 | writeGlobalType(os, type); |
| 577 | writeInitExpr(os, initExpr: intConst(value: sym->getVA(), is64)); |
| 578 | } |
| 579 | } |
| 580 | |
| 581 | void GlobalSection::addGlobal(InputGlobal *global) { |
| 582 | assert(!isSealed); |
| 583 | if (!global->live) |
| 584 | return; |
| 585 | inputGlobals.push_back(x: global); |
| 586 | } |
| 587 | |
| 588 | void ExportSection::writeBody() { |
| 589 | raw_ostream &os = bodyOutputStream; |
| 590 | |
| 591 | writeUleb128(os, number: exports.size(), msg: "export count" ); |
| 592 | for (const WasmExport &export_ : exports) |
| 593 | writeExport(os, export_); |
| 594 | } |
| 595 | |
| 596 | bool StartSection::isNeeded() const { return ctx.sym.startFunction != nullptr; } |
| 597 | |
| 598 | void StartSection::writeBody() { |
| 599 | raw_ostream &os = bodyOutputStream; |
| 600 | writeUleb128(os, number: ctx.sym.startFunction->getFunctionIndex(), msg: "function index" ); |
| 601 | } |
| 602 | |
| 603 | void ElemSection::addEntry(FunctionSymbol *sym) { |
| 604 | // Don't add stub functions to the wasm table. The address of all stub |
| 605 | // functions should be zero and they should they don't appear in the table. |
| 606 | // They only exist so that the calls to missing functions can validate. |
| 607 | if (sym->hasTableIndex() || sym->isStub) |
| 608 | return; |
| 609 | sym->setTableIndex(ctx.arg.tableBase + indirectFunctions.size()); |
| 610 | indirectFunctions.emplace_back(args&: sym); |
| 611 | } |
| 612 | |
| 613 | void ElemSection::writeBody() { |
| 614 | raw_ostream &os = bodyOutputStream; |
| 615 | |
| 616 | assert(ctx.sym.indirectFunctionTable); |
| 617 | writeUleb128(os, number: 1, msg: "segment count" ); |
| 618 | uint32_t tableNumber = ctx.sym.indirectFunctionTable->getTableNumber(); |
| 619 | uint32_t flags = 0; |
| 620 | if (tableNumber) |
| 621 | flags |= WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER; |
| 622 | writeUleb128(os, number: flags, msg: "elem segment flags" ); |
| 623 | if (flags & WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER) |
| 624 | writeUleb128(os, number: tableNumber, msg: "table number" ); |
| 625 | |
| 626 | WasmInitExpr initExpr; |
| 627 | initExpr.Extended = false; |
| 628 | if (ctx.isPic) { |
| 629 | initExpr.Inst.Opcode = WASM_OPCODE_GLOBAL_GET; |
| 630 | initExpr.Inst.Value.Global = ctx.sym.tableBase->getGlobalIndex(); |
| 631 | } else { |
| 632 | bool is64 = ctx.arg.is64.value_or(u: false); |
| 633 | initExpr = intConst(value: ctx.arg.tableBase, is64); |
| 634 | } |
| 635 | writeInitExpr(os, initExpr); |
| 636 | |
| 637 | if (flags & WASM_ELEM_SEGMENT_MASK_HAS_ELEM_DESC) { |
| 638 | // We only write active function table initializers, for which the elem kind |
| 639 | // is specified to be written as 0x00 and interpreted to mean "funcref". |
| 640 | const uint8_t elemKind = 0; |
| 641 | writeU8(os, byte: elemKind, msg: "elem kind" ); |
| 642 | } |
| 643 | |
| 644 | writeUleb128(os, number: indirectFunctions.size(), msg: "elem count" ); |
| 645 | uint32_t tableIndex = ctx.arg.tableBase; |
| 646 | for (const FunctionSymbol *sym : indirectFunctions) { |
| 647 | assert(sym->getTableIndex() == tableIndex); |
| 648 | (void)tableIndex; |
| 649 | writeUleb128(os, number: sym->getFunctionIndex(), msg: "function index" ); |
| 650 | ++tableIndex; |
| 651 | } |
| 652 | } |
| 653 | |
| 654 | DataCountSection::DataCountSection(ArrayRef<OutputSegment *> segments) |
| 655 | : SyntheticSection(llvm::wasm::WASM_SEC_DATACOUNT), |
| 656 | numSegments(llvm::count_if(Range&: segments, P: [](OutputSegment *const segment) { |
| 657 | return segment->requiredInBinary(); |
| 658 | })) {} |
| 659 | |
| 660 | void DataCountSection::writeBody() { |
| 661 | writeUleb128(os&: bodyOutputStream, number: numSegments, msg: "data count" ); |
| 662 | } |
| 663 | |
| 664 | bool DataCountSection::isNeeded() const { |
| 665 | // The datacount section is only required under certain circumstance. |
| 666 | // Specifically, when the module includes bulk memory instructions that deal |
| 667 | // with passive data segments. i.e. memory.init/data.drop. |
| 668 | // LLVM does not yet have relocation types for data segments so these |
| 669 | // instructions are not yet supported in input files. However, in the case |
| 670 | // of shared memory, lld itself will generate these instructions as part of |
| 671 | // `__wasm_init_memory`. See Writer::createInitMemoryFunction. |
| 672 | return numSegments && ctx.arg.sharedMemory; |
| 673 | } |
| 674 | |
| 675 | void LinkingSection::writeBody() { |
| 676 | raw_ostream &os = bodyOutputStream; |
| 677 | |
| 678 | writeUleb128(os, number: WasmMetadataVersion, msg: "Version" ); |
| 679 | |
| 680 | if (!symtabEntries.empty()) { |
| 681 | SubSection sub(WASM_SYMBOL_TABLE); |
| 682 | writeUleb128(os&: sub.os, number: symtabEntries.size(), msg: "num symbols" ); |
| 683 | |
| 684 | for (const Symbol *sym : symtabEntries) { |
| 685 | assert(sym->isDefined() || sym->isUndefined()); |
| 686 | WasmSymbolType kind = sym->getWasmType(); |
| 687 | uint32_t flags = sym->flags; |
| 688 | |
| 689 | writeU8(os&: sub.os, byte: kind, msg: "sym kind" ); |
| 690 | writeUleb128(os&: sub.os, number: flags, msg: "sym flags" ); |
| 691 | |
| 692 | if (auto *f = dyn_cast<FunctionSymbol>(Val: sym)) { |
| 693 | if (auto *d = dyn_cast<DefinedFunction>(Val: sym)) { |
| 694 | writeUleb128(os&: sub.os, number: d->getExportedFunctionIndex(), msg: "index" ); |
| 695 | } else { |
| 696 | writeUleb128(os&: sub.os, number: f->getFunctionIndex(), msg: "index" ); |
| 697 | } |
| 698 | if (sym->isDefined() || (flags & WASM_SYMBOL_EXPLICIT_NAME) != 0) |
| 699 | writeStr(os&: sub.os, string: sym->getName(), msg: "sym name" ); |
| 700 | } else if (auto *g = dyn_cast<GlobalSymbol>(Val: sym)) { |
| 701 | writeUleb128(os&: sub.os, number: g->getGlobalIndex(), msg: "index" ); |
| 702 | if (sym->isDefined() || (flags & WASM_SYMBOL_EXPLICIT_NAME) != 0) |
| 703 | writeStr(os&: sub.os, string: sym->getName(), msg: "sym name" ); |
| 704 | } else if (auto *t = dyn_cast<TagSymbol>(Val: sym)) { |
| 705 | writeUleb128(os&: sub.os, number: t->getTagIndex(), msg: "index" ); |
| 706 | if (sym->isDefined() || (flags & WASM_SYMBOL_EXPLICIT_NAME) != 0) |
| 707 | writeStr(os&: sub.os, string: sym->getName(), msg: "sym name" ); |
| 708 | } else if (auto *t = dyn_cast<TableSymbol>(Val: sym)) { |
| 709 | writeUleb128(os&: sub.os, number: t->getTableNumber(), msg: "table number" ); |
| 710 | if (sym->isDefined() || (flags & WASM_SYMBOL_EXPLICIT_NAME) != 0) |
| 711 | writeStr(os&: sub.os, string: sym->getName(), msg: "sym name" ); |
| 712 | } else if (isa<DataSymbol>(Val: sym)) { |
| 713 | writeStr(os&: sub.os, string: sym->getName(), msg: "sym name" ); |
| 714 | if (auto *dataSym = dyn_cast<DefinedData>(Val: sym)) { |
| 715 | if (dataSym->segment) { |
| 716 | writeUleb128(os&: sub.os, number: dataSym->getOutputSegmentIndex(), msg: "index" ); |
| 717 | writeUleb128(os&: sub.os, number: dataSym->getOutputSegmentOffset(), |
| 718 | msg: "data offset" ); |
| 719 | } else { |
| 720 | writeUleb128(os&: sub.os, number: 0, msg: "index" ); |
| 721 | writeUleb128(os&: sub.os, number: dataSym->getVA(), msg: "data offset" ); |
| 722 | } |
| 723 | writeUleb128(os&: sub.os, number: dataSym->getSize(), msg: "data size" ); |
| 724 | } |
| 725 | } else { |
| 726 | auto *s = cast<OutputSectionSymbol>(Val: sym); |
| 727 | writeUleb128(os&: sub.os, number: s->section->sectionIndex, msg: "sym section index" ); |
| 728 | } |
| 729 | } |
| 730 | |
| 731 | sub.writeTo(to&: os); |
| 732 | } |
| 733 | |
| 734 | if (dataSegments.size()) { |
| 735 | SubSection sub(WASM_SEGMENT_INFO); |
| 736 | writeUleb128(os&: sub.os, number: dataSegments.size(), msg: "num data segments" ); |
| 737 | for (const OutputSegment *s : dataSegments) { |
| 738 | writeStr(os&: sub.os, string: s->name, msg: "segment name" ); |
| 739 | writeUleb128(os&: sub.os, number: s->alignment, msg: "alignment" ); |
| 740 | writeUleb128(os&: sub.os, number: s->linkingFlags, msg: "flags" ); |
| 741 | } |
| 742 | sub.writeTo(to&: os); |
| 743 | } |
| 744 | |
| 745 | if (!initFunctions.empty()) { |
| 746 | SubSection sub(WASM_INIT_FUNCS); |
| 747 | writeUleb128(os&: sub.os, number: initFunctions.size(), msg: "num init functions" ); |
| 748 | for (const WasmInitEntry &f : initFunctions) { |
| 749 | writeUleb128(os&: sub.os, number: f.priority, msg: "priority" ); |
| 750 | writeUleb128(os&: sub.os, number: f.sym->getOutputSymbolIndex(), msg: "function index" ); |
| 751 | } |
| 752 | sub.writeTo(to&: os); |
| 753 | } |
| 754 | |
| 755 | struct ComdatEntry { |
| 756 | unsigned kind; |
| 757 | uint32_t index; |
| 758 | }; |
| 759 | std::map<StringRef, std::vector<ComdatEntry>> comdats; |
| 760 | |
| 761 | for (const InputFunction *f : out.functionSec->inputFunctions) { |
| 762 | StringRef comdat = f->getComdatName(); |
| 763 | if (!comdat.empty()) |
| 764 | comdats[comdat].emplace_back( |
| 765 | args: ComdatEntry{.kind: WASM_COMDAT_FUNCTION, .index: f->getFunctionIndex()}); |
| 766 | } |
| 767 | for (uint32_t i = 0; i < dataSegments.size(); ++i) { |
| 768 | const auto &inputSegments = dataSegments[i]->inputSegments; |
| 769 | if (inputSegments.empty()) |
| 770 | continue; |
| 771 | StringRef comdat = inputSegments[0]->getComdatName(); |
| 772 | #ifndef NDEBUG |
| 773 | for (const InputChunk *isec : inputSegments) |
| 774 | assert(isec->getComdatName() == comdat); |
| 775 | #endif |
| 776 | if (!comdat.empty()) |
| 777 | comdats[comdat].emplace_back(args: ComdatEntry{.kind: WASM_COMDAT_DATA, .index: i}); |
| 778 | } |
| 779 | |
| 780 | if (!comdats.empty()) { |
| 781 | SubSection sub(WASM_COMDAT_INFO); |
| 782 | writeUleb128(os&: sub.os, number: comdats.size(), msg: "num comdats" ); |
| 783 | for (const auto &c : comdats) { |
| 784 | writeStr(os&: sub.os, string: c.first, msg: "comdat name" ); |
| 785 | writeUleb128(os&: sub.os, number: 0, msg: "comdat flags" ); // flags for future use |
| 786 | writeUleb128(os&: sub.os, number: c.second.size(), msg: "num entries" ); |
| 787 | for (const ComdatEntry &entry : c.second) { |
| 788 | writeU8(os&: sub.os, byte: entry.kind, msg: "entry kind" ); |
| 789 | writeUleb128(os&: sub.os, number: entry.index, msg: "entry index" ); |
| 790 | } |
| 791 | } |
| 792 | sub.writeTo(to&: os); |
| 793 | } |
| 794 | } |
| 795 | |
| 796 | void LinkingSection::addToSymtab(Symbol *sym) { |
| 797 | sym->setOutputSymbolIndex(symtabEntries.size()); |
| 798 | symtabEntries.emplace_back(args&: sym); |
| 799 | } |
| 800 | |
| 801 | unsigned NameSection::numNamedFunctions() const { |
| 802 | unsigned numNames = out.importSec->getNumImportedFunctions(); |
| 803 | |
| 804 | for (const InputFunction *f : out.functionSec->inputFunctions) |
| 805 | if (!f->name.empty() || !f->debugName.empty()) |
| 806 | ++numNames; |
| 807 | |
| 808 | return numNames; |
| 809 | } |
| 810 | |
| 811 | unsigned NameSection::numNamedGlobals() const { |
| 812 | unsigned numNames = out.importSec->getNumImportedGlobals(); |
| 813 | |
| 814 | for (const InputGlobal *g : out.globalSec->inputGlobals) |
| 815 | if (!g->getName().empty()) |
| 816 | ++numNames; |
| 817 | |
| 818 | numNames += out.globalSec->internalGotSymbols.size(); |
| 819 | return numNames; |
| 820 | } |
| 821 | |
| 822 | unsigned NameSection::numNamedDataSegments() const { |
| 823 | unsigned numNames = 0; |
| 824 | |
| 825 | for (const OutputSegment *s : segments) |
| 826 | if (!s->name.empty() && s->requiredInBinary()) |
| 827 | ++numNames; |
| 828 | |
| 829 | return numNames; |
| 830 | } |
| 831 | |
| 832 | // Create the custom "name" section containing debug symbol names. |
| 833 | void NameSection::writeBody() { |
| 834 | { |
| 835 | SubSection sub(WASM_NAMES_MODULE); |
| 836 | StringRef moduleName = ctx.arg.soName; |
| 837 | if (ctx.arg.soName.empty()) |
| 838 | moduleName = llvm::sys::path::filename(path: ctx.arg.outputFile); |
| 839 | writeStr(os&: sub.os, string: moduleName, msg: "module name" ); |
| 840 | sub.writeTo(to&: bodyOutputStream); |
| 841 | } |
| 842 | |
| 843 | unsigned count = numNamedFunctions(); |
| 844 | if (count) { |
| 845 | SubSection sub(WASM_NAMES_FUNCTION); |
| 846 | writeUleb128(os&: sub.os, number: count, msg: "name count" ); |
| 847 | |
| 848 | // Function names appear in function index order. As it happens |
| 849 | // importedSymbols and inputFunctions are numbered in order with imported |
| 850 | // functions coming first. |
| 851 | for (const Symbol *s : out.importSec->importedSymbols) { |
| 852 | if (auto *f = dyn_cast<FunctionSymbol>(Val: s)) { |
| 853 | writeUleb128(os&: sub.os, number: f->getFunctionIndex(), msg: "func index" ); |
| 854 | writeStr(os&: sub.os, string: toString(sym: *s), msg: "symbol name" ); |
| 855 | } |
| 856 | } |
| 857 | for (const InputFunction *f : out.functionSec->inputFunctions) { |
| 858 | if (!f->name.empty()) { |
| 859 | writeUleb128(os&: sub.os, number: f->getFunctionIndex(), msg: "func index" ); |
| 860 | if (!f->debugName.empty()) { |
| 861 | writeStr(os&: sub.os, string: f->debugName, msg: "symbol name" ); |
| 862 | } else { |
| 863 | writeStr(os&: sub.os, string: maybeDemangleSymbol(name: f->name), msg: "symbol name" ); |
| 864 | } |
| 865 | } |
| 866 | } |
| 867 | sub.writeTo(to&: bodyOutputStream); |
| 868 | } |
| 869 | |
| 870 | count = numNamedGlobals(); |
| 871 | if (count) { |
| 872 | SubSection sub(WASM_NAMES_GLOBAL); |
| 873 | writeUleb128(os&: sub.os, number: count, msg: "name count" ); |
| 874 | |
| 875 | for (const Symbol *s : out.importSec->importedSymbols) { |
| 876 | if (auto *g = dyn_cast<GlobalSymbol>(Val: s)) { |
| 877 | writeUleb128(os&: sub.os, number: g->getGlobalIndex(), msg: "global index" ); |
| 878 | writeStr(os&: sub.os, string: toString(sym: *s), msg: "symbol name" ); |
| 879 | } |
| 880 | } |
| 881 | for (const Symbol *s : out.importSec->gotSymbols) { |
| 882 | writeUleb128(os&: sub.os, number: s->getGOTIndex(), msg: "global index" ); |
| 883 | writeStr(os&: sub.os, string: toString(sym: *s), msg: "symbol name" ); |
| 884 | } |
| 885 | for (const InputGlobal *g : out.globalSec->inputGlobals) { |
| 886 | if (!g->getName().empty()) { |
| 887 | writeUleb128(os&: sub.os, number: g->getAssignedIndex(), msg: "global index" ); |
| 888 | writeStr(os&: sub.os, string: maybeDemangleSymbol(name: g->getName()), msg: "symbol name" ); |
| 889 | } |
| 890 | } |
| 891 | for (Symbol *s : out.globalSec->internalGotSymbols) { |
| 892 | writeUleb128(os&: sub.os, number: s->getGOTIndex(), msg: "global index" ); |
| 893 | if (isa<FunctionSymbol>(Val: s)) |
| 894 | writeStr(os&: sub.os, string: "GOT.func.internal." + toString(sym: *s), msg: "symbol name" ); |
| 895 | else |
| 896 | writeStr(os&: sub.os, string: "GOT.data.internal." + toString(sym: *s), msg: "symbol name" ); |
| 897 | } |
| 898 | |
| 899 | sub.writeTo(to&: bodyOutputStream); |
| 900 | } |
| 901 | |
| 902 | count = numNamedDataSegments(); |
| 903 | if (count) { |
| 904 | SubSection sub(WASM_NAMES_DATA_SEGMENT); |
| 905 | writeUleb128(os&: sub.os, number: count, msg: "name count" ); |
| 906 | |
| 907 | for (OutputSegment *s : segments) { |
| 908 | if (!s->name.empty() && s->requiredInBinary()) { |
| 909 | writeUleb128(os&: sub.os, number: s->index, msg: "global index" ); |
| 910 | writeStr(os&: sub.os, string: s->name, msg: "segment name" ); |
| 911 | } |
| 912 | } |
| 913 | |
| 914 | sub.writeTo(to&: bodyOutputStream); |
| 915 | } |
| 916 | } |
| 917 | |
| 918 | void ProducersSection::(const WasmProducerInfo &info) { |
| 919 | for (auto &producers : |
| 920 | {std::make_pair(x: &info.Languages, y: &languages), |
| 921 | std::make_pair(x: &info.Tools, y: &tools), std::make_pair(x: &info.SDKs, y: &sDKs)}) |
| 922 | for (auto &producer : *producers.first) |
| 923 | if (llvm::none_of(Range&: *producers.second, |
| 924 | P: [&](std::pair<std::string, std::string> seen) { |
| 925 | return seen.first == producer.first; |
| 926 | })) |
| 927 | producers.second->push_back(Elt: producer); |
| 928 | } |
| 929 | |
| 930 | void ProducersSection::writeBody() { |
| 931 | auto &os = bodyOutputStream; |
| 932 | writeUleb128(os, number: fieldCount(), msg: "field count" ); |
| 933 | for (auto &field : |
| 934 | {std::make_pair(x: "language" , y&: languages), |
| 935 | std::make_pair(x: "processed-by" , y&: tools), std::make_pair(x: "sdk" , y&: sDKs)}) { |
| 936 | if (field.second.empty()) |
| 937 | continue; |
| 938 | writeStr(os, string: field.first, msg: "field name" ); |
| 939 | writeUleb128(os, number: field.second.size(), msg: "number of entries" ); |
| 940 | for (auto &entry : field.second) { |
| 941 | writeStr(os, string: entry.first, msg: "producer name" ); |
| 942 | writeStr(os, string: entry.second, msg: "producer version" ); |
| 943 | } |
| 944 | } |
| 945 | } |
| 946 | |
| 947 | void TargetFeaturesSection::writeBody() { |
| 948 | SmallVector<std::string, 8> emitted(features.begin(), features.end()); |
| 949 | llvm::sort(C&: emitted); |
| 950 | auto &os = bodyOutputStream; |
| 951 | writeUleb128(os, number: emitted.size(), msg: "feature count" ); |
| 952 | for (auto &feature : emitted) { |
| 953 | writeU8(os, byte: WASM_FEATURE_PREFIX_USED, msg: "feature used prefix" ); |
| 954 | writeStr(os, string: feature, msg: "feature name" ); |
| 955 | } |
| 956 | } |
| 957 | |
| 958 | void RelocSection::writeBody() { |
| 959 | uint32_t count = sec->getNumRelocations(); |
| 960 | assert(sec->sectionIndex != UINT32_MAX); |
| 961 | writeUleb128(os&: bodyOutputStream, number: sec->sectionIndex, msg: "reloc section" ); |
| 962 | writeUleb128(os&: bodyOutputStream, number: count, msg: "reloc count" ); |
| 963 | sec->writeRelocations(os&: bodyOutputStream); |
| 964 | } |
| 965 | |
| 966 | static size_t getHashSize() { |
| 967 | switch (ctx.arg.buildId) { |
| 968 | case BuildIdKind::Fast: |
| 969 | case BuildIdKind::Uuid: |
| 970 | return 16; |
| 971 | case BuildIdKind::Sha1: |
| 972 | return 20; |
| 973 | case BuildIdKind::Hexstring: |
| 974 | return ctx.arg.buildIdVector.size(); |
| 975 | case BuildIdKind::None: |
| 976 | return 0; |
| 977 | } |
| 978 | llvm_unreachable("build id kind not implemented" ); |
| 979 | } |
| 980 | |
| 981 | BuildIdSection::BuildIdSection() |
| 982 | : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, buildIdSectionName), |
| 983 | hashSize(getHashSize()) {} |
| 984 | |
| 985 | void BuildIdSection::writeBody() { |
| 986 | LLVM_DEBUG(llvm::dbgs() << "BuildId writebody\n" ); |
| 987 | // Write hash size |
| 988 | auto &os = bodyOutputStream; |
| 989 | writeUleb128(os, number: hashSize, msg: "build id size" ); |
| 990 | writeBytes(os, bytes: std::vector<char>(hashSize, ' ').data(), count: hashSize, |
| 991 | msg: "placeholder" ); |
| 992 | } |
| 993 | |
| 994 | void BuildIdSection::writeBuildId(llvm::ArrayRef<uint8_t> buf) { |
| 995 | assert(buf.size() == hashSize); |
| 996 | LLVM_DEBUG(dbgs() << "buildid write " << buf.size() << " " |
| 997 | << hashPlaceholderPtr << '\n'); |
| 998 | memcpy(dest: hashPlaceholderPtr, src: buf.data(), n: hashSize); |
| 999 | } |
| 1000 | |
| 1001 | } // namespace lld::wasm |
| 1002 | |