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