154359Sroberto//===- Symbols.cpp --------------------------------------------------------===//
254359Sroberto//
354359Sroberto// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
454359Sroberto// See https://llvm.org/LICENSE.txt for license information.
554359Sroberto// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
682498Sroberto//
754359Sroberto//===----------------------------------------------------------------------===//
854359Sroberto
954359Sroberto#include "Symbols.h"
1054359Sroberto#include "COFFLinkerContext.h"
1154359Sroberto#include "InputFiles.h"
1254359Sroberto#include "lld/Common/ErrorHandler.h"
1354359Sroberto#include "lld/Common/Memory.h"
1454359Sroberto#include "lld/Common/Strings.h"
1554359Sroberto#include "llvm/ADT/STLExtras.h"
1654359Sroberto#include "llvm/Demangle/Demangle.h"
1754359Sroberto#include "llvm/Support/Debug.h"
1854359Sroberto#include "llvm/Support/raw_ostream.h"
1954359Sroberto
2054359Srobertousing namespace llvm;
2154359Srobertousing namespace llvm::object;
2254359Sroberto
2354359Srobertousing namespace lld::coff;
2454359Sroberto
2554359Srobertonamespace lld {
2654359Sroberto
2754359Srobertostatic_assert(sizeof(SymbolUnion) <= 48,
2854359Sroberto              "symbols should be optimized for memory usage");
2954359Sroberto
3054359Sroberto// Returns a symbol name for an error message.
3154359Srobertostatic std::string maybeDemangleSymbol(const COFFLinkerContext &ctx,
3254359Sroberto                                       StringRef symName) {
3354359Sroberto  if (ctx.config.demangle) {
3454359Sroberto    std::string prefix;
3554359Sroberto    StringRef prefixless = symName;
3654359Sroberto    if (prefixless.consume_front("__imp_"))
3754359Sroberto      prefix = "__declspec(dllimport) ";
3854359Sroberto    StringRef demangleInput = prefixless;
3954359Sroberto    if (ctx.config.machine == I386)
4054359Sroberto      demangleInput.consume_front("_");
4154359Sroberto    std::string demangled = demangle(demangleInput);
4254359Sroberto    if (demangled != demangleInput)
4354359Sroberto      return prefix + demangled;
4454359Sroberto    return (prefix + prefixless).str();
4554359Sroberto  }
4654359Sroberto  return std::string(symName);
4754359Sroberto}
4854359Srobertostd::string toString(const COFFLinkerContext &ctx, coff::Symbol &b) {
4954359Sroberto  return maybeDemangleSymbol(ctx, b.getName());
5054359Sroberto}
5154359Srobertostd::string toCOFFString(const COFFLinkerContext &ctx,
5254359Sroberto                         const Archive::Symbol &b) {
5354359Sroberto  return maybeDemangleSymbol(ctx, b.getName());
5454359Sroberto}
5554359Sroberto
5654359Srobertonamespace coff {
5754359Sroberto
5854359Srobertovoid Symbol::computeName() {
5954359Sroberto  assert(nameData == nullptr &&
6054359Sroberto         "should only compute the name once for DefinedCOFF symbols");
6154359Sroberto  auto *d = cast<DefinedCOFF>(this);
6254359Sroberto  StringRef nameStr =
6354359Sroberto      check(cast<ObjFile>(d->file)->getCOFFObj()->getSymbolName(d->sym));
6454359Sroberto  nameData = nameStr.data();
6554359Sroberto  nameSize = nameStr.size();
6654359Sroberto  assert(nameSize == nameStr.size() && "name length truncated");
6754359Sroberto}
6854359Sroberto
6954359SrobertoInputFile *Symbol::getFile() {
7054359Sroberto  if (auto *sym = dyn_cast<DefinedCOFF>(this))
7154359Sroberto    return sym->file;
7254359Sroberto  if (auto *sym = dyn_cast<LazyArchive>(this))
7354359Sroberto    return sym->file;
7454359Sroberto  if (auto *sym = dyn_cast<LazyObject>(this))
7554359Sroberto    return sym->file;
7654359Sroberto  if (auto *sym = dyn_cast<LazyDLLSymbol>(this))
7754359Sroberto    return sym->file;
7854359Sroberto  return nullptr;
7954359Sroberto}
8054359Sroberto
8154359Srobertobool Symbol::isLive() const {
8254359Sroberto  if (auto *r = dyn_cast<DefinedRegular>(this))
8354359Sroberto    return r->getChunk()->live;
8454359Sroberto  if (auto *imp = dyn_cast<DefinedImportData>(this))
8554359Sroberto    return imp->file->live;
8654359Sroberto  if (auto *imp = dyn_cast<DefinedImportThunk>(this))
8754359Sroberto    return imp->wrappedSym->file->thunkLive;
8854359Sroberto  // Assume any other kind of symbol is live.
8954359Sroberto  return true;
9054359Sroberto}
9154359Sroberto
9254359Sroberto// MinGW specific.
9354359Srobertovoid Symbol::replaceKeepingName(Symbol *other, size_t size) {
9454359Sroberto  StringRef origName = getName();
9554359Sroberto  memcpy(this, other, size);
9654359Sroberto  nameData = origName.data();
9754359Sroberto  nameSize = origName.size();
9854359Sroberto}
9954359Sroberto
10054359SrobertoCOFFSymbolRef DefinedCOFF::getCOFFSymbol() {
10154359Sroberto  size_t symSize = cast<ObjFile>(file)->getCOFFObj()->getSymbolTableEntrySize();
10254359Sroberto  if (symSize == sizeof(coff_symbol16))
10354359Sroberto    return COFFSymbolRef(reinterpret_cast<const coff_symbol16 *>(sym));
10454359Sroberto  assert(symSize == sizeof(coff_symbol32));
10554359Sroberto  return COFFSymbolRef(reinterpret_cast<const coff_symbol32 *>(sym));
10654359Sroberto}
10754359Sroberto
10854359Srobertouint64_t DefinedAbsolute::getRVA() { return va - ctx.config.imageBase; }
10954359Sroberto
11054359Srobertostatic Chunk *makeImportThunk(COFFLinkerContext &ctx, DefinedImportData *s,
11154359Sroberto                              uint16_t machine) {
11254359Sroberto  if (machine == AMD64)
11354359Sroberto    return make<ImportThunkChunkX64>(ctx, s);
11454359Sroberto  if (machine == I386)
11554359Sroberto    return make<ImportThunkChunkX86>(ctx, s);
11654359Sroberto  if (machine == ARM64)
11754359Sroberto    return make<ImportThunkChunkARM64>(ctx, s);
11854359Sroberto  assert(machine == ARMNT);
11954359Sroberto  return make<ImportThunkChunkARM>(ctx, s);
12054359Sroberto}
12154359Sroberto
12254359SrobertoDefinedImportThunk::DefinedImportThunk(COFFLinkerContext &ctx, StringRef name,
12354359Sroberto                                       DefinedImportData *s, uint16_t machine)
12454359Sroberto    : Defined(DefinedImportThunkKind, name), wrappedSym(s),
12554359Sroberto      data(makeImportThunk(ctx, s, machine)) {}
12654359Sroberto
12754359SrobertoDefined *Undefined::getWeakAlias() {
12854359Sroberto  // A weak alias may be a weak alias to another symbol, so check recursively.
12954359Sroberto  for (Symbol *a = weakAlias; a; a = cast<Undefined>(a)->weakAlias)
13054359Sroberto    if (auto *d = dyn_cast<Defined>(a))
13154359Sroberto      return d;
13254359Sroberto  return nullptr;
13354359Sroberto}
13454359Sroberto
13554359SrobertoMemoryBufferRef LazyArchive::getMemberBuffer() {
13654359Sroberto  Archive::Child c =
13754359Sroberto      CHECK(sym.getMember(), "could not get the member for symbol " +
13854359Sroberto                                 toCOFFString(file->ctx, sym));
13954359Sroberto  return CHECK(c.getMemoryBufferRef(),
14054359Sroberto               "could not get the buffer for the member defining symbol " +
14154359Sroberto                   toCOFFString(file->ctx, sym));
14254359Sroberto}
14354359Sroberto} // namespace coff
14454359Sroberto} // namespace lld
14554359Sroberto