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