| //===- SymbolTable.h --------------------------------------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLD_WASM_SYMBOL_TABLE_H |
| #define LLD_WASM_SYMBOL_TABLE_H |
| |
| #include "InputFiles.h" |
| #include "LTO.h" |
| #include "Symbols.h" |
| #include "lld/Common/LLVM.h" |
| #include "llvm/ADT/CachedHashString.h" |
| #include "llvm/ADT/DenseSet.h" |
| #include "llvm/BinaryFormat/WasmTraits.h" |
| #include <optional> |
| |
| namespace lld::wasm { |
| |
| class InputSegment; |
| |
| // SymbolTable is a bucket of all known symbols, including defined, |
| // undefined, or lazy symbols (the last one is symbols in archive |
| // files whose archive members are not yet loaded). |
| // |
| // We put all symbols of all files to a SymbolTable, and the |
| // SymbolTable selects the "best" symbols if there are name |
| // conflicts. For example, obviously, a defined symbol is better than |
| // an undefined symbol. Or, if there's a conflict between a lazy and a |
| // undefined, it'll read an archive member to read a real definition |
| // to replace the lazy symbol. The logic is implemented in the |
| // add*() functions, which are called by input files as they are parsed. |
| // There is one add* function per symbol type. |
| class SymbolTable { |
| public: |
| ArrayRef<Symbol *> symbols() const { return symVector; } |
| |
| void wrap(Symbol *sym, Symbol *real, Symbol *wrap); |
| |
| void addFile(InputFile *file, StringRef symName = {}); |
| |
| void compileBitcodeFiles(); |
| |
| Symbol *find(StringRef name); |
| |
| void replace(StringRef name, Symbol* sym); |
| |
| void trace(StringRef name); |
| |
| Symbol *addSharedFunction(StringRef name, uint32_t flags, InputFile *file, |
| const WasmSignature *sig); |
| Symbol *addSharedData(StringRef name, uint32_t flags, InputFile *file); |
| Symbol *addDefinedFunction(StringRef name, uint32_t flags, InputFile *file, |
| InputFunction *function); |
| Symbol *addDefinedData(StringRef name, uint32_t flags, InputFile *file, |
| InputChunk *segment, uint64_t address, uint64_t size); |
| Symbol *addDefinedGlobal(StringRef name, uint32_t flags, InputFile *file, |
| InputGlobal *g); |
| Symbol *addDefinedTag(StringRef name, uint32_t flags, InputFile *file, |
| InputTag *t); |
| Symbol *addDefinedTable(StringRef name, uint32_t flags, InputFile *file, |
| InputTable *t); |
| |
| Symbol *addUndefinedFunction(StringRef name, |
| std::optional<StringRef> importName, |
| std::optional<StringRef> importModule, |
| uint32_t flags, InputFile *file, |
| const WasmSignature *signature, |
| bool isCalledDirectly); |
| Symbol *addUndefinedData(StringRef name, uint32_t flags, InputFile *file); |
| Symbol *addUndefinedGlobal(StringRef name, |
| std::optional<StringRef> importName, |
| std::optional<StringRef> importModule, |
| uint32_t flags, InputFile *file, |
| const WasmGlobalType *type); |
| Symbol *addUndefinedTable(StringRef name, std::optional<StringRef> importName, |
| std::optional<StringRef> importModule, |
| uint32_t flags, InputFile *file, |
| const WasmTableType *type); |
| Symbol *addUndefinedTag(StringRef name, std::optional<StringRef> importName, |
| std::optional<StringRef> importModule, uint32_t flags, |
| InputFile *file, const WasmSignature *sig); |
| |
| TableSymbol *resolveIndirectFunctionTable(bool required); |
| |
| void addLazy(StringRef name, InputFile *f); |
| |
| bool addComdat(StringRef name); |
| |
| DefinedData *addSyntheticDataSymbol(StringRef name, uint32_t flags); |
| DefinedGlobal *addSyntheticGlobal(StringRef name, uint32_t flags, |
| InputGlobal *global); |
| DefinedFunction *addSyntheticFunction(StringRef name, uint32_t flags, |
| InputFunction *function); |
| DefinedData *addOptionalDataSymbol(StringRef name, uint64_t value = 0); |
| DefinedGlobal *addOptionalGlobalSymbol(StringRef name, InputGlobal *global); |
| DefinedTable *addSyntheticTable(StringRef name, uint32_t flags, |
| InputTable *global); |
| |
| void handleSymbolVariants(); |
| void handleWeakUndefines(); |
| DefinedFunction *createUndefinedStub(const WasmSignature &sig); |
| |
| private: |
| std::pair<Symbol *, bool> insert(StringRef name, const InputFile *file); |
| std::pair<Symbol *, bool> insertName(StringRef name); |
| |
| bool getFunctionVariant(Symbol* sym, const WasmSignature *sig, |
| const InputFile *file, Symbol **out); |
| InputFunction *replaceWithUnreachable(Symbol *sym, const WasmSignature &sig, |
| StringRef debugName); |
| void replaceWithUndefined(Symbol *sym); |
| |
| TableSymbol *createDefinedIndirectFunctionTable(StringRef name); |
| TableSymbol *createUndefinedIndirectFunctionTable(StringRef name); |
| |
| // Maps symbol names to index into the symVector. -1 means that symbols |
| // is to not yet in the vector but it should have tracing enabled if it is |
| // ever added. |
| llvm::DenseMap<llvm::CachedHashStringRef, int> symMap; |
| std::vector<Symbol *> symVector; |
| |
| // For certain symbols types, e.g. function symbols, we allow for multiple |
| // variants of the same symbol with different signatures. |
| llvm::DenseMap<llvm::CachedHashStringRef, std::vector<Symbol *>> symVariants; |
| llvm::DenseMap<WasmSignature, DefinedFunction *> stubFunctions; |
| |
| // Comdat groups define "link once" sections. If two comdat groups have the |
| // same name, only one of them is linked, and the other is ignored. This set |
| // is used to uniquify them. |
| llvm::DenseSet<llvm::CachedHashStringRef> comdatGroups; |
| |
| // For LTO. |
| std::unique_ptr<BitcodeCompiler> lto; |
| }; |
| |
| extern SymbolTable *symtab; |
| |
| } // namespace lld::wasm |
| |
| #endif |