Coverage Report

Created: 2018-06-25 02:00

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/lld/wasm/SymbolTable.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- SymbolTable.cpp ----------------------------------------------------===//
2
//
3
//                             The LLVM Linker
4
//
5
// This file is distributed under the University of Illinois Open Source
6
// License. See LICENSE.TXT for details.
7
//
8
//===----------------------------------------------------------------------===//
9
10
#include "SymbolTable.h"
11
#include "Config.h"
12
#include "InputChunks.h"
13
#include "InputGlobal.h"
14
#include "WriterUtils.h"
15
#include "lld/Common/ErrorHandler.h"
16
#include "lld/Common/Memory.h"
17
#include "llvm/ADT/SetVector.h"
18
19
#define DEBUG_TYPE "lld"
20
21
using namespace llvm;
22
using namespace llvm::wasm;
23
using namespace lld;
24
using namespace lld::wasm;
25
26
SymbolTable *lld::wasm::Symtab;
27
28
0
void SymbolTable::addFile(InputFile *File) {
29
0
  log("Processing: " + toString(File));
30
0
  File->parse();
31
0
32
0
  // LLVM bitcode file
33
0
  if (auto *F = dyn_cast<BitcodeFile>(File))
34
0
    BitcodeFiles.push_back(F);
35
0
  else if (auto *F = dyn_cast<ObjFile>(File))
36
0
    ObjectFiles.push_back(F);
37
0
}
38
39
// This function is where all the optimizations of link-time
40
// optimization happens. When LTO is in use, some input files are
41
// not in native object file format but in the LLVM bitcode format.
42
// This function compiles bitcode files into a few big native files
43
// using LLVM functions and replaces bitcode symbols with the results.
44
// Because all bitcode files that the program consists of are passed
45
// to the compiler at once, it can do whole-program optimization.
46
0
void SymbolTable::addCombinedLTOObject() {
47
0
  if (BitcodeFiles.empty())
48
0
    return;
49
0
50
0
  // Compile bitcode files and replace bitcode symbols.
51
0
  LTO.reset(new BitcodeCompiler);
52
0
  for (BitcodeFile *F : BitcodeFiles)
53
0
    LTO->add(*F);
54
0
55
0
  for (StringRef Filename : LTO->compile()) {
56
0
    auto *Obj = make<ObjFile>(MemoryBufferRef(Filename, "lto.tmp"));
57
0
    Obj->parse();
58
0
    ObjectFiles.push_back(Obj);
59
0
  }
60
0
}
61
62
0
void SymbolTable::reportRemainingUndefines() {
63
0
  SetVector<Symbol *> Undefs;
64
0
  for (Symbol *Sym : SymVector) {
65
0
    if (!Sym->isUndefined() || Sym->isWeak())
66
0
      continue;
67
0
    if (Config->AllowUndefinedSymbols.count(Sym->getName()) != 0)
68
0
      continue;
69
0
    if (!Sym->IsUsedInRegularObj)
70
0
      continue;
71
0
    Undefs.insert(Sym);
72
0
  }
73
0
74
0
  if (Undefs.empty())
75
0
    return;
76
0
77
0
  for (ObjFile *File : ObjectFiles)
78
0
    for (Symbol *Sym : File->getSymbols())
79
0
      if (Undefs.count(Sym))
80
0
        error(toString(File) + ": undefined symbol: " + toString(*Sym));
81
0
82
0
  for (Symbol *Sym : Undefs)
83
0
    if (!Sym->getFile())
84
0
      error("undefined symbol: " + toString(*Sym));
85
0
}
86
87
0
Symbol *SymbolTable::find(StringRef Name) {
88
0
  return SymMap.lookup(CachedHashStringRef(Name));
89
0
}
90
91
0
std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) {
92
0
  Symbol *&Sym = SymMap[CachedHashStringRef(Name)];
93
0
  if (Sym)
94
0
    return {Sym, false};
95
0
  Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
96
0
  Sym->IsUsedInRegularObj = false;
97
0
  SymVector.emplace_back(Sym);
98
0
  return {Sym, true};
99
0
}
100
101
static void reportTypeError(const Symbol *Existing, const InputFile *File,
102
0
                            llvm::wasm::WasmSymbolType Type) {
103
0
  error("symbol type mismatch: " + toString(*Existing) + "\n>>> defined as " +
104
0
        toString(Existing->getWasmType()) + " in " +
105
0
        toString(Existing->getFile()) + "\n>>> defined as " + toString(Type) +
106
0
        " in " + toString(File));
107
0
}
108
109
static void checkFunctionType(const Symbol *Existing, const InputFile *File,
110
0
                              const WasmSignature *NewSig) {
111
0
  auto ExistingFunction = dyn_cast<FunctionSymbol>(Existing);
112
0
  if (!ExistingFunction) {
113
0
    reportTypeError(Existing, File, WASM_SYMBOL_TYPE_FUNCTION);
114
0
    return;
115
0
  }
116
0
117
0
  const WasmSignature *OldSig = ExistingFunction->getFunctionType();
118
0
  if (OldSig && NewSig && *NewSig != *OldSig) {
119
0
    warn("function signature mismatch: " + Existing->getName() +
120
0
         "\n>>> defined as " + toString(*OldSig) + " in " +
121
0
         toString(Existing->getFile()) + "\n>>> defined as " +
122
0
         toString(*NewSig) + " in " + toString(File));
123
0
  }
124
0
}
125
126
// Check the type of new symbol matches that of the symbol is replacing.
127
// For functions this can also involve verifying that the signatures match.
128
static void checkGlobalType(const Symbol *Existing, const InputFile *File,
129
0
                            const WasmGlobalType *NewType) {
130
0
  if (!isa<GlobalSymbol>(Existing)) {
131
0
    reportTypeError(Existing, File, WASM_SYMBOL_TYPE_GLOBAL);
132
0
    return;
133
0
  }
134
0
135
0
  const WasmGlobalType *OldType = cast<GlobalSymbol>(Existing)->getGlobalType();
136
0
  if (*NewType != *OldType) {
137
0
    error("Global type mismatch: " + Existing->getName() + "\n>>> defined as " +
138
0
          toString(*OldType) + " in " + toString(Existing->getFile()) +
139
0
          "\n>>> defined as " + toString(*NewType) + " in " + toString(File));
140
0
  }
141
0
}
142
143
0
static void checkDataType(const Symbol *Existing, const InputFile *File) {
144
0
  if (!isa<DataSymbol>(Existing))
145
0
    reportTypeError(Existing, File, WASM_SYMBOL_TYPE_DATA);
146
0
}
147
148
DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name,
149
                                                   uint32_t Flags,
