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 "InputEvent.h" 13 #include "InputFiles.h" 14 #include "InputGlobal.h" 15 #include "OutputSections.h" 16 #include "OutputSegment.h" 17 #include "lld/Common/ErrorHandler.h" 18 #include "lld/Common/Strings.h" 19 20 #define DEBUG_TYPE "lld" 21 22 using namespace llvm; 23 using namespace llvm::wasm; 24 25 namespace lld { 26 std::string toString(const wasm::Symbol &sym) { 27 return maybeDemangleSymbol(sym.getName()); 28 } 29 30 std::string maybeDemangleSymbol(StringRef name) { 31 if (wasm::config->demangle) 32 return demangleItanium(name); 33 return name; 34 } 35 36 std::string toString(wasm::Symbol::Kind kind) { 37 switch (kind) { 38 case wasm::Symbol::DefinedFunctionKind: 39 return "DefinedFunction"; 40 case wasm::Symbol::DefinedDataKind: 41 return "DefinedData"; 42 case wasm::Symbol::DefinedGlobalKind: 43 return "DefinedGlobal"; 44 case wasm::Symbol::DefinedEventKind: 45 return "DefinedEvent"; 46 case wasm::Symbol::UndefinedFunctionKind: 47 return "UndefinedFunction"; 48 case wasm::Symbol::UndefinedDataKind: 49 return "UndefinedData"; 50 case wasm::Symbol::UndefinedGlobalKind: 51 return "UndefinedGlobal"; 52 case wasm::Symbol::LazyKind: 53 return "LazyKind"; 54 case wasm::Symbol::SectionKind: 55 return "SectionKind"; 56 case wasm::Symbol::OutputSectionKind: 57 return "OutputSectionKind"; 58 } 59 llvm_unreachable("invalid symbol kind"); 60 } 61 62 namespace wasm { 63 DefinedFunction *WasmSym::callCtors; 64 DefinedFunction *WasmSym::initMemory; 65 DefinedFunction *WasmSym::applyRelocs; 66 DefinedFunction *WasmSym::initTLS; 67 DefinedData *WasmSym::dsoHandle; 68 DefinedData *WasmSym::dataEnd; 69 DefinedData *WasmSym::globalBase; 70 DefinedData *WasmSym::heapBase; 71 DefinedData *WasmSym::initMemoryFlag; 72 GlobalSymbol *WasmSym::stackPointer; 73 GlobalSymbol *WasmSym::tlsBase; 74 GlobalSymbol *WasmSym::tlsSize; 75 GlobalSymbol *WasmSym::tlsAlign; 76 UndefinedGlobal *WasmSym::tableBase; 77 DefinedData *WasmSym::definedTableBase; 78 UndefinedGlobal *WasmSym::memoryBase; 79 DefinedData *WasmSym::definedMemoryBase; 80 81 WasmSymbolType Symbol::getWasmType() const { 82 if (isa<FunctionSymbol>(this)) 83 return WASM_SYMBOL_TYPE_FUNCTION; 84 if (isa<DataSymbol>(this)) 85 return WASM_SYMBOL_TYPE_DATA; 86 if (isa<GlobalSymbol>(this)) 87 return WASM_SYMBOL_TYPE_GLOBAL; 88 if (isa<EventSymbol>(this)) 89 return WASM_SYMBOL_TYPE_EVENT; 90 if (isa<SectionSymbol>(this) || isa<OutputSectionSymbol>(this)) 91 return WASM_SYMBOL_TYPE_SECTION; 92 llvm_unreachable("invalid symbol kind"); 93 } 94 95 const WasmSignature *Symbol::getSignature() const { 96 if (auto* f = dyn_cast<FunctionSymbol>(this)) 97 return f->signature; 98 if (auto *l = dyn_cast<LazySymbol>(this)) 99 return l->signature; 100 return nullptr; 101 } 102 103 InputChunk *Symbol::getChunk() const { 104 if (auto *f = dyn_cast<DefinedFunction>(this)) 105 return f->function; 106 if (auto *d = dyn_cast<DefinedData>(this)) 107 return d->segment; 108 return nullptr; 109 } 110 111 bool Symbol::isDiscarded() const { 112 if (InputChunk *c = getChunk()) 113 return c->discarded; 114 return false; 115 } 116 117 bool Symbol::isLive() const { 118 if (auto *g = dyn_cast<DefinedGlobal>(this)) 119 return g->global->live; 120 if (auto *e = dyn_cast<DefinedEvent>(this)) 121 return e->event->live; 122 if (InputChunk *c = getChunk()) 123 return c->live; 124 return referenced; 125 } 126 127 void Symbol::markLive() { 128 assert(!isDiscarded()); 129 if (auto *g = dyn_cast<DefinedGlobal>(this)) 130 g->global->live = true; 131 if (auto *e = dyn_cast<DefinedEvent>(this)) 132 e->event->live = true; 133 if (InputChunk *c = getChunk()) 134 c->live = true; 135 referenced = true; 136 } 137 138 uint32_t Symbol::getOutputSymbolIndex() const { 139 assert(outputSymbolIndex != INVALID_INDEX); 140 return outputSymbolIndex; 141 } 142 143 void Symbol::setOutputSymbolIndex(uint32_t index) { 144 LLVM_DEBUG(dbgs() << "setOutputSymbolIndex " << name << " -> " << index 145 << "\n"); 146 assert(outputSymbolIndex == INVALID_INDEX); 147 outputSymbolIndex = index; 148 } 149 150 void Symbol::setGOTIndex(uint32_t index) { 151 LLVM_DEBUG(dbgs() << "setGOTIndex " << name << " -> " << index << "\n"); 152 assert(gotIndex == INVALID_INDEX); 153 if (config->isPic) { 154 // Any symbol that is assigned a GOT entry must be exported othewise the 155 // dynamic linker won't be able create the entry that contains it. 156 forceExport = true; 157 } 158 gotIndex = index; 159 } 160 161 bool Symbol::isWeak() const { 162 return (flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK; 163 } 164 165 bool Symbol::isLocal() const { 166 return (flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_LOCAL; 167 } 168 169 bool Symbol::isHidden() const { 170 return (flags & WASM_SYMBOL_VISIBILITY_MASK) == WASM_SYMBOL_VISIBILITY_HIDDEN; 171 } 172 173 void Symbol::setHidden(bool isHidden) { 174 LLVM_DEBUG(dbgs() << "setHidden: " << name << " -> " << isHidden << "\n"); 175 flags &= ~WASM_SYMBOL_VISIBILITY_MASK; 176 if (isHidden) 177 flags |= WASM_SYMBOL_VISIBILITY_HIDDEN; 178 else 179 flags |= WASM_SYMBOL_VISIBILITY_DEFAULT; 180 } 181 182 bool Symbol::isExported() const { 183 if (!isDefined() || isLocal()) 184 return false; 185 186 if (forceExport || config->exportAll) 187 return true; 188 189 if (config->exportDynamic && !isHidden()) 190 return true; 191 192 return flags & WASM_SYMBOL_EXPORTED; 193 } 194 195 bool Symbol::isNoStrip() const { 196 return flags & WASM_SYMBOL_NO_STRIP; 197 } 198 199 uint32_t FunctionSymbol::getFunctionIndex() const { 200 if (auto *f = dyn_cast<DefinedFunction>(this)) 201 return f->function->getFunctionIndex(); 202 assert(functionIndex != INVALID_INDEX); 203 return functionIndex; 204 } 205 206 void FunctionSymbol::setFunctionIndex(uint32_t index) { 207 LLVM_DEBUG(dbgs() << "setFunctionIndex " << name << " -> " << index << "\n"); 208 assert(functionIndex == INVALID_INDEX); 209 functionIndex = index; 210 } 211 212 bool FunctionSymbol::hasFunctionIndex() const { 213 if (auto *f = dyn_cast<DefinedFunction>(this)) 214 return f->function->hasFunctionIndex(); 215 return functionIndex != INVALID_INDEX; 216 } 217 218 uint32_t FunctionSymbol::getTableIndex() const { 219 if (auto *f = dyn_cast<DefinedFunction>(this)) 220 return f->function->getTableIndex(); 221 assert(tableIndex != INVALID_INDEX); 222 return tableIndex; 223 } 224 225 bool FunctionSymbol::hasTableIndex() const { 226 if (auto *f = dyn_cast<DefinedFunction>(this)) 227 return f->function->hasTableIndex(); 228 return tableIndex != INVALID_INDEX; 229 } 230 231 void FunctionSymbol::setTableIndex(uint32_t index) { 232 // For imports, we set the table index here on the Symbol; for defined 233 // functions we set the index on the InputFunction so that we don't export 234 // the same thing twice (keeps the table size down). 235 if (auto *f = dyn_cast<DefinedFunction>(this)) { 236 f->function->setTableIndex(index); 237 return; 238 } 239 LLVM_DEBUG(dbgs() << "setTableIndex " << name << " -> " << index << "\n"); 240 assert(tableIndex == INVALID_INDEX); 241 tableIndex = index; 242 } 243 244 DefinedFunction::DefinedFunction(StringRef name, uint32_t flags, InputFile *f, 245 InputFunction *function) 246 : FunctionSymbol(name, DefinedFunctionKind, flags, f, 247 function ? &function->signature : nullptr), 248 function(function) {} 249 250 uint32_t DefinedData::getVirtualAddress() const { 251 LLVM_DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n"); 252 if (segment) { 253 // For thread local data, the symbol location is relative to the start of 254 // the .tdata section, since they are used as offsets from __tls_base. 255 // Hence, we do not add in segment->outputSeg->startVA. 256 if (segment->outputSeg->name == ".tdata") 257 return segment->outputSegmentOffset + offset; 258 return segment->outputSeg->startVA + segment->outputSegmentOffset + offset; 259 } 260 return offset; 261 } 262 263 void DefinedData::setVirtualAddress(uint32_t value) { 264 LLVM_DEBUG(dbgs() << "setVirtualAddress " << name << " -> " << value << "\n"); 265 assert(!segment); 266 offset = value; 267 } 268 269 uint32_t DefinedData::getOutputSegmentOffset() const { 270 LLVM_DEBUG(dbgs() << "getOutputSegmentOffset: " << getName() << "\n"); 271 return segment->outputSegmentOffset + offset; 272 } 273 274 uint32_t DefinedData::getOutputSegmentIndex() const { 275 LLVM_DEBUG(dbgs() << "getOutputSegmentIndex: " << getName() << "\n"); 276 return segment->outputSeg->index; 277 } 278 279 uint32_t GlobalSymbol::getGlobalIndex() const { 280 if (auto *f = dyn_cast<DefinedGlobal>(this)) 281 return f->global->getGlobalIndex(); 282 assert(globalIndex != INVALID_INDEX); 283 return globalIndex; 284 } 285 286 void GlobalSymbol::setGlobalIndex(uint32_t index) { 287 LLVM_DEBUG(dbgs() << "setGlobalIndex " << name << " -> " << index << "\n"); 288 assert(globalIndex == INVALID_INDEX); 289 globalIndex = index; 290 } 291 292 bool GlobalSymbol::hasGlobalIndex() const { 293 if (auto *f = dyn_cast<DefinedGlobal>(this)) 294 return f->global->hasGlobalIndex(); 295 return globalIndex != INVALID_INDEX; 296 } 297 298 DefinedGlobal::DefinedGlobal(StringRef name, uint32_t flags, InputFile *file, 299 InputGlobal *global) 300 : GlobalSymbol(name, DefinedGlobalKind, flags, file, 301 global ? &global->getType() : nullptr), 302 global(global) {} 303 304 uint32_t EventSymbol::getEventIndex() const { 305 if (auto *f = dyn_cast<DefinedEvent>(this)) 306 return f->event->getEventIndex(); 307 assert(eventIndex != INVALID_INDEX); 308 return eventIndex; 309 } 310 311 void EventSymbol::setEventIndex(uint32_t index) { 312 LLVM_DEBUG(dbgs() << "setEventIndex " << name << " -> " << index << "\n"); 313 assert(eventIndex == INVALID_INDEX); 314 eventIndex = index; 315 } 316 317 bool EventSymbol::hasEventIndex() const { 318 if (auto *f = dyn_cast<DefinedEvent>(this)) 319 return f->event->hasEventIndex(); 320 return eventIndex != INVALID_INDEX; 321 } 322 323 DefinedEvent::DefinedEvent(StringRef name, uint32_t flags, InputFile *file, 324 InputEvent *event) 325 : EventSymbol(name, DefinedEventKind, flags, file, 326 event ? &event->getType() : nullptr, 327 event ? &event->signature : nullptr), 328 event(event) {} 329 330 const OutputSectionSymbol *SectionSymbol::getOutputSectionSymbol() const { 331 assert(section->outputSec && section->outputSec->sectionSym); 332 return section->outputSec->sectionSym; 333 } 334 335 void LazySymbol::fetch() { cast<ArchiveFile>(file)->addMember(&archiveSymbol); } 336 337 void printTraceSymbolUndefined(StringRef name, const InputFile* file) { 338 message(toString(file) + ": reference to " + name); 339 } 340 341 // Print out a log message for --trace-symbol. 342 void printTraceSymbol(Symbol *sym) { 343 // Undefined symbols are traced via printTraceSymbolUndefined 344 if (sym->isUndefined()) 345 return; 346 347 std::string s; 348 if (sym->isLazy()) 349 s = ": lazy definition of "; 350 else 351 s = ": definition of "; 352 353 message(toString(sym->getFile()) + s + sym->getName()); 354 } 355 356 const char *defaultModule = "env"; 357 const char *functionTableName = "__indirect_function_table"; 358 359 } // namespace wasm 360 } // namespace lld 361