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