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 static 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.str()); 42 if (demangled != demangleInput) 43 return prefix + demangle(demangleInput.str()); 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 namespace coff { 57 58 void Symbol::computeName() { 59 assert(nameData == nullptr && 60 "should only compute the name once for DefinedCOFF symbols"); 61 auto *d = cast<DefinedCOFF>(this); 62 StringRef nameStr = 63 check(cast<ObjFile>(d->file)->getCOFFObj()->getSymbolName(d->sym)); 64 nameData = nameStr.data(); 65 nameSize = nameStr.size(); 66 assert(nameSize == nameStr.size() && "name length truncated"); 67 } 68 69 InputFile *Symbol::getFile() { 70 if (auto *sym = dyn_cast<DefinedCOFF>(this)) 71 return sym->file; 72 if (auto *sym = dyn_cast<LazyArchive>(this)) 73 return sym->file; 74 if (auto *sym = dyn_cast<LazyObject>(this)) 75 return sym->file; 76 if (auto *sym = dyn_cast<LazyDLLSymbol>(this)) 77 return sym->file; 78 return nullptr; 79 } 80 81 bool Symbol::isLive() const { 82 if (auto *r = dyn_cast<DefinedRegular>(this)) 83 return r->getChunk()->live; 84 if (auto *imp = dyn_cast<DefinedImportData>(this)) 85 return imp->file->live; 86 if (auto *imp = dyn_cast<DefinedImportThunk>(this)) 87 return imp->wrappedSym->file->thunkLive; 88 // Assume any other kind of symbol is live. 89 return true; 90 } 91 92 // MinGW specific. 93 void Symbol::replaceKeepingName(Symbol *other, size_t size) { 94 StringRef origName = getName(); 95 memcpy(this, other, size); 96 nameData = origName.data(); 97 nameSize = origName.size(); 98 } 99 100 COFFSymbolRef DefinedCOFF::getCOFFSymbol() { 101 size_t symSize = cast<ObjFile>(file)->getCOFFObj()->getSymbolTableEntrySize(); 102 if (symSize == sizeof(coff_symbol16)) 103 return COFFSymbolRef(reinterpret_cast<const coff_symbol16 *>(sym)); 104 assert(symSize == sizeof(coff_symbol32)); 105 return COFFSymbolRef(reinterpret_cast<const coff_symbol32 *>(sym)); 106 } 107 108 uint64_t DefinedAbsolute::getRVA() { return va - ctx.config.imageBase; } 109 110 static Chunk *makeImportThunk(COFFLinkerContext &ctx, DefinedImportData *s, 111 uint16_t machine) { 112 if (machine == AMD64) 113 return make<ImportThunkChunkX64>(ctx, s); 114 if (machine == I386) 115 return make<ImportThunkChunkX86>(ctx, s); 116 if (machine == ARM64) 117 return make<ImportThunkChunkARM64>(ctx, s); 118 assert(machine == ARMNT); 119 return make<ImportThunkChunkARM>(ctx, s); 120 } 121 122 DefinedImportThunk::DefinedImportThunk(COFFLinkerContext &ctx, StringRef name, 123 DefinedImportData *s, uint16_t machine) 124 : Defined(DefinedImportThunkKind, name), wrappedSym(s), 125 data(makeImportThunk(ctx, s, machine)) {} 126 127 Defined *Undefined::getWeakAlias() { 128 // A weak alias may be a weak alias to another symbol, so check recursively. 129 for (Symbol *a = weakAlias; a; a = cast<Undefined>(a)->weakAlias) 130 if (auto *d = dyn_cast<Defined>(a)) 131 return d; 132 return nullptr; 133 } 134 135 MemoryBufferRef LazyArchive::getMemberBuffer() { 136 Archive::Child c = 137 CHECK(sym.getMember(), "could not get the member for symbol " + 138 toCOFFString(file->ctx, sym)); 139 return CHECK(c.getMemoryBufferRef(), 140 "could not get the buffer for the member defining symbol " + 141 toCOFFString(file->ctx, sym)); 142 } 143 } // namespace coff 144 } // namespace lld 145