1//===- Symbols.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#include "Symbols.h"
10#include "InputFiles.h"
11#include "lld/Common/ErrorHandler.h"
12#include "lld/Common/Memory.h"
13#include "lld/Common/Strings.h"
14#include "llvm/ADT/STLExtras.h"
15#include "llvm/Demangle/Demangle.h"
16#include "llvm/Support/Debug.h"
17#include "llvm/Support/raw_ostream.h"
18
19using namespace llvm;
20using namespace llvm::object;
21
22using namespace lld::coff;
23
24namespace lld {
25
26static_assert(sizeof(SymbolUnion) <= 48,
27              "symbols should be optimized for memory usage");
28
29// Returns a symbol name for an error message.
30static std::string maybeDemangleSymbol(StringRef symName) {
31  if (config->demangle) {
32    std::string prefix;
33    StringRef prefixless = symName;
34    if (prefixless.consume_front("__imp_"))
35      prefix = "__declspec(dllimport) ";
36    StringRef demangleInput = prefixless;
37    if (config->machine == I386)
38      demangleInput.consume_front("_");
39    std::string demangled = demangle(demangleInput);
40    if (demangled != demangleInput)
41      return prefix + demangle(demangleInput);
42    return (prefix + prefixless).str();
43  }
44  return symName;
45}
46std::string toString(coff::Symbol &b) {
47  return maybeDemangleSymbol(b.getName());
48}
49std::string toCOFFString(const Archive::Symbol &b) {
50  return maybeDemangleSymbol(b.getName());
51}
52
53namespace coff {
54
55StringRef Symbol::getName() {
56  // COFF symbol names are read lazily for a performance reason.
57  // Non-external symbol names are never used by the linker except for logging
58  // or debugging. Their internal references are resolved not by name but by
59  // symbol index. And because they are not external, no one can refer them by
60  // name. Object files contain lots of non-external symbols, and creating
61  // StringRefs for them (which involves lots of strlen() on the string table)
62  // is a waste of time.
63  if (nameData == nullptr) {
64    auto *d = cast<DefinedCOFF>(this);
65    StringRef nameStr;
66    cast<ObjFile>(d->file)->getCOFFObj()->getSymbolName(d->sym, nameStr);
67    nameData = nameStr.data();
68    nameSize = nameStr.size();
69    assert(nameSize == nameStr.size() && "name length truncated");
70  }
71  return StringRef(nameData, nameSize);
72}
73
74InputFile *Symbol::getFile() {
75  if (auto *sym = dyn_cast<DefinedCOFF>(this))
76    return sym->file;
77  if (auto *sym = dyn_cast<LazyArchive>(this))
78    return sym->file;
79  if (auto *sym = dyn_cast<LazyObject>(this))
80    return sym->file;
81  return nullptr;
82}
83
84bool Symbol::isLive() const {
85  if (auto *r = dyn_cast<DefinedRegular>(this))
86    return r->getChunk()->live;
87  if (auto *imp = dyn_cast<DefinedImportData>(this))
88    return imp->file->live;
89  if (auto *imp = dyn_cast<DefinedImportThunk>(this))
90    return imp->wrappedSym->file->thunkLive;
91  // Assume any other kind of symbol is live.
92  return true;
93}
94
95// MinGW specific.
96void Symbol::replaceKeepingName(Symbol *other, size_t size) {
97  StringRef origName = getName();
98  memcpy(this, other, size);
99  nameData = origName.data();
100  nameSize = origName.size();
101}
102
103COFFSymbolRef DefinedCOFF::getCOFFSymbol() {
104  size_t symSize = cast<ObjFile>(file)->getCOFFObj()->getSymbolTableEntrySize();
105  if (symSize == sizeof(coff_symbol16))
106    return COFFSymbolRef(reinterpret_cast<const coff_symbol16 *>(sym));
107  assert(symSize == sizeof(coff_symbol32));
108  return COFFSymbolRef(reinterpret_cast<const coff_symbol32 *>(sym));
109}
110
111uint16_t DefinedAbsolute::numOutputSections;
112
113static Chunk *makeImportThunk(DefinedImportData *s, uint16_t machine) {
114  if (machine == AMD64)
115    return make<ImportThunkChunkX64>(s);
116  if (machine == I386)
117    return make<ImportThunkChunkX86>(s);
118  if (machine == ARM64)
119    return make<ImportThunkChunkARM64>(s);
120  assert(machine == ARMNT);
121  return make<ImportThunkChunkARM>(s);
122}
123
124DefinedImportThunk::DefinedImportThunk(StringRef name, DefinedImportData *s,
125                                       uint16_t machine)
126    : Defined(DefinedImportThunkKind, name), wrappedSym(s),
127      data(makeImportThunk(s, machine)) {}
128
129Defined *Undefined::getWeakAlias() {
130  // A weak alias may be a weak alias to another symbol, so check recursively.
131  for (Symbol *a = weakAlias; a; a = cast<Undefined>(a)->weakAlias)
132    if (auto *d = dyn_cast<Defined>(a))
133      return d;
134  return nullptr;
135}
136
137MemoryBufferRef LazyArchive::getMemberBuffer() {
138  Archive::Child c =
139    CHECK(sym.getMember(),
140          "could not get the member for symbol " + toCOFFString(sym));
141  return CHECK(c.getMemoryBufferRef(),
142      "could not get the buffer for the member defining symbol " +
143      toCOFFString(sym));
144}
145} // namespace coff
146} // namespace lld
147