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