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 "COFFLinkerContext.h" 11 #include "InputFiles.h" 12 #include "lld/Common/ErrorHandler.h" 13 #include "llvm/Demangle/Demangle.h" 14 15 using namespace llvm; 16 using namespace llvm::object; 17 18 using namespace lld::coff; 19 20 namespace lld { 21 22 static_assert(sizeof(SymbolUnion) <= 48, 23 "symbols should be optimized for memory usage"); 24 25 // Returns a symbol name for an error message. 26 std::string maybeDemangleSymbol(const COFFLinkerContext &ctx, 27 StringRef symName) { 28 if (ctx.config.demangle) { 29 std::string prefix; 30 StringRef prefixless = symName; 31 if (prefixless.consume_front("__imp_")) 32 prefix = "__declspec(dllimport) "; 33 StringRef demangleInput = prefixless; 34 if (ctx.config.machine == I386) 35 demangleInput.consume_front("_"); 36 std::string demangled = demangle(demangleInput); 37 if (demangled != demangleInput) 38 return prefix + demangled; 39 return (prefix + prefixless).str(); 40 } 41 return std::string(symName); 42 } 43 std::string toString(const COFFLinkerContext &ctx, coff::Symbol &b) { 44 return maybeDemangleSymbol(ctx, b.getName()); 45 } 46 std::string toCOFFString(const COFFLinkerContext &ctx, 47 const Archive::Symbol &b) { 48 return maybeDemangleSymbol(ctx, b.getName()); 49 } 50 51 const COFFSyncStream & 52 coff::operator<<(const COFFSyncStream &s, 53 const llvm::object::Archive::Symbol *sym) { 54 s << maybeDemangleSymbol(s.ctx, sym->getName()); 55 return s; 56 } 57 58 namespace coff { 59 60 void Symbol::computeName() { 61 assert(nameData == nullptr && 62 "should only compute the name once for DefinedCOFF symbols"); 63 auto *d = cast<DefinedCOFF>(this); 64 StringRef nameStr = 65 check(cast<ObjFile>(d->file)->getCOFFObj()->getSymbolName(d->sym)); 66 nameData = nameStr.data(); 67 nameSize = nameStr.size(); 68 assert(nameSize == nameStr.size() && "name length truncated"); 69 } 70 71 InputFile *Symbol::getFile() { 72 if (auto *sym = dyn_cast<DefinedCOFF>(this)) 73 return sym->file; 74 if (auto *sym = dyn_cast<LazyArchive>(this)) 75 return sym->file; 76 if (auto *sym = dyn_cast<LazyObject>(this)) 77 return sym->file; 78 if (auto *sym = dyn_cast<LazyDLLSymbol>(this)) 79 return sym->file; 80 return nullptr; 81 } 82 83 bool Symbol::isLive() const { 84 if (auto *r = dyn_cast<DefinedRegular>(this)) 85 return r->getChunk()->live; 86 if (auto *imp = dyn_cast<DefinedImportData>(this)) 87 return imp->file->live; 88 if (auto *imp = dyn_cast<DefinedImportThunk>(this)) 89 return imp->getChunk()->live; 90 // Assume any other kind of symbol is live. 91 return true; 92 } 93 94 void Symbol::replaceKeepingName(Symbol *other, size_t size) { 95 StringRef origName = getName(); 96 memcpy(this, other, size); 97 nameData = origName.data(); 98 nameSize = origName.size(); 99 } 100 101 COFFSymbolRef DefinedCOFF::getCOFFSymbol() { 102 size_t symSize = cast<ObjFile>(file)->getCOFFObj()->getSymbolTableEntrySize(); 103 if (symSize == sizeof(coff_symbol16)) 104 return COFFSymbolRef(reinterpret_cast<const coff_symbol16 *>(sym)); 105 assert(symSize == sizeof(coff_symbol32)); 106 return COFFSymbolRef(reinterpret_cast<const coff_symbol32 *>(sym)); 107 } 108 109 uint64_t DefinedAbsolute::getRVA() { return va - ctx.config.imageBase; } 110 111 DefinedImportThunk::DefinedImportThunk(COFFLinkerContext &ctx, StringRef name, 112 DefinedImportData *s, 113 ImportThunkChunk *chunk) 114 : Defined(DefinedImportThunkKind, name), wrappedSym(s), data(chunk) {} 115 116 Symbol *Undefined::getWeakAlias() { 117 // A weak alias may be a weak alias to another symbol, so check recursively. 118 DenseSet<Symbol *> weakChain; 119 for (Symbol *a = weakAlias; a; a = cast<Undefined>(a)->weakAlias) { 120 // Anti-dependency symbols can't be chained. 121 if (a->isAntiDep) 122 break; 123 if (!isa<Undefined>(a)) 124 return a; 125 if (!weakChain.insert(a).second) 126 break; // We have a cycle. 127 } 128 return nullptr; 129 } 130 131 bool Undefined::resolveWeakAlias() { 132 Defined *d = getDefinedWeakAlias(); 133 if (!d) 134 return false; 135 136 // We want to replace Sym with D. However, we can't just blindly 137 // copy sizeof(SymbolUnion) bytes from D to Sym because D may be an 138 // internal symbol, and internal symbols are stored as "unparented" 139 // Symbols. For that reason we need to check which type of symbol we 140 // are dealing with and copy the correct number of bytes. 141 StringRef name = getName(); 142 bool wasAntiDep = isAntiDep; 143 if (isa<DefinedRegular>(d)) 144 memcpy(this, d, sizeof(DefinedRegular)); 145 else if (isa<DefinedAbsolute>(d)) 146 memcpy(this, d, sizeof(DefinedAbsolute)); 147 else 148 memcpy(this, d, sizeof(SymbolUnion)); 149 150 nameData = name.data(); 151 nameSize = name.size(); 152 isAntiDep = wasAntiDep; 153 return true; 154 } 155 156 MemoryBufferRef LazyArchive::getMemberBuffer() { 157 Archive::Child c = 158 CHECK(sym.getMember(), "could not get the member for symbol " + 159 toCOFFString(file->symtab.ctx, sym)); 160 return CHECK(c.getMemoryBufferRef(), 161 "could not get the buffer for the member defining symbol " + 162 toCOFFString(file->symtab.ctx, sym)); 163 } 164 } // namespace coff 165 } // namespace lld 166