Bug Summary

File:build/source/lld/COFF/Symbols.h
Warning:line 234, column 30
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name MapFile.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/source/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-17/lib/clang/17 -D LLD_VENDOR="Debian" -D _DEBUG -D _GLIBCXX_ASSERTIONS -D _GNU_SOURCE -D _LIBCPP_ENABLE_ASSERTIONS -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I tools/lld/COFF -I /build/source/lld/COFF -I /build/source/lld/include -I tools/lld/include -I include -I /build/source/llvm/include -D _FORTIFY_SOURCE=2 -D NDEBUG -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-17/lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/source/= -fcoverage-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/source/= -source-date-epoch 1683717183 -O2 -Wno-unused-command-line-argument -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -Wno-misleading-indentation -std=c++17 -fdeprecated-macro -fdebug-compilation-dir=/build/source/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/= -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2023-05-10-133810-16478-1 -x c++ /build/source/lld/COFF/MapFile.cpp

/build/source/lld/COFF/MapFile.cpp

1//===- MapFile.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// This file implements the /map option in the same format as link.exe
10// (based on observations)
11//
12// Header (program name, timestamp info, preferred load address)
13//
14// Section list (Start = Section index:Base address):
15// Start Length Name Class
16// 0001:00001000 00000015H .text CODE
17//
18// Symbols list:
19// Address Publics by Value Rva + Base Lib:Object
20// 0001:00001000 main 0000000140001000 main.obj
21// 0001:00001300 ?__scrt_common_main@@YAHXZ 0000000140001300 libcmt:exe_main.obj
22//
23// entry point at 0001:00000360
24//
25// Static symbols
26//
27// 0000:00000000 __guard_fids__ 0000000140000000 libcmt : exe_main.obj
28//===----------------------------------------------------------------------===//
29
30#include "MapFile.h"
31#include "COFFLinkerContext.h"
32#include "SymbolTable.h"
33#include "Symbols.h"
34#include "Writer.h"
35#include "lld/Common/ErrorHandler.h"
36#include "lld/Common/Timer.h"
37#include "llvm/Support/Parallel.h"
38#include "llvm/Support/Path.h"
39#include "llvm/Support/raw_ostream.h"
40
41using namespace llvm;
42using namespace llvm::object;
43using namespace lld;
44using namespace lld::coff;
45
46// Print out the first two columns of a line.
47static void writeHeader(raw_ostream &os, uint32_t sec, uint64_t addr) {
48 os << format(" %04x:%08llx", sec, addr);
49}
50
51// Write the time stamp with the format used by link.exe
52// It seems identical to strftime with "%c" on msvc build, but we need a
53// locale-agnostic version.
54static void writeFormattedTimestamp(raw_ostream &os, time_t tds) {
55 constexpr const char *const days[7] = {"Sun", "Mon", "Tue", "Wed",
56 "Thu", "Fri", "Sat"};
57 constexpr const char *const months[12] = {"Jan", "Feb", "Mar", "Apr",
58 "May", "Jun", "Jul", "Aug",
59 "Sep", "Oct", "Nov", "Dec"};
60 tm *time = localtime(&tds);
61 os << format("%s %s %2d %02d:%02d:%02d %d", days[time->tm_wday],
62 months[time->tm_mon], time->tm_mday, time->tm_hour, time->tm_min,
63 time->tm_sec, time->tm_year + 1900);
64}
65
66static void sortUniqueSymbols(std::vector<Defined *> &syms,
67 uint64_t imageBase) {
68 // Build helper vector
69 using SortEntry = std::pair<Defined *, size_t>;
70 std::vector<SortEntry> v;
71 v.resize(syms.size());
72 for (size_t i = 0, e = syms.size(); i < e; ++i)
73 v[i] = SortEntry(syms[i], i);
74
75 // Remove duplicate symbol pointers
76 parallelSort(v, std::less<SortEntry>());
77 auto end = std::unique(v.begin(), v.end(),
78 [](const SortEntry &a, const SortEntry &b) {
79 return a.first == b.first;
80 });
81 v.erase(end, v.end());
82
83 // Sort by RVA then original order
84 parallelSort(v, [imageBase](const SortEntry &a, const SortEntry &b) {
85 // Add config.imageBase to avoid comparing "negative" RVAs.
86 // This can happen with symbols of Absolute kind
87 uint64_t rvaa = imageBase + a.first->getRVA();
88 uint64_t rvab = imageBase + b.first->getRVA();
89 return rvaa < rvab || (rvaa == rvab && a.second < b.second);
90 });
91
92 syms.resize(v.size());
93 for (size_t i = 0, e = v.size(); i < e; ++i)
94 syms[i] = v[i].first;
95}
96
97// Returns the lists of all symbols that we want to print out.
98static void getSymbols(const COFFLinkerContext &ctx,
99 std::vector<Defined *> &syms,
100 std::vector<Defined *> &staticSyms) {
101
102 for (ObjFile *file : ctx.objFileInstances)
103 for (Symbol *b : file->getSymbols()) {
104 if (!b || !b->isLive())
105 continue;
106 if (auto *sym = dyn_cast<DefinedCOFF>(b)) {
107 COFFSymbolRef symRef = sym->getCOFFSymbol();
108 if (!symRef.isSectionDefinition() &&
109 symRef.getStorageClass() != COFF::IMAGE_SYM_CLASS_LABEL) {
110 if (symRef.getStorageClass() == COFF::IMAGE_SYM_CLASS_STATIC)
111 staticSyms.push_back(sym);
112 else
113 syms.push_back(sym);
114 }
115 } else if (auto *sym = dyn_cast<Defined>(b)) {
116 syms.push_back(sym);
117 }
118 }
119
120 for (ImportFile *file : ctx.importFileInstances) {
121 if (!file->live)
122 continue;
123
124 if (!file->thunkSym)
125 continue;
126
127 if (!file->thunkLive)
128 continue;
129
130 if (auto *thunkSym = dyn_cast<Defined>(file->thunkSym))
131 syms.push_back(thunkSym);
132
133 if (auto *impSym = dyn_cast_or_null<Defined>(file->impSym))
134 syms.push_back(impSym);
135 }
136
137 sortUniqueSymbols(syms, ctx.config.imageBase);
138 sortUniqueSymbols(staticSyms, ctx.config.imageBase);
139}
140
141// Construct a map from symbols to their stringified representations.
142static DenseMap<Defined *, std::string>
143getSymbolStrings(const COFFLinkerContext &ctx, ArrayRef<Defined *> syms) {
144 std::vector<std::string> str(syms.size());
145 parallelFor((size_t)0, syms.size(), [&](size_t i) {
146 raw_string_ostream os(str[i]);
147 Defined *sym = syms[i];
148
149 uint16_t sectionIdx = 0;
150 uint64_t address = 0;
151 SmallString<128> fileDescr;
152
153 if (auto *absSym
1.1
'absSym' is null
1.1
'absSym' is null
= dyn_cast<DefinedAbsolute>(sym)) {
1
Assuming 'sym' is not a 'CastReturnType'
2
Taking false branch
154 address = absSym->getVA();
155 fileDescr = "<absolute>";
156 } else if (isa<DefinedSynthetic>(sym)) {
3
Assuming 'sym' is not a 'DefinedSynthetic'
4
Taking false branch
157 fileDescr = "<linker-defined>";
158 } else if (isa<DefinedCommon>(sym)) {
5
Assuming 'sym' is not a 'DefinedCommon'
6
Taking false branch
159 fileDescr = "<common>";
160 } else if (Chunk *chunk = sym->getChunk()) {
7
Assuming 'chunk' is null
8
Taking false branch
161 address = sym->getRVA();
162 if (OutputSection *sec = ctx.getOutputSection(chunk))
163 address -= sec->header.VirtualAddress;
164
165 sectionIdx = chunk->getOutputSectionIdx();
166
167 InputFile *file;
168 if (auto *impSym = dyn_cast<DefinedImportData>(sym))
169 file = impSym->file;
170 else if (auto *thunkSym = dyn_cast<DefinedImportThunk>(sym))
171 file = thunkSym->wrappedSym->file;
172 else
173 file = sym->getFile();
174
175 if (file) {
176 if (!file->parentName.empty()) {
177 fileDescr = sys::path::filename(file->parentName);
178 sys::path::replace_extension(fileDescr, "");
179 fileDescr += ":";
180 }
181 fileDescr += sys::path::filename(file->getName());
182 }
183 }
184 writeHeader(os, sectionIdx, address);
185 os << " ";
186 os << left_justify(sym->getName(), 26);
187 os << " ";
188 os << format_hex_no_prefix((ctx.config.imageBase + sym->getRVA()), 16);
9
Calling 'Defined::getRVA'
189 if (!fileDescr.empty()) {
190 os << " "; // FIXME : Handle "f" and "i" flags sometimes generated
191 // by link.exe in those spaces
192 os << fileDescr;
193 }
194 });
195
196 DenseMap<Defined *, std::string> ret;
197 for (size_t i = 0, e = syms.size(); i < e; ++i)
198 ret[syms[i]] = std::move(str[i]);
199 return ret;
200}
201
202void lld::coff::writeMapFile(COFFLinkerContext &ctx) {
203 if (ctx.config.mapFile.empty())
204 return;
205
206 std::error_code ec;
207 raw_fd_ostream os(ctx.config.mapFile, ec, sys::fs::OF_None);
208 if (ec)
209 fatal("cannot open " + ctx.config.mapFile + ": " + ec.message());
210
211 ScopedTimer t1(ctx.totalMapTimer);
212
213 // Collect symbol info that we want to print out.
214 ScopedTimer t2(ctx.symbolGatherTimer);
215 std::vector<Defined *> syms;
216 std::vector<Defined *> staticSyms;
217 getSymbols(ctx, syms, staticSyms);
218 t2.stop();
219
220 ScopedTimer t3(ctx.symbolStringsTimer);
221 DenseMap<Defined *, std::string> symStr = getSymbolStrings(ctx, syms);
222 DenseMap<Defined *, std::string> staticSymStr =
223 getSymbolStrings(ctx, staticSyms);
224 t3.stop();
225
226 ScopedTimer t4(ctx.writeTimer);
227 SmallString<128> AppName = sys::path::filename(ctx.config.outputFile);
228 sys::path::replace_extension(AppName, "");
229
230 // Print out the file header
231 os << " " << AppName << "\n";
232 os << "\n";
233
234 os << " Timestamp is " << format_hex_no_prefix(ctx.config.timestamp, 8)
235 << " (";
236 if (ctx.config.repro) {
237 os << "Repro mode";
238 } else {
239 writeFormattedTimestamp(os, ctx.config.timestamp);
240 }
241 os << ")\n";
242
243 os << "\n";
244 os << " Preferred load address is "
245 << format_hex_no_prefix(ctx.config.imageBase, 16) << "\n";
246 os << "\n";
247
248 // Print out section table.
249 os << " Start Length Name Class\n";
250
251 for (OutputSection *sec : ctx.outputSections) {
252 // Merge display of chunks with same sectionName
253 std::vector<std::pair<SectionChunk *, SectionChunk *>> ChunkRanges;
254 for (Chunk *c : sec->chunks) {
255 auto *sc = dyn_cast<SectionChunk>(c);
256 if (!sc)
257 continue;
258
259 if (ChunkRanges.empty() ||
260 c->getSectionName() != ChunkRanges.back().first->getSectionName()) {
261 ChunkRanges.emplace_back(sc, sc);
262 } else {
263 ChunkRanges.back().second = sc;
264 }
265 }
266
267 const bool isCodeSection =
268 (sec->header.Characteristics & COFF::IMAGE_SCN_CNT_CODE) &&
269 (sec->header.Characteristics & COFF::IMAGE_SCN_MEM_READ) &&
270 (sec->header.Characteristics & COFF::IMAGE_SCN_MEM_EXECUTE);
271 StringRef SectionClass = (isCodeSection ? "CODE" : "DATA");
272
273 for (auto &cr : ChunkRanges) {
274 size_t size =
275 cr.second->getRVA() + cr.second->getSize() - cr.first->getRVA();
276
277 auto address = cr.first->getRVA() - sec->header.VirtualAddress;
278 writeHeader(os, sec->sectionIndex, address);
279 os << " " << format_hex_no_prefix(size, 8) << "H";
280 os << " " << left_justify(cr.first->getSectionName(), 23);
281 os << " " << SectionClass;
282 os << '\n';
283 }
284 }
285
286 // Print out the symbols table (without static symbols)
287 os << "\n";
288 os << " Address Publics by Value Rva+Base"
289 " Lib:Object\n";
290 os << "\n";
291 for (Defined *sym : syms)
292 os << symStr[sym] << '\n';
293
294 // Print out the entry point.
295 os << "\n";
296
297 uint16_t entrySecIndex = 0;
298 uint64_t entryAddress = 0;
299
300 if (!ctx.config.noEntry) {
301 Defined *entry = dyn_cast_or_null<Defined>(ctx.config.entry);
302 if (entry) {
303 Chunk *chunk = entry->getChunk();
304 entrySecIndex = chunk->getOutputSectionIdx();
305 entryAddress =
306 entry->getRVA() - ctx.getOutputSection(chunk)->header.VirtualAddress;
307 }
308 }
309 os << " entry point at ";
310 os << format("%04x:%08llx", entrySecIndex, entryAddress);
311 os << "\n";
312
313 // Print out the static symbols
314 os << "\n";
315 os << " Static symbols\n";
316 os << "\n";
317 for (Defined *sym : staticSyms)
318 os << staticSymStr[sym] << '\n';
319
320 // Print out the exported functions
321 if (ctx.config.mapInfo) {
322 os << "\n";
323 os << " Exports\n";
324 os << "\n";
325 os << " ordinal name\n\n";
326 for (Export &e : ctx.config.exports) {
327 os << format(" %7d", e.ordinal) << " " << e.name << "\n";
328 if (!e.extName.empty() && e.extName != e.name)
329 os << " exported name: " << e.extName << "\n";
330 }
331 }
332
333 t4.stop();
334 t1.stop();
335}

