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