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 using namespace lld; 25 using namespace lld::wasm; 26 27 DefinedFunction *WasmSym::CallCtors; 28 DefinedFunction *WasmSym::ApplyRelocs; 29 DefinedData *WasmSym::DsoHandle; 30 DefinedData *WasmSym::DataEnd; 31 DefinedData *WasmSym::HeapBase; 32 GlobalSymbol *WasmSym::StackPointer; 33 UndefinedGlobal *WasmSym::TableBase; 34 UndefinedGlobal *WasmSym::MemoryBase; 35 36 WasmSymbolType Symbol::getWasmType() const { 37 if (isa<FunctionSymbol>(this)) 38 return WASM_SYMBOL_TYPE_FUNCTION; 39 if (isa<DataSymbol>(this)) 40 return WASM_SYMBOL_TYPE_DATA; 41 if (isa<GlobalSymbol>(this)) 42 return WASM_SYMBOL_TYPE_GLOBAL; 43 if (isa<EventSymbol>(this)) 44 return WASM_SYMBOL_TYPE_EVENT; 45 if (isa<SectionSymbol>(this) || isa<OutputSectionSymbol>(this)) 46 return WASM_SYMBOL_TYPE_SECTION; 47 llvm_unreachable("invalid symbol kind"); 48 } 49 50 const WasmSignature *Symbol::getSignature() const { 51 if (auto* F = dyn_cast<FunctionSymbol>(this)) 52 return F->Signature; 53 if (auto *L = dyn_cast<LazySymbol>(this)) 54 return L->Signature; 55 return nullptr; 56 } 57 58 InputChunk *Symbol::getChunk() const { 59 if (auto *F = dyn_cast<DefinedFunction>(this)) 60 return F->Function; 61 if (auto *D = dyn_cast<DefinedData>(this)) 62 return D->Segment; 63 return nullptr; 64 } 65 66 bool Symbol::isDiscarded() const { 67 if (InputChunk *C = getChunk()) 68 return C->Discarded; 69 return false; 70 } 71 72 bool Symbol::isLive() const { 73 if (auto *G = dyn_cast<DefinedGlobal>(this)) 74 return G->Global->Live; 75 if (auto *E = dyn_cast<DefinedEvent>(this)) 76 return E->Event->Live; 77 if (InputChunk *C = getChunk()) 78 return C->Live; 79 return Referenced; 80 } 81 82 void Symbol::markLive() { 83 assert(!isDiscarded()); 84 if (auto *G = dyn_cast<DefinedGlobal>(this)) 85 G->Global->Live = true; 86 if (auto *E = dyn_cast<DefinedEvent>(this)) 87 E->Event->Live = true; 88 if (InputChunk *C = getChunk()) 89 C->Live = true; 90 Referenced = true; 91 } 92 93 uint32_t Symbol::getOutputSymbolIndex() const { 94 assert(OutputSymbolIndex != INVALID_INDEX); 95 return OutputSymbolIndex; 96 } 97 98 void Symbol::setOutputSymbolIndex(uint32_t Index) { 99 LLVM_DEBUG(dbgs() << "setOutputSymbolIndex " << Name << " -> " << Index 100 << "\n"); 101 assert(OutputSymbolIndex == INVALID_INDEX); 102 OutputSymbolIndex = Index; 103 } 104 105 void Symbol::setGOTIndex(uint32_t Index) { 106 LLVM_DEBUG(dbgs() << "setGOTIndex " << Name << " -> " << Index << "\n"); 107 assert(GOTIndex == INVALID_INDEX); 108 // Any symbol that is assigned a GOT entry must be exported othewise the 109 // dynamic linker won't be able create the entry that contains it. 110 ForceExport = true; 111 GOTIndex = Index; 112 } 113 114 bool Symbol::isWeak() const { 115 return (Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK; 116 } 117 118 bool Symbol::isLocal() const { 119 return (Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_LOCAL; 120 } 121 122 bool Symbol::isHidden() const { 123 return (Flags & WASM_SYMBOL_VISIBILITY_MASK) == WASM_SYMBOL_VISIBILITY_HIDDEN; 124 } 125 126 void Symbol::setHidden(bool IsHidden) { 127 LLVM_DEBUG(dbgs() << "setHidden: " << Name << " -> " << IsHidden << "\n"); 128 Flags &= ~WASM_SYMBOL_VISIBILITY_MASK; 129 if (IsHidden) 130 Flags |= WASM_SYMBOL_VISIBILITY_HIDDEN; 131 else 132 Flags |= WASM_SYMBOL_VISIBILITY_DEFAULT; 133 } 134 135 bool Symbol::isExported() const { 136 if (!isDefined() || isLocal()) 137 return false; 138 139 if (ForceExport || Config->ExportAll) 140 return true; 141 142 if (Config->ExportDynamic && !isHidden()) 143 return true; 144 145 return Flags & WASM_SYMBOL_EXPORTED; 146 } 147 148 uint32_t FunctionSymbol::getFunctionIndex() const { 149 if (auto *F = dyn_cast<DefinedFunction>(this)) 150 return F->Function->getFunctionIndex(); 151 assert(FunctionIndex != INVALID_INDEX); 152 return FunctionIndex; 153 } 154 155 void FunctionSymbol::setFunctionIndex(uint32_t Index) { 156 LLVM_DEBUG(dbgs() << "setFunctionIndex " << Name << " -> " << Index << "\n"); 157 assert(FunctionIndex == INVALID_INDEX); 158 FunctionIndex = Index; 159 } 160 161 bool FunctionSymbol::hasFunctionIndex() const { 162 if (auto *F = dyn_cast<DefinedFunction>(this)) 163 return F->Function->hasFunctionIndex(); 164 return FunctionIndex != INVALID_INDEX; 165 } 166 167 uint32_t FunctionSymbol::getTableIndex() const { 168 if (auto *F = dyn_cast<DefinedFunction>(this)) 169 return F->Function->getTableIndex(); 170 assert(TableIndex != INVALID_INDEX); 171 return TableIndex; 172 } 173 174 bool FunctionSymbol::hasTableIndex() const { 175 if (auto *F = dyn_cast<DefinedFunction>(this)) 176 return F->Function->hasTableIndex(); 177 return TableIndex != INVALID_INDEX; 178 } 179 180 void FunctionSymbol::setTableIndex(uint32_t Index) { 181 // For imports, we set the table index here on the Symbol; for defined 182 // functions we set the index on the InputFunction so that we don't export 183 // the same thing twice (keeps the table size down). 184 if (auto *F = dyn_cast<DefinedFunction>(this)) { 185 F->Function->setTableIndex(Index); 186 return; 187 } 188 LLVM_DEBUG(dbgs() << "setTableIndex " << Name << " -> " << Index << "\n"); 189 assert(TableIndex == INVALID_INDEX); 190 TableIndex = Index; 191 } 192 193 DefinedFunction::DefinedFunction(StringRef Name, uint32_t Flags, InputFile *F, 194 InputFunction *Function) 195 : FunctionSymbol(Name, DefinedFunctionKind, Flags, F, 196 Function ? &Function->Signature : nullptr), 197 Function(Function) {} 198 199 uint32_t DefinedData::getVirtualAddress() const { 200 LLVM_DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n"); 201 if (Segment) 202 return Segment->OutputSeg->StartVA + Segment->OutputSegmentOffset + Offset; 203 return Offset; 204 } 205 206 void DefinedData::setVirtualAddress(uint32_t Value) { 207 LLVM_DEBUG(dbgs() << "setVirtualAddress " << Name << " -> " << Value << "\n"); 208 assert(!Segment); 209 Offset = Value; 210 } 211 212 uint32_t DefinedData::getOutputSegmentOffset() const { 213 LLVM_DEBUG(dbgs() << "getOutputSegmentOffset: " << getName() << "\n"); 214 return Segment->OutputSegmentOffset + Offset; 215 } 216 217 uint32_t DefinedData::getOutputSegmentIndex() const { 218 LLVM_DEBUG(dbgs() << "getOutputSegmentIndex: " << getName() << "\n"); 219 return Segment->OutputSeg->Index; 220 } 221 222 uint32_t GlobalSymbol::getGlobalIndex() const { 223 if (auto *F = dyn_cast<DefinedGlobal>(this)) 224 return F->Global->getGlobalIndex(); 225 assert(GlobalIndex != INVALID_INDEX); 226 return GlobalIndex; 227 } 228 229 void GlobalSymbol::setGlobalIndex(uint32_t Index) { 230 LLVM_DEBUG(dbgs() << "setGlobalIndex " << Name << " -> " << Index << "\n"); 231 assert(GlobalIndex == INVALID_INDEX); 232 GlobalIndex = Index; 233 } 234 235 bool GlobalSymbol::hasGlobalIndex() const { 236 if (auto *F = dyn_cast<DefinedGlobal>(this)) 237 return F->Global->hasGlobalIndex(); 238 return GlobalIndex != INVALID_INDEX; 239 } 240 241 DefinedGlobal::DefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File, 242 InputGlobal *Global) 243 : GlobalSymbol(Name, DefinedGlobalKind, Flags, File, 244 Global ? &Global->getType() : nullptr), 245 Global(Global) {} 246 247 uint32_t EventSymbol::getEventIndex() const { 248 if (auto *F = dyn_cast<DefinedEvent>(this)) 249 return F->Event->getEventIndex(); 250 assert(EventIndex != INVALID_INDEX); 251 return EventIndex; 252 } 253 254 void EventSymbol::setEventIndex(uint32_t Index) { 255 LLVM_DEBUG(dbgs() << "setEventIndex " << Name << " -> " << Index << "\n"); 256 assert(EventIndex == INVALID_INDEX); 257 EventIndex = Index; 258 } 259 260 bool EventSymbol::hasEventIndex() const { 261 if (auto *F = dyn_cast<DefinedEvent>(this)) 262 return F->Event->hasEventIndex(); 263 return EventIndex != INVALID_INDEX; 264 } 265 266 DefinedEvent::DefinedEvent(StringRef Name, uint32_t Flags, InputFile *File, 267 InputEvent *Event) 268 : EventSymbol(Name, DefinedEventKind, Flags, File, 269 Event ? &Event->getType() : nullptr, 270 Event ? &Event->Signature : nullptr), 271 Event(Event) {} 272 273 const OutputSectionSymbol *SectionSymbol::getOutputSectionSymbol() const { 274 assert(Section->OutputSec && Section->OutputSec->SectionSym); 275 return Section->OutputSec->SectionSym; 276 } 277 278 void LazySymbol::fetch() { cast<ArchiveFile>(File)->addMember(&ArchiveSymbol); } 279 280 std::string lld::toString(const wasm::Symbol &Sym) { 281 return lld::maybeDemangleSymbol(Sym.getName()); 282 } 283 284 std::string lld::maybeDemangleSymbol(StringRef Name) { 285 if (Config->Demangle) 286 if (Optional<std::string> S = demangleItanium(Name)) 287 return *S; 288 return Name; 289 } 290 291 std::string lld::toString(wasm::Symbol::Kind Kind) { 292 switch (Kind) { 293 case wasm::Symbol::DefinedFunctionKind: 294 return "DefinedFunction"; 295 case wasm::Symbol::DefinedDataKind: 296 return "DefinedData"; 297 case wasm::Symbol::DefinedGlobalKind: 298 return "DefinedGlobal"; 299 case wasm::Symbol::DefinedEventKind: 300 return "DefinedEvent"; 301 case wasm::Symbol::UndefinedFunctionKind: 302 return "UndefinedFunction"; 303 case wasm::Symbol::UndefinedDataKind: 304 return "UndefinedData"; 305 case wasm::Symbol::UndefinedGlobalKind: 306 return "UndefinedGlobal"; 307 case wasm::Symbol::LazyKind: 308 return "LazyKind"; 309 case wasm::Symbol::SectionKind: 310 return "SectionKind"; 311 case wasm::Symbol::OutputSectionKind: 312 return "OutputSectionKind"; 313 } 314 llvm_unreachable("invalid symbol kind"); 315 } 316 317 318 void lld::wasm::printTraceSymbolUndefined(StringRef Name, const InputFile* File) { 319 message(toString(File) + ": reference to " + Name); 320 } 321 322 // Print out a log message for --trace-symbol. 323 void lld::wasm::printTraceSymbol(Symbol *Sym) { 324 // Undefined symbols are traced via printTraceSymbolUndefined 325 if (Sym->isUndefined()) 326 return; 327 328 std::string S; 329 if (Sym->isLazy()) 330 S = ": lazy definition of "; 331 else 332 S = ": definition of "; 333 334 message(toString(Sym->getFile()) + S + Sym->getName()); 335 } 336 337 const char *lld::wasm::DefaultModule = "env"; 338 const char *lld::wasm::FunctionTableName = "__indirect_function_table"; 339