aboutsummaryrefslogtreecommitdiff
path: root/COFF/Symbols.cpp
blob: b3975a59cb66b091731c4c8c29fdff0b0fb64ab9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
//===- Symbols.cpp --------------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "Error.h"
#include "InputFiles.h"
#include "Symbols.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm::object;
using llvm::sys::fs::identify_magic;
using llvm::sys::fs::file_magic;

namespace lld {
namespace coff {

StringRef SymbolBody::getName() {
  // DefinedCOFF names are read lazily for a performance reason.
  // Non-external symbol names are never used by the linker except for logging
  // or debugging. Their internal references are resolved not by name but by
  // symbol index. And because they are not external, no one can refer them by
  // name. Object files contain lots of non-external symbols, and creating
  // StringRefs for them (which involves lots of strlen() on the string table)
  // is a waste of time.
  if (Name.empty()) {
    auto *D = cast<DefinedCOFF>(this);
    D->File->getCOFFObj()->getSymbolName(D->Sym, Name);
  }
  return Name;
}

// Returns 1, 0 or -1 if this symbol should take precedence
// over the Other, tie or lose, respectively.
int SymbolBody::compare(SymbolBody *Other) {
  Kind LK = kind(), RK = Other->kind();

  // Normalize so that the smaller kind is on the left.
  if (LK > RK)
    return -Other->compare(this);

  // First handle comparisons between two different kinds.
  if (LK != RK) {
    if (RK > LastDefinedKind) {
      if (LK == LazyKind && cast<Undefined>(Other)->WeakAlias)
        return -1;

      // The LHS is either defined or lazy and so it wins.
      assert((LK <= LastDefinedKind || LK == LazyKind) && "Bad kind!");
      return 1;
    }

    // Bitcode has special complexities.
    if (RK == DefinedBitcodeKind) {
      auto *RHS = cast<DefinedBitcode>(Other);

      switch (LK) {
      case DefinedCommonKind:
        return 1;

      case DefinedRegularKind:
        // As an approximation, regular symbols win over bitcode symbols,
        // but we definitely have a conflict if the regular symbol is not
        // replaceable and neither is the bitcode symbol. We do not
        // replicate the rest of the symbol resolution logic here; symbol
        // resolution will be done accurately after lowering bitcode symbols
        // to regular symbols in addCombinedLTOObject().
        if (cast<DefinedRegular>(this)->isCOMDAT() || RHS->IsReplaceable)
          return 1;

        // Fallthrough to the default of a tie otherwise.
      default:
        return 0;
      }
    }

    // Either of the object file kind will trump a higher kind.
    if (LK <= LastDefinedCOFFKind)
      return 1;

    // The remaining kind pairs are ties amongst defined symbols.
    return 0;
  }

  // Now handle the case where the kinds are the same.
  switch (LK) {
  case DefinedRegularKind: {
    auto *LHS = cast<DefinedRegular>(this);
    auto *RHS = cast<DefinedRegular>(Other);
    if (LHS->isCOMDAT() && RHS->isCOMDAT())
      return LHS->getFileIndex() < RHS->getFileIndex() ? 1 : -1;
    return 0;
  }

  case DefinedCommonKind: {
    auto *LHS = cast<DefinedCommon>(this);
    auto *RHS = cast<DefinedCommon>(Other);
    if (LHS->getSize() == RHS->getSize())
      return LHS->getFileIndex() < RHS->getFileIndex() ? 1 : -1;
    return LHS->getSize() > RHS->getSize() ? 1 : -1;
  }

  case DefinedBitcodeKind: {
    auto *LHS = cast<DefinedBitcode>(this);
    auto *RHS = cast<DefinedBitcode>(Other);
    // If both are non-replaceable, we have a tie.
    if (!LHS->IsReplaceable && !RHS->IsReplaceable)
      return 0;

    // Non-replaceable symbols win, but even two replaceable symboles don't
    // tie. If both symbols are replaceable, choice is arbitrary.
    if (RHS->IsReplaceable && LHS->IsReplaceable)
      return uintptr_t(LHS) < uintptr_t(RHS) ? 1 : -1;
    return LHS->IsReplaceable ? -1 : 1;
  }

  case LazyKind: {
    // Don't tie, pick the earliest.
    auto *LHS = cast<Lazy>(this);
    auto *RHS = cast<Lazy>(Other);
    return LHS->getFileIndex() < RHS->getFileIndex() ? 1 : -1;
  }

  case UndefinedKind: {
    auto *LHS = cast<Undefined>(this);
    auto *RHS = cast<Undefined>(Other);
    // Tie if both undefined symbols have different weak aliases.
    if (LHS->WeakAlias && RHS->WeakAlias) {
      if (LHS->WeakAlias->repl() != RHS->WeakAlias->repl())
        return 0;
      return uintptr_t(LHS) < uintptr_t(RHS) ? 1 : -1;
    }
    return LHS->WeakAlias ? 1 : -1;
  }

  case DefinedLocalImportKind:
  case DefinedImportThunkKind:
  case DefinedImportDataKind:
  case DefinedAbsoluteKind:
    // These all simply tie.
    return 0;
  }
  llvm_unreachable("unknown symbol kind");
}

std::string SymbolBody::getDebugName() {
  std::string N = getName().str();
  if (auto *D = dyn_cast<DefinedCOFF>(this)) {
    N += " ";
    N += D->File->getShortName();
  } else if (auto *D = dyn_cast<DefinedBitcode>(this)) {
    N += " ";
    N += D->File->getShortName();
  }
  return N;
}

uint64_t Defined::getRVA() {
  switch (kind()) {
  case DefinedAbsoluteKind:
    return cast<DefinedAbsolute>(this)->getRVA();
  case DefinedImportDataKind:
    return cast<DefinedImportData>(this)->getRVA();
  case DefinedImportThunkKind:
    return cast<DefinedImportThunk>(this)->getRVA();
  case DefinedLocalImportKind:
    return cast<DefinedLocalImport>(this)->getRVA();
  case DefinedCommonKind:
    return cast<DefinedCommon>(this)->getRVA();
  case DefinedRegularKind:
    return cast<DefinedRegular>(this)->getRVA();

  case DefinedBitcodeKind:
    llvm_unreachable("There is no address for a bitcode symbol.");
  case LazyKind:
  case UndefinedKind:
    llvm_unreachable("Cannot get the address for an undefined symbol.");
  }
  llvm_unreachable("unknown symbol kind");
}

uint64_t Defined::getFileOff() {
  switch (kind()) {
  case DefinedImportDataKind:
    return cast<DefinedImportData>(this)->getFileOff();
  case DefinedImportThunkKind:
    return cast<DefinedImportThunk>(this)->getFileOff();
  case DefinedLocalImportKind:
    return cast<DefinedLocalImport>(this)->getFileOff();
  case DefinedCommonKind:
    return cast<DefinedCommon>(this)->getFileOff();
  case DefinedRegularKind:
    return cast<DefinedRegular>(this)->getFileOff();

  case DefinedBitcodeKind:
    llvm_unreachable("There is no file offset for a bitcode symbol.");
  case DefinedAbsoluteKind:
    llvm_unreachable("Cannot get a file offset for an absolute symbol.");
  case LazyKind:
  case UndefinedKind:
    llvm_unreachable("Cannot get a file offset for an undefined symbol.");
  }
  llvm_unreachable("unknown symbol kind");
}

ErrorOr<std::unique_ptr<InputFile>> Lazy::getMember() {
  auto MBRefOrErr = File->getMember(&Sym);
  if (auto EC = MBRefOrErr.getError())
    return EC;
  MemoryBufferRef MBRef = MBRefOrErr.get();

  // getMember returns an empty buffer if the member was already
  // read from the library.
  if (MBRef.getBuffer().empty())
    return std::unique_ptr<InputFile>(nullptr);

  file_magic Magic = identify_magic(MBRef.getBuffer());
  if (Magic == file_magic::coff_import_library)
    return std::unique_ptr<InputFile>(new ImportFile(MBRef));

  std::unique_ptr<InputFile> Obj;
  if (Magic == file_magic::coff_object) {
    Obj.reset(new ObjectFile(MBRef));
  } else if (Magic == file_magic::bitcode) {
    Obj.reset(new BitcodeFile(MBRef));
  } else {
    llvm::errs() << File->getName() << ": unknown file type\n";
    return make_error_code(LLDError::InvalidFile);
  }

  Obj->setParentName(File->getName());
  return std::move(Obj);
}

Defined *Undefined::getWeakAlias() {
  // A weak alias may be a weak alias to another symbol, so check recursively.
  for (SymbolBody *A = WeakAlias; A; A = cast<Undefined>(A)->WeakAlias)
    if (auto *D = dyn_cast<Defined>(A->repl()))
      return D;
  return nullptr;
}

} // namespace coff
} // namespace lld