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