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