/build/source/lld/COFF/Symbols.h

1//===- Symbols.h ------------------------------------------------*- C++ -*-===//
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#ifndef LLD_COFF_SYMBOLS_H
10#define LLD_COFF_SYMBOLS_H
11
12#include "Chunks.h"
13#include "Config.h"
14#include "lld/Common/LLVM.h"
15#include "lld/Common/Memory.h"
16#include "llvm/ADT/ArrayRef.h"
17#include "llvm/Object/Archive.h"
18#include "llvm/Object/COFF.h"
19#include <atomic>
20#include <memory>
21#include <vector>
22
23namespace lld {
24
25namespace coff {
26
27using llvm::object::Archive;
28using llvm::object::COFFSymbolRef;
29using llvm::object::coff_import_header;
30using llvm::object::coff_symbol_generic;
31
32class ArchiveFile;
33class COFFLinkerContext;
34class InputFile;
35class ObjFile;
36class SymbolTable;
37
38// The base class for real symbol classes.
39class Symbol {
40public:
41 enum Kind {
42 // The order of these is significant. We start with the regular defined
43 // symbols as those are the most prevalent and the zero tag is the cheapest
44 // to set. Among the defined kinds, the lower the kind is preferred over
45 // the higher kind when testing whether one symbol should take precedence
46 // over another.
47 DefinedRegularKind = 0,
48 DefinedCommonKind,
49 DefinedLocalImportKind,
50 DefinedImportThunkKind,
51 DefinedImportDataKind,
52 DefinedAbsoluteKind,
53 DefinedSyntheticKind,
54
55 UndefinedKind,
56 LazyArchiveKind,
57 LazyObjectKind,
58 LazyDLLSymbolKind,
59
60 LastDefinedCOFFKind = DefinedCommonKind,
61 LastDefinedKind = DefinedSyntheticKind,
62 };
63
64 Kind kind() const { return static_cast<Kind>(symbolKind); }
65
66 // Returns the symbol name.
67 StringRef getName() {
68 // COFF symbol names are read lazily for a performance reason.
69 // Non-external symbol names are never used by the linker except for logging
70 // or debugging. Their internal references are resolved not by name but by
71 // symbol index. And because they are not external, no one can refer them by
72 // name. Object files contain lots of non-external symbols, and creating
73 // StringRefs for them (which involves lots of strlen() on the string table)
74 // is a waste of time.
75 if (nameData == nullptr)
76 computeName();
77 return StringRef(nameData, nameSize);
78 }
79
80 void replaceKeepingName(Symbol *other, size_t size);
81
82 // Returns the file from which this symbol was created.
83 InputFile *getFile();
84
85 // Indicates that this symbol will be included in the final image. Only valid
86 // after calling markLive.
87 bool isLive() const;
88
89 bool isLazy() const {
90 return symbolKind == LazyArchiveKind || symbolKind == LazyObjectKind ||
91 symbolKind == LazyDLLSymbolKind;
92 }
93
94private:
95 void computeName();
96
97protected:
98 friend SymbolTable;
99 explicit Symbol(Kind k, StringRef n = "")
100 : symbolKind(k), isExternal(true), isCOMDAT(false),
101 writtenToSymtab(false), pendingArchiveLoad(false), isGCRoot(false),
102 isRuntimePseudoReloc(false), deferUndefined(false), canInline(true),
103 isWeak(false), nameSize(n.size()),
104 nameData(n.empty() ? nullptr : n.data()) {
105 assert((!n.empty() || k <= LastDefinedCOFFKind) &&(static_cast <bool> ((!n.empty() || k <= LastDefinedCOFFKind
) && "If the name is empty, the Symbol must be a DefinedCOFF."
) ? void (0) : __assert_fail ("(!n.empty() || k <= LastDefinedCOFFKind) && \"If the name is empty, the Symbol must be a DefinedCOFF.\""
, "lld/COFF/Symbols.h", 106, __extension__ __PRETTY_FUNCTION__
))
106 "If the name is empty, the Symbol must be a DefinedCOFF.")(static_cast <bool> ((!n.empty() || k <= LastDefinedCOFFKind
) && "If the name is empty, the Symbol must be a DefinedCOFF."
) ? void (0) : __assert_fail ("(!n.empty() || k <= LastDefinedCOFFKind) && \"If the name is empty, the Symbol must be a DefinedCOFF.\""
, "lld/COFF/Symbols.h", 106, __extension__ __PRETTY_FUNCTION__
))
;
107 }
108
109 const unsigned symbolKind : 8;
110 unsigned isExternal : 1;
111
112public:
113 // This bit is used by the \c DefinedRegular subclass.
114 unsigned isCOMDAT : 1;
115
116 // This bit is used by Writer::createSymbolAndStringTable() to prevent
117 // symbols from being written to the symbol table more than once.
118 unsigned writtenToSymtab : 1;
119
120 // True if this symbol was referenced by a regular (non-bitcode) object.
121 unsigned isUsedInRegularObj : 1;
122
123 // True if we've seen both a lazy and an undefined symbol with this symbol
124 // name, which means that we have enqueued an archive member load and should
125 // not load any more archive members to resolve the same symbol.
126 unsigned pendingArchiveLoad : 1;
127
128 /// True if we've already added this symbol to the list of GC roots.
129 unsigned isGCRoot : 1;
130
131 unsigned isRuntimePseudoReloc : 1;
132
133 // True if we want to allow this symbol to be undefined in the early
134 // undefined check pass in SymbolTable::reportUnresolvable(), as it
135 // might be fixed up later.
136 unsigned deferUndefined : 1;
137
138 // False if LTO shouldn't inline whatever this symbol points to. If a symbol
139 // is overwritten after LTO, LTO shouldn't inline the symbol because it
140 // doesn't know the final contents of the symbol.
141 unsigned canInline : 1;
142
143 // True if the symbol is weak. This is only tracked for bitcode/LTO symbols.
144 // This information isn't written to the output; rather, it's used for
145 // managing weak symbol overrides.
146 unsigned isWeak : 1;
147
148protected:
149 // Symbol name length. Assume symbol lengths fit in a 32-bit integer.
150 uint32_t nameSize;
151
152 const char *nameData;
153};
154
155// The base class for any defined symbols, including absolute symbols,
156// etc.
157class Defined : public Symbol {
158public:
159 Defined(Kind k, StringRef n) : Symbol(k, n) {}
160
161 static bool classof(const Symbol *s) { return s->kind() <= LastDefinedKind; }
162
163 // Returns the RVA (relative virtual address) of this symbol. The
164 // writer sets and uses RVAs.
165 uint64_t getRVA();
166
167 // Returns the chunk containing this symbol. Absolute symbols and __ImageBase
168 // do not have chunks, so this may return null.
169 Chunk *getChunk();
170};
171
172// Symbols defined via a COFF object file or bitcode file. For COFF files, this
173// stores a coff_symbol_generic*, and names of internal symbols are lazily
174// loaded through that. For bitcode files, Sym is nullptr and the name is stored
175// as a decomposed StringRef.
176class DefinedCOFF : public Defined {
177 friend Symbol;
178
179public:
180 DefinedCOFF(Kind k, InputFile *f, StringRef n, const coff_symbol_generic *s)
181 : Defined(k, n), file(f), sym(s) {}
182
183 static bool classof(const Symbol *s) {
184 return s->kind() <= LastDefinedCOFFKind;
185 }
186
187 InputFile *getFile() { return file; }
188
189 COFFSymbolRef getCOFFSymbol();
190
191 InputFile *file;
192
193protected:
194 const coff_symbol_generic *sym;
195};
196
197// Regular defined symbols read from object file symbol tables.
198class DefinedRegular : public DefinedCOFF {
199public:
200 DefinedRegular(InputFile *f, StringRef n, bool isCOMDAT,
201 bool isExternal = false,
202 const coff_symbol_generic *s = nullptr,
203 SectionChunk *c = nullptr, bool isWeak = false)
204 : DefinedCOFF(DefinedRegularKind, f, n, s), data(c ? &c->repl : nullptr) {
205 this->isExternal = isExternal;
206 this->isCOMDAT = isCOMDAT;
207 this->isWeak = isWeak;
208 }
209
210 static bool classof(const Symbol *s) {
211 return s->kind() == DefinedRegularKind;
212 }
213
214 uint64_t getRVA() const { return (*data)->getRVA() + sym->Value; }
215 SectionChunk *getChunk() const { return *data; }
216 uint32_t getValue() const { return sym->Value; }
217
218 SectionChunk **data;
219};
220
221class DefinedCommon : public DefinedCOFF {
222public:
223 DefinedCommon(InputFile *f, StringRef n, uint64_t size,
224 const coff_symbol_generic *s = nullptr,
225 CommonChunk *c = nullptr)
226 : DefinedCOFF(DefinedCommonKind, f, n, s), data(c), size(size) {
227 this->isExternal = true;
228 }
229
230 static bool classof(const Symbol *s) {
231 return s->kind() == DefinedCommonKind;
232 }
233
234 uint64_t getRVA() { return data->getRVA(); }
13
Called C++ object pointer is null
235 CommonChunk *getChunk() { return data; }
236
237private:
238 friend SymbolTable;
239 uint64_t getSize() const { return size; }
240 CommonChunk *data;
241 uint64_t size;
242};
243
244// Absolute symbols.
245class DefinedAbsolute : public Defined {
246public:
247 DefinedAbsolute(const COFFLinkerContext &c, StringRef n, COFFSymbolRef s)
248 : Defined(DefinedAbsoluteKind, n), va(s.getValue()), ctx(c) {
249 isExternal = s.isExternal();
250 }
251
252 DefinedAbsolute(const COFFLinkerContext &c, StringRef n, uint64_t v)
253 : Defined(DefinedAbsoluteKind, n), va(v), ctx(c) {}
254
255 static bool classof(const Symbol *s) {
256 return s->kind() == DefinedAbsoluteKind;
257 }
258
259 uint64_t getRVA();
260 void setVA(uint64_t v) { va = v; }
261 uint64_t getVA() const { return va; }
262
263private:
264 uint64_t va;
265 const COFFLinkerContext &ctx;
266};
267
268// This symbol is used for linker-synthesized symbols like __ImageBase and
269// __safe_se_handler_table.
270class DefinedSynthetic : public Defined {
271public:
272 explicit DefinedSynthetic(StringRef name, Chunk *c)
273 : Defined(DefinedSyntheticKind, name), c(c) {}
274
275 static bool classof(const Symbol *s) {
276 return s->kind() == DefinedSyntheticKind;
277 }
278
279 // A null chunk indicates that this is __ImageBase. Otherwise, this is some
280 // other synthesized chunk, like SEHTableChunk.
281 uint32_t getRVA() { return c ? c->getRVA() : 0; }
282 Chunk *getChunk() { return c; }
283
284private:
285 Chunk *c;
286};
287
288// This class represents a symbol defined in an archive file. It is
289// created from an archive file header, and it knows how to load an
290// object file from an archive to replace itself with a defined
291// symbol. If the resolver finds both Undefined and LazyArchive for
292// the same name, it will ask the LazyArchive to load a file.
293class LazyArchive : public Symbol {
294public:
295 LazyArchive(ArchiveFile *f, const Archive::Symbol s)
296 : Symbol(LazyArchiveKind, s.getName()), file(f), sym(s) {}
297
298 static bool classof(const Symbol *s) { return s->kind() == LazyArchiveKind; }
299
300 MemoryBufferRef getMemberBuffer();
301
302 ArchiveFile *file;
303 const Archive::Symbol sym;
304};
305
306class LazyObject : public Symbol {
307public:
308 LazyObject(InputFile *f, StringRef n) : Symbol(LazyObjectKind, n), file(f) {}
309 static bool classof(const Symbol *s) { return s->kind() == LazyObjectKind; }
310 InputFile *file;
311};
312
313// MinGW only.
314class LazyDLLSymbol : public Symbol {
315public:
316 LazyDLLSymbol(DLLFile *f, DLLFile::Symbol *s, StringRef n)
317 : Symbol(LazyDLLSymbolKind, n), file(f), sym(s) {}
318 static bool classof(const Symbol *s) {
319 return s->kind() == LazyDLLSymbolKind;
320 }
321
322 DLLFile *file;
323 DLLFile::Symbol *sym;
324};
325
326// Undefined symbols.
327class Undefined : public Symbol {
328public:
329 explicit Undefined(StringRef n) : Symbol(UndefinedKind, n) {}
330
331 static bool classof(const Symbol *s) { return s->kind() == UndefinedKind; }
332
333 // An undefined symbol can have a fallback symbol which gives an
334 // undefined symbol a second chance if it would remain undefined.
335 // If it remains undefined, it'll be replaced with whatever the
336 // Alias pointer points to.
337 Symbol *weakAlias = nullptr;
338
339 // If this symbol is external weak, try to resolve it to a defined
340 // symbol by searching the chain of fallback symbols. Returns the symbol if
341 // successful, otherwise returns null.
342 Defined *getWeakAlias();
343};
344
345// Windows-specific classes.
346
347// This class represents a symbol imported from a DLL. This has two
348// names for internal use and external use. The former is used for
349// name resolution, and the latter is used for the import descriptor
350// table in an output. The former has "__imp_" prefix.
351class DefinedImportData : public Defined {
352public:
353 DefinedImportData(StringRef n, ImportFile *f)
354 : Defined(DefinedImportDataKind, n), file(f) {
355 }
356
357 static bool classof(const Symbol *s) {
358 return s->kind() == DefinedImportDataKind;
359 }
360
361 uint64_t getRVA() { return file->location->getRVA(); }
362 Chunk *getChunk() { return file->location; }
363 void setLocation(Chunk *addressTable) { file->location = addressTable; }
364
365 StringRef getDLLName() { return file->dllName; }
366 StringRef getExternalName() { return file->externalName; }
367 uint16_t getOrdinal() { return file->hdr->OrdinalHint; }
368
369 ImportFile *file;
370
371 // This is a pointer to the synthetic symbol associated with the load thunk
372 // for this symbol that will be called if the DLL is delay-loaded. This is
373 // needed for Control Flow Guard because if this DefinedImportData symbol is a
374 // valid call target, the corresponding load thunk must also be marked as a
375 // valid call target.
376 DefinedSynthetic *loadThunkSym = nullptr;
377};
378
379// This class represents a symbol for a jump table entry which jumps
380// to a function in a DLL. Linker are supposed to create such symbols
381// without "__imp_" prefix for all function symbols exported from
382// DLLs, so that you can call DLL functions as regular functions with
383// a regular name. A function pointer is given as a DefinedImportData.
384class DefinedImportThunk : public Defined {
385public:
386 DefinedImportThunk(COFFLinkerContext &ctx, StringRef name,
387 DefinedImportData *s, uint16_t machine);
388
389 static bool classof(const Symbol *s) {
390 return s->kind() == DefinedImportThunkKind;
391 }
392
393 uint64_t getRVA() { return data->getRVA(); }
394 Chunk *getChunk() { return data; }
395
396 DefinedImportData *wrappedSym;
397
398private:
399 Chunk *data;
400};
401
402// If you have a symbol "foo" in your object file, a symbol name
403// "__imp_foo" becomes automatically available as a pointer to "foo".
404// This class is for such automatically-created symbols.
405// Yes, this is an odd feature. We didn't intend to implement that.
406// This is here just for compatibility with MSVC.
407class DefinedLocalImport : public Defined {
408public:
409 DefinedLocalImport(COFFLinkerContext &ctx, StringRef n, Defined *s)
410 : Defined(DefinedLocalImportKind, n),
411 data(make<LocalImportChunk>(ctx, s)) {}
412
413 static bool classof(const Symbol *s) {
414 return s->kind() == DefinedLocalImportKind;
415 }
416
417 uint64_t getRVA() { return data->getRVA(); }
418 Chunk *getChunk() { return data; }
419
420private:
421 LocalImportChunk *data;
422};
423
424inline uint64_t Defined::getRVA() {
425 switch (kind()) {
10
Control jumps to 'case DefinedCommonKind:' at line 436
426 case DefinedAbsoluteKind:
427 return cast<DefinedAbsolute>(this)->getRVA();
428 case DefinedSyntheticKind:
429 return cast<DefinedSynthetic>(this)->getRVA();
430 case DefinedImportDataKind:
431 return cast<DefinedImportData>(this)->getRVA();
432 case DefinedImportThunkKind:
433 return cast<DefinedImportThunk>(this)->getRVA();
434 case DefinedLocalImportKind:
435 return cast<DefinedLocalImport>(this)->getRVA();
436 case DefinedCommonKind:
437 return cast<DefinedCommon>(this)->getRVA();
11
The object is a 'DefinedCommon'
12
Calling 'DefinedCommon::getRVA'
438 case DefinedRegularKind:
439 return cast<DefinedRegular>(this)->getRVA();
440 case LazyArchiveKind:
441 case LazyObjectKind:
442 case LazyDLLSymbolKind:
443 case UndefinedKind:
444 llvm_unreachable("Cannot get the address for an undefined symbol.")::llvm::llvm_unreachable_internal("Cannot get the address for an undefined symbol."
, "lld/COFF/Symbols.h", 444)
;
445 }
446 llvm_unreachable("unknown symbol kind")::llvm::llvm_unreachable_internal("unknown symbol kind", "lld/COFF/Symbols.h"
, 446)
;
447}
448
449inline Chunk *Defined::getChunk() {
450 switch (kind()) {
451 case DefinedRegularKind:
452 return cast<DefinedRegular>(this)->getChunk();
453 case DefinedAbsoluteKind:
454 return nullptr;
455 case DefinedSyntheticKind:
456 return cast<DefinedSynthetic>(this)->getChunk();
457 case DefinedImportDataKind:
458 return cast<DefinedImportData>(this)->getChunk();
459 case DefinedImportThunkKind:
460 return cast<DefinedImportThunk>(this)->getChunk();
461 case DefinedLocalImportKind:
462 return cast<DefinedLocalImport>(this)->getChunk();
463 case DefinedCommonKind:
464 return cast<DefinedCommon>(this)->getChunk();
465 case LazyArchiveKind:
466 case LazyObjectKind:
467 case LazyDLLSymbolKind:
468 case UndefinedKind:
469 llvm_unreachable("Cannot get the chunk of an undefined symbol.")::llvm::llvm_unreachable_internal("Cannot get the chunk of an undefined symbol."
, "lld/COFF/Symbols.h", 469)
;
470 }
471 llvm_unreachable("unknown symbol kind")::llvm::llvm_unreachable_internal("unknown symbol kind", "lld/COFF/Symbols.h"
, 471)
;
472}
473
474// A buffer class that is large enough to hold any Symbol-derived
475// object. We allocate memory using this class and instantiate a symbol
476// using the placement new.
477union SymbolUnion {
478 alignas(DefinedRegular) char a[sizeof(DefinedRegular)];
479 alignas(DefinedCommon) char b[sizeof(DefinedCommon)];
480 alignas(DefinedAbsolute) char c[sizeof(DefinedAbsolute)];
481 alignas(DefinedSynthetic) char d[sizeof(DefinedSynthetic)];
482 alignas(LazyArchive) char e[sizeof(LazyArchive)];
483 alignas(Undefined) char f[sizeof(Undefined)];
484 alignas(DefinedImportData) char g[sizeof(DefinedImportData)];
485 alignas(DefinedImportThunk) char h[sizeof(DefinedImportThunk)];
486 alignas(DefinedLocalImport) char i[sizeof(DefinedLocalImport)];
487 alignas(LazyObject) char j[sizeof(LazyObject)];
488 alignas(LazyDLLSymbol) char k[sizeof(LazyDLLSymbol)];
489};
490
491template <typename T, typename... ArgT>
492void replaceSymbol(Symbol *s, ArgT &&... arg) {
493 static_assert(std::is_trivially_destructible<T>(),
494 "Symbol types must be trivially destructible");
495 static_assert(sizeof(T) <= sizeof(SymbolUnion), "Symbol too small");
496 static_assert(alignof(T) <= alignof(SymbolUnion),
497 "SymbolUnion not aligned enough");
498 assert(static_cast<Symbol *>(static_cast<T *>(nullptr)) == nullptr &&(static_cast <bool> (static_cast<Symbol *>(static_cast
<T *>(nullptr)) == nullptr && "Not a Symbol") ?
void (0) : __assert_fail ("static_cast<Symbol *>(static_cast<T *>(nullptr)) == nullptr && \"Not a Symbol\""
, "lld/COFF/Symbols.h", 499, __extension__ __PRETTY_FUNCTION__
))
499 "Not a Symbol")(static_cast <bool> (static_cast<Symbol *>(static_cast
<T *>(nullptr)) == nullptr && "Not a Symbol") ?
void (0) : __assert_fail ("static_cast<Symbol *>(static_cast<T *>(nullptr)) == nullptr && \"Not a Symbol\""
, "lld/COFF/Symbols.h", 499, __extension__ __PRETTY_FUNCTION__
))
;
500 bool canInline = s->canInline;
501 new (s) T(std::forward<ArgT>(arg)...);
502 s->canInline = canInline;
503}
504} // namespace coff
505
506std::string toString(const coff::COFFLinkerContext &ctx, coff::Symbol &b);
507std::string toCOFFString(const coff::COFFLinkerContext &ctx,
508 const llvm::object::Archive::Symbol &b);
509
510} // namespace lld
511
512#endif