150
0
                                                   InputFunction *Function) {
151
0
  LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << Name << "\n");
152
0
  assert(!find(Name));
153
0
  SyntheticFunctions.emplace_back(Function);
154
0
  return replaceSymbol<DefinedFunction>(insert(Name).first, Name, Flags,
155
0
                                        nullptr, Function);
156
0
}
157
158
DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef Name,
159
0
                                                 uint32_t Flags) {
160
0
  LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << Name << "\n");
161
0
  assert(!find(Name));
162
0
  return replaceSymbol<DefinedData>(insert(Name).first, Name, Flags);
163
0
}
164
165
DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags,
166
0
                                               InputGlobal *Global) {
167
0
  LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << Name << " -> " << Global
168
0
                    << "\n");
169
0
  assert(!find(Name));
170
0
  SyntheticGlobals.emplace_back(Global);
171
0
  return replaceSymbol<DefinedGlobal>(insert(Name).first, Name, Flags, nullptr,
172
0
                                      Global);
173
0
}
174
175
static bool shouldReplace(const Symbol *Existing, InputFile *NewFile,
176
0
                          uint32_t NewFlags) {
177
0
  // If existing symbol is undefined, replace it.
178
0
  if (!Existing->isDefined()) {
179
0
    LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: "
180
0
                      << Existing->getName() << "\n");
181
0
    return true;
182
0
  }
183
0
184
0
  // Now we have two defined symbols. If the new one is weak, we can ignore it.
185
0
  if ((NewFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
186
0
    LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n");
187
0
    return false;
188
0
  }
189
0
190
0
  // If the existing symbol is weak, we should replace it.
191
0
  if (Existing->isWeak()) {
192
0
    LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n");
193
0
    return true;
194
0
  }
195
0
196
0
  // Neither symbol is week. They conflict.
197
0
  error("duplicate symbol: " + toString(*Existing) + "\n>>> defined in " +
198
0
        toString(Existing->getFile()) + "\n>>> defined in " +
199
0
        toString(NewFile));
200
0
  return true;
201
0
}
202
203
Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags,
204
                                        InputFile *File,
205
0
                                        InputFunction *Function) {
206
0
  LLVM_DEBUG(dbgs() << "addDefinedFunction: " << Name << "\n");
207
0
  Symbol *S;
208
0
  bool WasInserted;
209
0
  std::tie(S, WasInserted) = insert(Name);
210
0
211
0
  if (!File || File->kind() == InputFile::ObjectKind)
212
0
    S->IsUsedInRegularObj = true;
213
0
214
0
  if (WasInserted || S->isLazy()) {
215
0
    replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
216
0
    return S;
217
0
  }
218
0
219
0
  if (Function)
220
0
    checkFunctionType(S, File, &Function->Signature);
221
0
222
0
  if (shouldReplace(S, File, Flags))
223
0
    replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
224
0
  return S;
225
0
}
226
227
Symbol *SymbolTable::addDefinedData(StringRef Name, uint32_t Flags,
228
                                    InputFile *File, InputSegment *Segment,
229
0
                                    uint32_t Address, uint32_t Size) {
230
0
  LLVM_DEBUG(dbgs() << "addDefinedData:" << Name << " addr:" << Address
231
0
                    << "\n");
232
0
  Symbol *S;
233
0
  bool WasInserted;
234
0
  std::tie(S, WasInserted) = insert(Name);
235
0
236
0
  if (!File || File->kind() == InputFile::ObjectKind)
237
0
    S->IsUsedInRegularObj = true;
238
0
239
0
  if (WasInserted || S->isLazy()) {
240
0
    replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size);
241
0
    return S;
242
0
  }
