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 gotIndex = index; 194 } 195 196 bool Symbol::isWeak() const { 197 return (flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK; 198 } 199 200 bool Symbol::isLocal() const { 201 return (flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_LOCAL; 202 } 203 204 bool Symbol::isHidden() const { 205 return (flags & WASM_SYMBOL_VISIBILITY_MASK) == WASM_SYMBOL_VISIBILITY_HIDDEN; 206 } 207 208 bool Symbol::isTLS() const { return flags & WASM_SYMBOL_TLS; } 209 210 void Symbol::setHidden(bool isHidden) { 211 LLVM_DEBUG(dbgs() << "setHidden: " << name << " -> " << isHidden << "\n"); 212 flags &= ~WASM_SYMBOL_VISIBILITY_MASK; 213 if (isHidden) 214 flags |= WASM_SYMBOL_VISIBILITY_HIDDEN; 215 else 216 flags |= WASM_SYMBOL_VISIBILITY_DEFAULT; 217 } 218 219 bool Symbol::isExported() const { 220 if (!isDefined() || isLocal()) 221 return false; 222 223 // Shared libraries must export all weakly defined symbols 224 // in case they contain the version that will be chosen by 225 // the dynamic linker. 226 if (config->shared && isLive() && isWeak() && !isHidden()) 227 return true; 228 229 if (config->exportAll || (config->exportDynamic && !isHidden())) 230 return true; 231 232 return isExportedExplicit(); 233 } 234 235 bool Symbol::isExportedExplicit() const { 236 return forceExport || flags & WASM_SYMBOL_EXPORTED; 237 } 238 239 bool Symbol::isNoStrip() const { 240 return flags & WASM_SYMBOL_NO_STRIP; 241 } 242 243 uint32_t FunctionSymbol::getFunctionIndex() const { 244 if (const auto *u = dyn_cast<UndefinedFunction>(this)) 245 if (u->stubFunction) 246 return u->stubFunction->getFunctionIndex(); 247 if (functionIndex != INVALID_INDEX) 248 return functionIndex; 249 auto *f = cast<DefinedFunction>(this); 250 return f->function->getFunctionIndex(); 251 } 252 253 void FunctionSymbol::setFunctionIndex(uint32_t index) { 254 LLVM_DEBUG(dbgs() << "setFunctionIndex " << name << " -> " << index << "\n"); 255 assert(functionIndex == INVALID_INDEX); 256 functionIndex = index; 257 } 258 259 bool FunctionSymbol::hasFunctionIndex() const { 260 if (auto *f = dyn_cast<DefinedFunction>(this)) 261 return f->function->hasFunctionIndex(); 262 return functionIndex != INVALID_INDEX; 263 } 264 265 uint32_t FunctionSymbol::getTableIndex() const { 266 if (auto *f = dyn_cast<DefinedFunction>(this)) 267 return f->function->getTableIndex(); 268 assert(tableIndex != INVALID_INDEX); 269 return tableIndex; 270 } 271 272 bool FunctionSymbol::hasTableIndex() const { 273 if (auto *f = dyn_cast<DefinedFunction>(this)) 274 return f->function->hasTableIndex(); 275 return tableIndex != INVALID_INDEX; 276 } 277 278 void FunctionSymbol::setTableIndex(uint32_t index) { 279 // For imports, we set the table index here on the Symbol; for defined 280 // functions we set the index on the InputFunction so that we don't export 281 // the same thing twice (keeps the table size down). 282 if (auto *f = dyn_cast<DefinedFunction>(this)) { 283 f->function->setTableIndex(index); 284 return; 285 } 286 LLVM_DEBUG(dbgs() << "setTableIndex " << name << " -> " << index << "\n"); 287 assert(tableIndex == INVALID_INDEX); 288 tableIndex = index; 289 } 290 291 DefinedFunction::DefinedFunction(StringRef name, uint32_t flags, InputFile *f, 292 InputFunction *function) 293 : FunctionSymbol(name, DefinedFunctionKind, flags, f, 294 function ? &function->signature : nullptr), 295 function(function) {} 296 297 uint32_t DefinedFunction::getExportedFunctionIndex() const { 298 return function->getFunctionIndex(); 299 } 300 301 uint64_t DefinedData::getVA() const { 302 LLVM_DEBUG(dbgs() << "getVA: " << getName() << "\n"); 303 // In the shared memory case, TLS symbols are relative to the start of the TLS 304 // output segment (__tls_base). When building without shared memory, TLS 305 // symbols absolute, just like non-TLS. 306 if (isTLS() && config->sharedMemory) 307 return getOutputSegmentOffset() + value; 308 if (segment) 309 return segment->getVA(value); 310 return value; 311 } 312 313 void DefinedData::setVA(uint64_t value_) { 314 LLVM_DEBUG(dbgs() << "setVA " << name << " -> " << value_ << "\n"); 315 assert(!segment); 316 value = value_; 317 } 318 319 uint64_t DefinedData::getOutputSegmentOffset() const { 320 LLVM_DEBUG(dbgs() << "getOutputSegmentOffset: " << getName() << "\n"); 321 return segment->getChunkOffset(value); 322 } 323 324 uint64_t DefinedData::getOutputSegmentIndex() const { 325 LLVM_DEBUG(dbgs() << "getOutputSegmentIndex: " << getName() << "\n"); 326 return segment->outputSeg->index; 327 } 328 329 uint32_t GlobalSymbol::getGlobalIndex() const { 330 if (auto *f = dyn_cast<DefinedGlobal>(this)) 331 return f->global->getAssignedIndex(); 332 assert(globalIndex != INVALID_INDEX); 333 return globalIndex; 334 } 335 336 void GlobalSymbol::setGlobalIndex(uint32_t index) { 337 LLVM_DEBUG(dbgs() << "setGlobalIndex " << name << " -> " << index << "\n"); 338 assert(globalIndex == INVALID_INDEX); 339 globalIndex = index; 340 } 341 342 bool GlobalSymbol::hasGlobalIndex() const { 343 if (auto *f = dyn_cast<DefinedGlobal>(this)) 344 return f->global->hasAssignedIndex(); 345 return globalIndex != INVALID_INDEX; 346 } 347 348 DefinedGlobal::DefinedGlobal(StringRef name, uint32_t flags, InputFile *file, 349 InputGlobal *global) 350 : GlobalSymbol(name, DefinedGlobalKind, flags, file, 351 global ? &global->getType() : nullptr), 352 global(global) {} 353 354 uint32_t TagSymbol::getTagIndex() const { 355 if (auto *f = dyn_cast<DefinedTag>(this)) 356 return f->tag->getAssignedIndex(); 357 assert(tagIndex != INVALID_INDEX); 358 return tagIndex; 359 } 360 361 void TagSymbol::setTagIndex(uint32_t index) { 362 LLVM_DEBUG(dbgs() << "setTagIndex " << name << " -> " << index << "\n"); 363 assert(tagIndex == INVALID_INDEX); 364 tagIndex = index; 365 } 366 367 bool TagSymbol::hasTagIndex() const { 368 if (auto *f = dyn_cast<DefinedTag>(this)) 369 return f->tag->hasAssignedIndex(); 370 return tagIndex != INVALID_INDEX; 371 } 372 373 DefinedTag::DefinedTag(StringRef name, uint32_t flags, InputFile *file, 374 InputTag *tag) 375 : TagSymbol(name, DefinedTagKind, flags, file, 376 tag ? &tag->signature : nullptr), 377 tag(tag) {} 378 379 void TableSymbol::setLimits(const WasmLimits &limits) { 380 if (auto *t = dyn_cast<DefinedTable>(this)) 381 t->table->setLimits(limits); 382 auto *newType = make<WasmTableType>(*tableType); 383 newType->Limits = limits; 384 tableType = newType; 385 } 386 387 uint32_t TableSymbol::getTableNumber() const { 388 if (const auto *t = dyn_cast<DefinedTable>(this)) 389 return t->table->getAssignedIndex(); 390 assert(tableNumber != INVALID_INDEX); 391 return tableNumber; 392 } 393 394 void TableSymbol::setTableNumber(uint32_t number) { 395 if (const auto *t = dyn_cast<DefinedTable>(this)) 396 return t->table->assignIndex(number); 397 LLVM_DEBUG(dbgs() << "setTableNumber " << name << " -> " << number << "\n"); 398 assert(tableNumber == INVALID_INDEX); 399 tableNumber = number; 400 } 401 402 bool TableSymbol::hasTableNumber() const { 403 if (const auto *t = dyn_cast<DefinedTable>(this)) 404 return t->table->hasAssignedIndex(); 405 return tableNumber != INVALID_INDEX; 406 } 407 408 DefinedTable::DefinedTable(StringRef name, uint32_t flags, InputFile *file, 409 InputTable *table) 410 : TableSymbol(name, DefinedTableKind, flags, file, 411 table ? &table->getType() : nullptr), 412 table(table) {} 413 414 const OutputSectionSymbol *SectionSymbol::getOutputSectionSymbol() const { 415 assert(section->outputSec && section->outputSec->sectionSym); 416 return section->outputSec->sectionSym; 417 } 418 419 void LazySymbol::fetch() { cast<ArchiveFile>(file)->addMember(&archiveSymbol); } 420 421 void LazySymbol::setWeak() { 422 flags |= (flags & ~WASM_SYMBOL_BINDING_MASK) | WASM_SYMBOL_BINDING_WEAK; 423 } 424 425 MemoryBufferRef LazySymbol::getMemberBuffer() { 426 Archive::Child c = 427 CHECK(archiveSymbol.getMember(), 428 "could not get the member for symbol " + toString(*this)); 429 430 return CHECK(c.getMemoryBufferRef(), 431 "could not get the buffer for the member defining symbol " + 432 toString(*this)); 433 } 434 435 void printTraceSymbolUndefined(StringRef name, const InputFile* file) { 436 message(toString(file) + ": reference to " + name); 437 } 438 439 // Print out a log message for --trace-symbol. 440 void printTraceSymbol(Symbol *sym) { 441 // Undefined symbols are traced via printTraceSymbolUndefined 442 if (sym->isUndefined()) 443 return; 444 445 std::string s; 446 if (sym->isLazy()) 447 s = ": lazy definition of "; 448 else 449 s = ": definition of "; 450 451 message(toString(sym->getFile()) + s + sym->getName()); 452 } 453 454 const char *defaultModule = "env"; 455 const char *functionTableName = "__indirect_function_table"; 456 457 } // namespace wasm 458 } // namespace lld 459