10b57cec5SDimitry Andric //===- Symbols.cpp --------------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "Symbols.h"
10bdd1243dSDimitry Andric #include "COFFLinkerContext.h"
110b57cec5SDimitry Andric #include "InputFiles.h"
120b57cec5SDimitry Andric #include "lld/Common/ErrorHandler.h"
130b57cec5SDimitry Andric #include "lld/Common/Memory.h"
140b57cec5SDimitry Andric #include "lld/Common/Strings.h"
150b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
1685868e8aSDimitry Andric #include "llvm/Demangle/Demangle.h"
170b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
180b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
190b57cec5SDimitry Andric
200b57cec5SDimitry Andric using namespace llvm;
210b57cec5SDimitry Andric using namespace llvm::object;
220b57cec5SDimitry Andric
230b57cec5SDimitry Andric using namespace lld::coff;
240b57cec5SDimitry Andric
250b57cec5SDimitry Andric namespace lld {
260b57cec5SDimitry Andric
270b57cec5SDimitry Andric static_assert(sizeof(SymbolUnion) <= 48,
280b57cec5SDimitry Andric "symbols should be optimized for memory usage");
290b57cec5SDimitry Andric
300b57cec5SDimitry Andric // Returns a symbol name for an error message.
maybeDemangleSymbol(const COFFLinkerContext & ctx,StringRef symName)31bdd1243dSDimitry Andric static std::string maybeDemangleSymbol(const COFFLinkerContext &ctx,
32bdd1243dSDimitry Andric StringRef symName) {
33bdd1243dSDimitry Andric if (ctx.config.demangle) {
3485868e8aSDimitry Andric std::string prefix;
3585868e8aSDimitry Andric StringRef prefixless = symName;
3685868e8aSDimitry Andric if (prefixless.consume_front("__imp_"))
3785868e8aSDimitry Andric prefix = "__declspec(dllimport) ";
3885868e8aSDimitry Andric StringRef demangleInput = prefixless;
39bdd1243dSDimitry Andric if (ctx.config.machine == I386)
4085868e8aSDimitry Andric demangleInput.consume_front("_");
4106c3fb27SDimitry Andric std::string demangled = demangle(demangleInput);
4285868e8aSDimitry Andric if (demangled != demangleInput)
4306c3fb27SDimitry Andric return prefix + demangled;
4485868e8aSDimitry Andric return (prefix + prefixless).str();
4585868e8aSDimitry Andric }
465ffd83dbSDimitry Andric return std::string(symName);
470b57cec5SDimitry Andric }
toString(const COFFLinkerContext & ctx,coff::Symbol & b)48bdd1243dSDimitry Andric std::string toString(const COFFLinkerContext &ctx, coff::Symbol &b) {
49bdd1243dSDimitry Andric return maybeDemangleSymbol(ctx, b.getName());
5085868e8aSDimitry Andric }
toCOFFString(const COFFLinkerContext & ctx,const Archive::Symbol & b)51bdd1243dSDimitry Andric std::string toCOFFString(const COFFLinkerContext &ctx,
52bdd1243dSDimitry Andric const Archive::Symbol &b) {
53bdd1243dSDimitry Andric return maybeDemangleSymbol(ctx, b.getName());
540b57cec5SDimitry Andric }
550b57cec5SDimitry Andric
560b57cec5SDimitry Andric namespace coff {
570b57cec5SDimitry Andric
computeName()585ffd83dbSDimitry Andric void Symbol::computeName() {
595ffd83dbSDimitry Andric assert(nameData == nullptr &&
605ffd83dbSDimitry Andric "should only compute the name once for DefinedCOFF symbols");
610b57cec5SDimitry Andric auto *d = cast<DefinedCOFF>(this);
625ffd83dbSDimitry Andric StringRef nameStr =
635ffd83dbSDimitry Andric check(cast<ObjFile>(d->file)->getCOFFObj()->getSymbolName(d->sym));
640b57cec5SDimitry Andric nameData = nameStr.data();
650b57cec5SDimitry Andric nameSize = nameStr.size();
660b57cec5SDimitry Andric assert(nameSize == nameStr.size() && "name length truncated");
670b57cec5SDimitry Andric }
680b57cec5SDimitry Andric
getFile()690b57cec5SDimitry Andric InputFile *Symbol::getFile() {
700b57cec5SDimitry Andric if (auto *sym = dyn_cast<DefinedCOFF>(this))
710b57cec5SDimitry Andric return sym->file;
7285868e8aSDimitry Andric if (auto *sym = dyn_cast<LazyArchive>(this))
7385868e8aSDimitry Andric return sym->file;
7485868e8aSDimitry Andric if (auto *sym = dyn_cast<LazyObject>(this))
750b57cec5SDimitry Andric return sym->file;
76fe6060f1SDimitry Andric if (auto *sym = dyn_cast<LazyDLLSymbol>(this))
77fe6060f1SDimitry Andric return sym->file;
780b57cec5SDimitry Andric return nullptr;
790b57cec5SDimitry Andric }
800b57cec5SDimitry Andric
isLive() const810b57cec5SDimitry Andric bool Symbol::isLive() const {
820b57cec5SDimitry Andric if (auto *r = dyn_cast<DefinedRegular>(this))
830b57cec5SDimitry Andric return r->getChunk()->live;
840b57cec5SDimitry Andric if (auto *imp = dyn_cast<DefinedImportData>(this))
850b57cec5SDimitry Andric return imp->file->live;
860b57cec5SDimitry Andric if (auto *imp = dyn_cast<DefinedImportThunk>(this))
870b57cec5SDimitry Andric return imp->wrappedSym->file->thunkLive;
880b57cec5SDimitry Andric // Assume any other kind of symbol is live.
890b57cec5SDimitry Andric return true;
900b57cec5SDimitry Andric }
910b57cec5SDimitry Andric
920b57cec5SDimitry Andric // MinGW specific.
replaceKeepingName(Symbol * other,size_t size)930b57cec5SDimitry Andric void Symbol::replaceKeepingName(Symbol *other, size_t size) {
940b57cec5SDimitry Andric StringRef origName = getName();
950b57cec5SDimitry Andric memcpy(this, other, size);
960b57cec5SDimitry Andric nameData = origName.data();
970b57cec5SDimitry Andric nameSize = origName.size();
980b57cec5SDimitry Andric }
990b57cec5SDimitry Andric
getCOFFSymbol()1000b57cec5SDimitry Andric COFFSymbolRef DefinedCOFF::getCOFFSymbol() {
1010b57cec5SDimitry Andric size_t symSize = cast<ObjFile>(file)->getCOFFObj()->getSymbolTableEntrySize();
1020b57cec5SDimitry Andric if (symSize == sizeof(coff_symbol16))
1030b57cec5SDimitry Andric return COFFSymbolRef(reinterpret_cast<const coff_symbol16 *>(sym));
1040b57cec5SDimitry Andric assert(symSize == sizeof(coff_symbol32));
1050b57cec5SDimitry Andric return COFFSymbolRef(reinterpret_cast<const coff_symbol32 *>(sym));
1060b57cec5SDimitry Andric }
1070b57cec5SDimitry Andric
getRVA()108bdd1243dSDimitry Andric uint64_t DefinedAbsolute::getRVA() { return va - ctx.config.imageBase; }
1090b57cec5SDimitry Andric
makeImportThunk(COFFLinkerContext & ctx,DefinedImportData * s,uint16_t machine)110bdd1243dSDimitry Andric static Chunk *makeImportThunk(COFFLinkerContext &ctx, DefinedImportData *s,
111bdd1243dSDimitry Andric uint16_t machine) {
1120b57cec5SDimitry Andric if (machine == AMD64)
113bdd1243dSDimitry Andric return make<ImportThunkChunkX64>(ctx, s);
1140b57cec5SDimitry Andric if (machine == I386)
115bdd1243dSDimitry Andric return make<ImportThunkChunkX86>(ctx, s);
1160b57cec5SDimitry Andric if (machine == ARM64)
117bdd1243dSDimitry Andric return make<ImportThunkChunkARM64>(ctx, s);
1180b57cec5SDimitry Andric assert(machine == ARMNT);
119bdd1243dSDimitry Andric return make<ImportThunkChunkARM>(ctx, s);
1200b57cec5SDimitry Andric }
1210b57cec5SDimitry Andric
DefinedImportThunk(COFFLinkerContext & ctx,StringRef name,DefinedImportData * s,uint16_t machine)122bdd1243dSDimitry Andric DefinedImportThunk::DefinedImportThunk(COFFLinkerContext &ctx, StringRef name,
123bdd1243dSDimitry Andric DefinedImportData *s, uint16_t machine)
1240b57cec5SDimitry Andric : Defined(DefinedImportThunkKind, name), wrappedSym(s),
125bdd1243dSDimitry Andric data(makeImportThunk(ctx, s, machine)) {}
1260b57cec5SDimitry Andric
getWeakAlias()1270b57cec5SDimitry Andric Defined *Undefined::getWeakAlias() {
1280b57cec5SDimitry Andric // A weak alias may be a weak alias to another symbol, so check recursively.
1290b57cec5SDimitry Andric for (Symbol *a = weakAlias; a; a = cast<Undefined>(a)->weakAlias)
1300b57cec5SDimitry Andric if (auto *d = dyn_cast<Defined>(a))
1310b57cec5SDimitry Andric return d;
1320b57cec5SDimitry Andric return nullptr;
1330b57cec5SDimitry Andric }
1340b57cec5SDimitry Andric
getMemberBuffer()13585868e8aSDimitry Andric MemoryBufferRef LazyArchive::getMemberBuffer() {
1360b57cec5SDimitry Andric Archive::Child c =
137bdd1243dSDimitry Andric CHECK(sym.getMember(), "could not get the member for symbol " +
138bdd1243dSDimitry Andric toCOFFString(file->ctx, sym));
1390b57cec5SDimitry Andric return CHECK(c.getMemoryBufferRef(),
1400b57cec5SDimitry Andric "could not get the buffer for the member defining symbol " +
141bdd1243dSDimitry Andric toCOFFString(file->ctx, sym));
1420b57cec5SDimitry Andric }
1430b57cec5SDimitry Andric } // namespace coff
1440b57cec5SDimitry Andric } // namespace lld
145