1 //===- Symbols.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 #include "Symbols.h" 10 #include "Config.h" 11 #include "InputChunks.h" 12 #include "InputElement.h" 13 #include "InputFiles.h" 14 #include "OutputSections.h" 15 #include "OutputSegment.h" 16 #include "SymbolTable.h" 17 #include "lld/Common/ErrorHandler.h" 18 #include "lld/Common/Memory.h" 19 #include "llvm/Demangle/Demangle.h" 20 21 #define DEBUG_TYPE "lld" 22 23 using namespace llvm; 24 using namespace llvm::object; 25 using namespace llvm::wasm; 26 using namespace lld::wasm; 27 28 namespace lld { 29 std::string toString(const wasm::Symbol &sym) { 30 return maybeDemangleSymbol(sym.getName()); 31 } 32 33 std::string maybeDemangleSymbol(StringRef name) { 34 // WebAssembly requires caller and callee signatures to match, so we mangle 35 // `main` in the case where we need to pass it arguments. 36 if (name == "__main_argc_argv") 37 return "main"; 38 if (wasm::ctx.arg.demangle) 39 return demangle(name); 40 return name.str(); 41 } 42 43 std::string toString(wasm::Symbol::Kind kind) { 44 switch (kind) { 45 case wasm::Symbol::DefinedFunctionKind: 46 return "DefinedFunction"; 47 case wasm::Symbol::DefinedDataKind: 48 return "DefinedData"; 49 case wasm::Symbol::DefinedGlobalKind: 50 return "DefinedGlobal"; 51 case wasm::Symbol::DefinedTableKind: 52 return "DefinedTable"; 53 case wasm::Symbol::DefinedTagKind: 54 return "DefinedTag"; 55 case wasm::Symbol::UndefinedFunctionKind: 56 return "UndefinedFunction"; 57 case wasm::Symbol::UndefinedDataKind: 58 return "UndefinedData"; 59 case wasm::Symbol::UndefinedGlobalKind: 60 return "UndefinedGlobal"; 61 case wasm::Symbol::UndefinedTableKind: 62 return "UndefinedTable"; 63 case wasm::Symbol::UndefinedTagKind: 64 return "UndefinedTag"; 65 case wasm::Symbol::LazyKind: 66 return "LazyKind"; 67 case wasm::Symbol::SectionKind: 68 return "SectionKind"; 69 case wasm::Symbol::OutputSectionKind: 70 return "OutputSectionKind"; 71 case wasm::Symbol::SharedFunctionKind: 72 return "SharedFunctionKind"; 73 case wasm::Symbol::SharedDataKind: 74 return "SharedDataKind"; 75 } 76 llvm_unreachable("invalid symbol kind"); 77 } 78 79 namespace wasm { 80 DefinedFunction *WasmSym::callCtors; 81 DefinedFunction *WasmSym::callDtors; 82 DefinedFunction *WasmSym::initMemory; 83 DefinedFunction *WasmSym::applyGlobalRelocs; 84 DefinedFunction *WasmSym::applyTLSRelocs; 85 DefinedFunction *WasmSym::applyGlobalTLSRelocs; 86 DefinedFunction *WasmSym::initTLS; 87 DefinedFunction *WasmSym::startFunction; 88 DefinedData *WasmSym::dsoHandle; 89 DefinedData *WasmSym::dataEnd; 90 DefinedData *WasmSym::globalBase; 91 DefinedData *WasmSym::heapBase; 92 DefinedData *WasmSym::heapEnd; 93 DefinedData *WasmSym::initMemoryFlag; 94 GlobalSymbol *WasmSym::stackPointer; 95 DefinedData *WasmSym::stackLow; 96 DefinedData *WasmSym::stackHigh; 97 GlobalSymbol *WasmSym::tlsBase; 98 GlobalSymbol *WasmSym::tlsSize; 99 GlobalSymbol *WasmSym::tlsAlign; 100 UndefinedGlobal *WasmSym::tableBase; 101 DefinedData *WasmSym::definedTableBase; 102 UndefinedGlobal *WasmSym::memoryBase; 103 DefinedData *WasmSym::definedMemoryBase; 104 TableSymbol *WasmSym::indirectFunctionTable; 105 106 WasmSymbolType Symbol::getWasmType() const { 107 if (isa<FunctionSymbol>(this)) 108 return WASM_SYMBOL_TYPE_FUNCTION; 109 if (isa<DataSymbol>(this)) 110 return WASM_SYMBOL_TYPE_DATA; 111 if (isa<GlobalSymbol>(this)) 112 return WASM_SYMBOL_TYPE_GLOBAL; 113 if (isa<TagSymbol>(this)) 114 return WASM_SYMBOL_TYPE_TAG; 115 if (isa<TableSymbol>(this)) 116 return WASM_SYMBOL_TYPE_TABLE; 117 if (isa<SectionSymbol>(this) || isa<OutputSectionSymbol>(this)) 118 return WASM_SYMBOL_TYPE_SECTION; 119 llvm_unreachable("invalid symbol kind"); 120 } 121 122 const WasmSignature *Symbol::getSignature() const { 123 if (auto* f = dyn_cast<FunctionSymbol>(this)) 124 return f->signature; 125 if (auto *t = dyn_cast<TagSymbol>(this)) 126 return t->signature; 127 if (auto *l = dyn_cast<LazySymbol>(this)) 128 return l->signature; 129 return nullptr; 130 } 131 132 InputChunk *Symbol::getChunk() const { 133 if (auto *f = dyn_cast<DefinedFunction>(this)) 134 return f->function; 135 if (auto *f = dyn_cast<UndefinedFunction>(this)) 136 if (f->stubFunction) 137 return f->stubFunction->function; 138 if (auto *d = dyn_cast<DefinedData>(this)) 139 return d->segment; 140 return nullptr; 141 } 142 143 bool Symbol::isDiscarded() const { 144 if (InputChunk *c = getChunk()) 145 return c->discarded; 146 return false; 147 } 148 149 bool Symbol::isLive() const { 150 if (auto *g = dyn_cast<DefinedGlobal>(this)) 151 return g->global->live; 152 if (auto *t = dyn_cast<DefinedTag>(this)) 153 return t->tag->live; 154 if (auto *t = dyn_cast<DefinedTable>(this)) 155 return t->table->live; 156 if (InputChunk *c = getChunk()) 157 return c->live; 158 return referenced; 159 } 160 161 void Symbol::markLive() { 162 assert(!isDiscarded()); 163 referenced = true; 164 if (file != nullptr && isDefined()) 165 file->markLive(); 166 if (auto *g = dyn_cast<DefinedGlobal>(this)) 167 g->global->live = true; 168 if (auto *t = dyn_cast<DefinedTag>(this)) 169 t->tag->live = true; 170 if (auto *t = dyn_cast<DefinedTable>(this)) 171 t->table->live = true; 172 if (InputChunk *c = getChunk()) { 173 // Usually, a whole chunk is marked as live or dead, but in mergeable 174 // (splittable) sections, each piece of data has independent liveness bit. 175 // So we explicitly tell it which offset is in use. 176 if (auto *d = dyn_cast<DefinedData>(this)) { 177 if (auto *ms = dyn_cast<MergeInputChunk>(c)) { 178 ms->getSectionPiece(d->value)->live = true; 179 } 180 } 181 c->live = true; 182 } 183 } 184 185 uint32_t Symbol::getOutputSymbolIndex() const { 186 assert(outputSymbolIndex != INVALID_INDEX); 187 return outputSymbolIndex; 188 } 189 190 void Symbol::setOutputSymbolIndex(uint32_t index) { 191 LLVM_DEBUG(dbgs() << "setOutputSymbolIndex " << name << " -> " << index 192 << "\n"); 193 assert(outputSymbolIndex == INVALID_INDEX); 194 outputSymbolIndex = index; 195 } 196 197 void Symbol::setGOTIndex(uint32_t index) { 198 LLVM_DEBUG(dbgs() << "setGOTIndex " << name << " -> " << index << "\n"); 199 assert(gotIndex == INVALID_INDEX); 200 gotIndex = index; 201 } 202 203 bool Symbol::isWeak() const { 204 return (flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK; 205 } 206 207 bool Symbol::isLocal() const { 208 return (flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_LOCAL; 209 } 210 211 bool Symbol::isHidden() const { 212 return (flags & WASM_SYMBOL_VISIBILITY_MASK) == WASM_SYMBOL_VISIBILITY_HIDDEN; 213 } 214 215 bool Symbol::isTLS() const { return flags & WASM_SYMBOL_TLS; } 216 217 void Symbol::setHidden(bool isHidden) { 218 LLVM_DEBUG(dbgs() << "setHidden: " << name << " -> " << isHidden << "\n"); 219 flags &= ~WASM_SYMBOL_VISIBILITY_MASK; 220 if (isHidden) 221 flags |= WASM_SYMBOL_VISIBILITY_HIDDEN; 222 else 223 flags |= WASM_SYMBOL_VISIBILITY_DEFAULT; 224 } 225 226 bool Symbol::isImported() const { 227 return isShared() || 228 (isUndefined() && (importName.has_value() || forceImport)); 229 } 230 231 bool Symbol::isExported() const { 232 if (!isDefined() || isShared() || isLocal()) 233 return false; 234 235 // Shared libraries must export all weakly defined symbols 236 // in case they contain the version that will be chosen by 237 // the dynamic linker. 238 if (ctx.arg.shared && isLive() && isWeak() && !isHidden()) 239 return true; 240 241 if (ctx.arg.exportAll || (ctx.arg.exportDynamic && !isHidden())) 242 return true; 243 244 return isExportedExplicit(); 245 } 246 247 bool Symbol::isExportedExplicit() const { 248 return forceExport || flags & WASM_SYMBOL_EXPORTED; 249 } 250 251 bool Symbol::isNoStrip() const { 252 return flags & WASM_SYMBOL_NO_STRIP; 253 } 254 255 uint32_t FunctionSymbol::getFunctionIndex() const { 256 if (const auto *u = dyn_cast<UndefinedFunction>(this)) 257 if (u->stubFunction) 258 return u->stubFunction->getFunctionIndex(); 259 if (functionIndex != INVALID_INDEX) 260 return functionIndex; 261 auto *f = cast<DefinedFunction>(this); 262 return f->function->getFunctionIndex(); 263 } 264 265 void FunctionSymbol::setFunctionIndex(uint32_t index) { 266 LLVM_DEBUG(dbgs() << "setFunctionIndex " << name << " -> " << index << "\n"); 267 assert(functionIndex == INVALID_INDEX); 268 functionIndex = index; 269 } 270 271 bool FunctionSymbol::hasFunctionIndex() const { 272 if (auto *f = dyn_cast<DefinedFunction>(this)) 273 return f->function->hasFunctionIndex(); 274 return functionIndex != INVALID_INDEX; 275 } 276 277 uint32_t FunctionSymbol::getTableIndex() const { 278 if (auto *f = dyn_cast<DefinedFunction>(this)) 279 return f->function->getTableIndex(); 280 assert(tableIndex != INVALID_INDEX); 281 return tableIndex; 282 } 283 284 bool FunctionSymbol::hasTableIndex() const { 285 if (auto *f = dyn_cast<DefinedFunction>(this)) 286 return f->function->hasTableIndex(); 287 return tableIndex != INVALID_INDEX; 288 } 289 290 void FunctionSymbol::setTableIndex(uint32_t index) { 291 // For imports, we set the table index here on the Symbol; for defined 292 // functions we set the index on the InputFunction so that we don't export 293 // the same thing twice (keeps the table size down). 294 if (auto *f = dyn_cast<DefinedFunction>(this)) { 295 f->function->setTableIndex(index); 296 return; 297 } 298 LLVM_DEBUG(dbgs() << "setTableIndex " << name << " -> " << index << "\n"); 299 assert(tableIndex == INVALID_INDEX); 300 tableIndex = index; 301 } 302 303 DefinedFunction::DefinedFunction(StringRef name, uint32_t flags, InputFile *f, 304 InputFunction *function) 305 : FunctionSymbol(name, DefinedFunctionKind, flags, f, 306 function ? &function->signature : nullptr), 307 function(function) {} 308 309 uint32_t DefinedFunction::getExportedFunctionIndex() const { 310 return function->getFunctionIndex(); 311 } 312 313 uint64_t DefinedData::getVA(bool absolute) const { 314 LLVM_DEBUG(dbgs() << "getVA: " << getName() << "\n"); 315 // TLS symbols (by default) are relative to the start of the TLS output 316 // segment (__tls_base). 317 if (isTLS() && !absolute) 318 return getOutputSegmentOffset(); 319 if (segment) 320 return segment->getVA(value); 321 return value; 322 } 323 324 void DefinedData::setVA(uint64_t value_) { 325 LLVM_DEBUG(dbgs() << "setVA " << name << " -> " << value_ << "\n"); 326 assert(!segment); 327 value = value_; 328 } 329 330 uint64_t DefinedData::getOutputSegmentOffset() const { 331 LLVM_DEBUG(dbgs() << "getOutputSegmentOffset: " << getName() << "\n"); 332 return segment->getChunkOffset(value); 333 } 334 335 uint64_t DefinedData::getOutputSegmentIndex() const { 336 LLVM_DEBUG(dbgs() << "getOutputSegmentIndex: " << getName() << "\n"); 337 return segment->outputSeg->index; 338 } 339 340 uint32_t GlobalSymbol::getGlobalIndex() const { 341 if (auto *f = dyn_cast<DefinedGlobal>(this)) 342 return f->global->getAssignedIndex(); 343 assert(globalIndex != INVALID_INDEX); 344 return globalIndex; 345 } 346 347 void GlobalSymbol::setGlobalIndex(uint32_t index) { 348 LLVM_DEBUG(dbgs() << "setGlobalIndex " << name << " -> " << index << "\n"); 349 assert(globalIndex == INVALID_INDEX); 350 globalIndex = index; 351 } 352 353 bool GlobalSymbol::hasGlobalIndex() const { 354 if (auto *f = dyn_cast<DefinedGlobal>(this)) 355 return f->global->hasAssignedIndex(); 356 return globalIndex != INVALID_INDEX; 357 } 358 359 DefinedGlobal::DefinedGlobal(StringRef name, uint32_t flags, InputFile *file, 360 InputGlobal *global) 361 : GlobalSymbol(name, DefinedGlobalKind, flags, file, 362 global ? &global->getType() : nullptr), 363 global(global) {} 364 365 uint32_t TagSymbol::getTagIndex() const { 366 if (auto *f = dyn_cast<DefinedTag>(this)) 367 return f->tag->getAssignedIndex(); 368 assert(tagIndex != INVALID_INDEX); 369 return tagIndex; 370 } 371 372 void TagSymbol::setTagIndex(uint32_t index) { 373 LLVM_DEBUG(dbgs() << "setTagIndex " << name << " -> " << index << "\n"); 374 assert(tagIndex == INVALID_INDEX); 375 tagIndex = index; 376 } 377 378 bool TagSymbol::hasTagIndex() const { 379 if (auto *f = dyn_cast<DefinedTag>(this)) 380 return f->tag->hasAssignedIndex(); 381 return tagIndex != INVALID_INDEX; 382 } 383 384 DefinedTag::DefinedTag(StringRef name, uint32_t flags, InputFile *file, 385 InputTag *tag) 386 : TagSymbol(name, DefinedTagKind, flags, file, 387 tag ? &tag->signature : nullptr), 388 tag(tag) {} 389 390 void TableSymbol::setLimits(const WasmLimits &limits) { 391 if (auto *t = dyn_cast<DefinedTable>(this)) 392 t->table->setLimits(limits); 393 auto *newType = make<WasmTableType>(*tableType); 394 newType->Limits = limits; 395 tableType = newType; 396 } 397 398 uint32_t TableSymbol::getTableNumber() const { 399 if (const auto *t = dyn_cast<DefinedTable>(this)) 400 return t->table->getAssignedIndex(); 401 assert(tableNumber != INVALID_INDEX); 402 return tableNumber; 403 } 404 405 void TableSymbol::setTableNumber(uint32_t number) { 406 if (const auto *t = dyn_cast<DefinedTable>(this)) 407 return t->table->assignIndex(number); 408 LLVM_DEBUG(dbgs() << "setTableNumber " << name << " -> " << number << "\n"); 409 assert(tableNumber == INVALID_INDEX); 410 tableNumber = number; 411 } 412 413 bool TableSymbol::hasTableNumber() const { 414 if (const auto *t = dyn_cast<DefinedTable>(this)) 415 return t->table->hasAssignedIndex(); 416 return tableNumber != INVALID_INDEX; 417 } 418 419 DefinedTable::DefinedTable(StringRef name, uint32_t flags, InputFile *file, 420 InputTable *table) 421 : TableSymbol(name, DefinedTableKind, flags, file, 422 table ? &table->getType() : nullptr), 423 table(table) {} 424 425 const OutputSectionSymbol *SectionSymbol::getOutputSectionSymbol() const { 426 assert(section->outputSec && section->outputSec->sectionSym); 427 return section->outputSec->sectionSym; 428 } 429 430 void LazySymbol::extract() { 431 if (file->lazy) { 432 file->lazy = false; 433 symtab->addFile(file, name); 434 } 435 } 436 437 void LazySymbol::setWeak() { 438 flags |= (flags & ~WASM_SYMBOL_BINDING_MASK) | WASM_SYMBOL_BINDING_WEAK; 439 } 440 441 void printTraceSymbolUndefined(StringRef name, const InputFile* file) { 442 message(toString(file) + ": reference to " + name); 443 } 444 445 // Print out a log message for --trace-symbol. 446 void printTraceSymbol(Symbol *sym) { 447 // Undefined symbols are traced via printTraceSymbolUndefined 448 if (sym->isUndefined()) 449 return; 450 451 std::string s; 452 if (sym->isLazy()) 453 s = ": lazy definition of "; 454 else 455 s = ": definition of "; 456 457 message(toString(sym->getFile()) + s + sym->getName()); 458 } 459 460 const char *defaultModule = "env"; 461 const char *functionTableName = "__indirect_function_table"; 462 const char *memoryName = "memory"; 463 464 } // namespace wasm 465 } // namespace lld 466