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(Prefix: "__imp_" )) |
37 | prefix = "__declspec(dllimport) " ; |
38 | StringRef demangleInput = prefixless; |
39 | if (ctx.config.machine == I386) |
40 | demangleInput.consume_front(Prefix: "_" ); |
41 | std::string demangled = demangle(MangledName: 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, symName: b.getName()); |
50 | } |
51 | std::string toCOFFString(const COFFLinkerContext &ctx, |
52 | const Archive::Symbol &b) { |
53 | return maybeDemangleSymbol(ctx, symName: 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>(Val: this); |
62 | StringRef nameStr = |
63 | check(e: cast<ObjFile>(Val: d->file)->getCOFFObj()->getSymbolName(Symbol: 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>(Val: this)) |
71 | return sym->file; |
72 | if (auto *sym = dyn_cast<LazyArchive>(Val: this)) |
73 | return sym->file; |
74 | if (auto *sym = dyn_cast<LazyObject>(Val: this)) |
75 | return sym->file; |
76 | if (auto *sym = dyn_cast<LazyDLLSymbol>(Val: this)) |
77 | return sym->file; |
78 | return nullptr; |
79 | } |
80 | |
81 | bool Symbol::isLive() const { |
82 | if (auto *r = dyn_cast<DefinedRegular>(Val: this)) |
83 | return r->getChunk()->live; |
84 | if (auto *imp = dyn_cast<DefinedImportData>(Val: this)) |
85 | return imp->file->live; |
86 | if (auto *imp = dyn_cast<DefinedImportThunk>(Val: 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(dest: this, src: other, n: size); |
96 | nameData = origName.data(); |
97 | nameSize = origName.size(); |
98 | } |
99 | |
100 | COFFSymbolRef DefinedCOFF::getCOFFSymbol() { |
101 | size_t symSize = cast<ObjFile>(Val: 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>(args&: ctx, args&: s); |
114 | if (machine == I386) |
115 | return make<ImportThunkChunkX86>(args&: ctx, args&: s); |
116 | if (machine == ARM64) |
117 | return make<ImportThunkChunkARM64>(args&: ctx, args&: s); |
118 | assert(machine == ARMNT); |
119 | return make<ImportThunkChunkARM>(args&: ctx, args&: 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>(Val: a)->weakAlias) |
130 | if (auto *d = dyn_cast<Defined>(Val: 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 | |