243
0
244
0
  checkDataType(S, File);
245
0
246
0
  if (shouldReplace(S, File, Flags))
247
0
    replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size);
248
0
  return S;
249
0
}
250
251
Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Flags,
252
0
                                      InputFile *File, InputGlobal *Global) {
253
0
  LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << Name << "\n");
254
0
  Symbol *S;
255
0
  bool WasInserted;
256
0
  std::tie(S, WasInserted) = insert(Name);
257
0
258
0
  if (!File || File->kind() == InputFile::ObjectKind)
259
0
    S->IsUsedInRegularObj = true;
260
0
261
0
  if (WasInserted || S->isLazy()) {
262
0
    replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global);
263
0
    return S;
264
0
  }
265
0
266
0
  checkGlobalType(S, File, &Global->getType());
267
0
268
0
  if (shouldReplace(S, File, Flags))
269
0
    replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global);
270
0
  return S;
271
0
}
272
273
Symbol *SymbolTable::addUndefinedFunction(StringRef Name, uint32_t Flags,
274
                                          InputFile *File,
275
0
                                          const WasmSignature *Sig) {
276
0
  LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << Name << "\n");
277
0
278
0
  Symbol *S;
279
0
  bool WasInserted;
280
0
  std::tie(S, WasInserted) = insert(Name);
281
0
282
0
  if (!File || File->kind() == InputFile::ObjectKind)
283
0
    S->IsUsedInRegularObj = true;
284
0
285
0
  if (WasInserted)
286
0
    replaceSymbol<UndefinedFunction>(S, Name, Flags, File, Sig);
287
0
  else if (auto *Lazy = dyn_cast<LazySymbol>(S))
288
0
    Lazy->fetch();
289
0
  else if (S->isDefined())
290
0
    checkFunctionType(S, File, Sig);
291
0
  return S;
292
0
}
293
294
Symbol *SymbolTable::addUndefinedData(StringRef Name, uint32_t Flags,
295
0
                                      InputFile *File) {
296
0
  LLVM_DEBUG(dbgs() << "addUndefinedData: " << Name << "\n");
297
0
298
0
  Symbol *S;
299
0
  bool WasInserted;
300
0
  std::tie(S, WasInserted) = insert(Name);
301
0
302
0
  if (WasInserted)
303
0
    replaceSymbol<UndefinedData>(S, Name, Flags, File);
304
0
  else if (auto *Lazy = dyn_cast<LazySymbol>(S))
305
0
    Lazy->fetch();
306
0
  else if (S->isDefined())
307
0
    checkDataType(S, File);
308
0
  return S;
309
0
}
310
311
Symbol *SymbolTable::addUndefinedGlobal(StringRef Name, uint32_t Flags,
312
                                        InputFile *File,
313
0
                                        const WasmGlobalType *Type) {
314
0
  LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << Name << "\n");
315
0
316
0
  Symbol *S;
317
0
  bool WasInserted;
318
0
  std::tie(S, WasInserted) = insert(Name);
319
0
320
0
  if (!File || File->kind() == InputFile::ObjectKind)
321
0
    S->IsUsedInRegularObj = true;
322
0
323
0
  if (WasInserted)
324
0
    replaceSymbol<UndefinedGlobal>(S, Name, Flags, File, Type);
325
0
  else if (auto *Lazy = dyn_cast<LazySymbol>(S))
326
0
    Lazy->fetch();
327
0
  else if (S->isDefined())
328
0
    checkGlobalType(S, File, Type);
329
0
  return S;
330
0
}
331
332
0
void SymbolTable::addLazy(ArchiveFile *File, const Archive::Symbol *Sym) {
333
0
  LLVM_DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n");
334
0
  StringRef Name = Sym->getName();
335
0
336
0
  Symbol *S;
337
0
  bool WasInserted;
338
0
  std::tie(S, WasInserted) = insert(Name);
339
0
340
0
  if (WasInserted) {
341
0
    replaceSymbol<LazySymbol>(S, Name, File, *Sym);
342
0
    return;
343
0
  }
344
0
345
0
  // If there is an existing undefined symbol, load a new one from the archive.
346
0
  if (S->isUndefined()) {
347
0
    LLVM_DEBUG(dbgs() << "replacing existing undefined\n");
348
0
    File->addMember(Sym);
349
0
  }
350
0
}
351
352
0
bool SymbolTable::addComdat(StringRef Name) {
353
0
  return Comdats.insert(CachedHashStringRef(Name)).second;
354
0
}