xref: /llvm-project/lld/COFF/Symbols.cpp (revision a16adafd4799665718f54596054bbc816d151f92)
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