Coverage Report

Created: 2019-07-24 05:18

/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
// 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 "SymbolTable.h"
10
#include "Config.h"
11
#include "InputChunks.h"
12
#include "InputEvent.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 llvm::object;
24
using namespace lld;
25
using namespace lld::wasm;
26
27
SymbolTable *lld::wasm::symtab;
28
29
327
void SymbolTable::addFile(InputFile *file) {
30
327
  log("Processing: " + toString(file));
31
327
32
327
  // .a file
33
327
  if (auto *f = dyn_cast<ArchiveFile>(file)) {
34
16
    f->parse();
35
16
    return;
36
16
  }
37
311
38
311
  // .so file
39
311
  if (auto *f = dyn_cast<SharedFile>(file)) {
40
1
    sharedFiles.push_back(f);
41
1
    return;
42
1
  }
43
310
44
310
  if (config->trace)
45
2
    message(toString(file));
46
310
47
310
  // LLVM bitcode file
48
310
  if (auto *f = dyn_cast<BitcodeFile>(file)) {
49
43
    f->parse();
50
43
    bitcodeFiles.push_back(f);
51
43
    return;
52
43
  }
53
267
54
267
  // Regular object file
55
267
  auto *f = cast<ObjFile>(file);
56
267
  f->parse(false);
57
267
  objectFiles.push_back(f);
58
267
}
59
60
// This function is where all the optimizations of link-time
61
// optimization happens. When LTO is in use, some input files are
62
// not in native object file format but in the LLVM bitcode format.
63
// This function compiles bitcode files into a few big native files
64
// using LLVM functions and replaces bitcode symbols with the results.
65
// Because all bitcode files that the program consists of are passed
66
// to the compiler at once, it can do whole-program optimization.
67
199
void SymbolTable::addCombinedLTOObject() {
68
199
  if (bitcodeFiles.empty())
69
168
    return;
70
31
71
31
  // Compile bitcode files and replace bitcode symbols.
72
31
  lto.reset(new BitcodeCompiler);
73
31
  for (BitcodeFile *f : bitcodeFiles)
74
42
    lto->add(*f);
75
31
76
48
  for (StringRef filename : lto->compile()) {
77
48
    auto *obj = make<ObjFile>(MemoryBufferRef(filename, "lto.tmp"), "");
78
48
    obj->parse(true);
79
48
    objectFiles.push_back(obj);
80
48
  }
81
31
}
82
83
861
Symbol *SymbolTable::find(StringRef name) {
84
861
  auto it = symMap.find(CachedHashStringRef(name));
85
861
  if (it == symMap.end() || 
it->second == -1283
)
86
578
    return nullptr;
87
283
  return symVector[it->second];
88
283
}
89
90
8
void SymbolTable::replace(StringRef name, Symbol* sym) {
91
8
  auto it = symMap.find(CachedHashStringRef(name));
92
8
  symVector[it->second] = sym;
93
8
}
94
95
1.62k
std::pair<Symbol *, bool> SymbolTable::insertName(StringRef name) {
96
1.62k
  bool trace = false;
97
1.62k
  auto p = symMap.insert({CachedHashStringRef(name), (int)symVector.size()});
98
1.62k
  int &symIndex = p.first->second;
99
1.62k
  bool isNew = p.second;
100
1.62k
  if (symIndex == -1) {
101
5
    symIndex = symVector.size();
102
5
    trace = true;
103
5
    isNew = true;
104
5
  }
105
1.62k
106
1.62k
  if (!isNew)
107
191
    return {symVector[symIndex], false};
108
1.42k
109
1.42k
  Symbol *sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
110
1.42k
  sym->isUsedInRegularObj = false;
111
1.42k
  sym->canInline = true;
112
1.42k
  sym->traced = trace;
113
1.42k
  symVector.emplace_back(sym);
114
1.42k
  return {sym, true};
115
1.42k
}
116
117
std::pair<Symbol *, bool> SymbolTable::insert(StringRef name,
118
888
                                              const InputFile *file) {
119
888
  Symbol *s;
120
888
  bool wasInserted;
121
888
  std::tie(s, wasInserted) = insertName(name);
122
888
123
888
  if (!file || 
file->kind() == InputFile::ObjectKind866
)
124
823
    s->isUsedInRegularObj = true;
125
888
126
888
  return {s, wasInserted};
127
888
}
128
129
static void reportTypeError(const Symbol *existing, const InputFile *file,
130
1
                            llvm::wasm::WasmSymbolType type) {
131
1
  error("symbol type mismatch: " + toString(*existing) + "\n>>> defined as " +
132
1
        toString(existing->getWasmType()) + " in " +
133
1
        toString(existing->getFile()) + "\n>>> defined as " + toString(type) +
134
1
        " in " + toString(file));
135
1
}
136
137
// Check the type of new symbol matches that of the symbol is replacing.
138
// Returns true if the function types match, false is there is a singature
139
// mismatch.
140
static bool signatureMatches(FunctionSymbol *existing,
141
93
                             const WasmSignature *newSig) {
142
93
  const WasmSignature *oldSig = existing->signature;
143
93
144
93
  // If either function is missing a signature (this happend for bitcode
145
93
  // symbols) then assume they match.  Any mismatch will be reported later
146
93
  // when the LTO objects are added.
147
93
  if (!newSig || 
!oldSig92
)
148
40
    return true;
149
53
150
53
  return *newSig == *oldSig;
151
53
}
152
153
static void checkGlobalType(const Symbol *existing, const InputFile *file,
154
8
                            const WasmGlobalType *newType) {
155
8
  if (!isa<GlobalSymbol>(existing)) {
156
0
    reportTypeError(existing, file, WASM_SYMBOL_TYPE_GLOBAL);
157
0
    return;
158
0
  }
159
8
160
8
  const WasmGlobalType *oldType = cast<GlobalSymbol>(existing)->getGlobalType();
161
8
  if (*newType != *oldType) {
162
0
    error("Global type mismatch: " + existing->getName() + "\n>>> defined as " +
163
0
          toString(*oldType) + " in " + toString(existing->getFile()) +
164
0
          "\n>>> defined as " + toString(*newType) + " in " + toString(file));
165
0
  }
166
8
}
167
168
static void checkEventType(const Symbol *existing, const InputFile *file,
169
                           const WasmEventType *newType,
170
1
                           const WasmSignature *newSig) {
171
1
  auto existingEvent = dyn_cast<EventSymbol>(existing);
172
1
  if (!isa<EventSymbol>(existing)) {
173
0
    reportTypeError(existing, file, WASM_SYMBOL_TYPE_EVENT);
174
0
    return;
175
0
  }
176
1
177
1
  const WasmEventType *oldType = cast<EventSymbol>(existing)->getEventType();
178
1
  const WasmSignature *oldSig = existingEvent->signature;
179
1
  if (newType->Attribute != oldType->Attribute)
180
0
    error("Event type mismatch: " + existing->getName() + "\n>>> defined as " +
181
0
          toString(*oldType) + " in " + toString(existing->getFile()) +
182
0
          "\n>>> defined as " + toString(*newType) + " in " + toString(file));
183
1
  if (*newSig != *oldSig)
184
0
    warn("Event signature mismatch: " + existing->getName() +
185
0
         "\n>>> defined as " + toString(*oldSig) + " in " +
186
0
         toString(existing->getFile()) + "\n>>> defined as " +
187
0
         toString(*newSig) + " in " + toString(file));
188
1
}
189
190
14
static void checkDataType(const Symbol *existing, const InputFile *file) {
191
14
  if (!isa<DataSymbol>(existing))
192
0
    reportTypeError(existing, file, WASM_SYMBOL_TYPE_DATA);
193
14
}
194
195
DefinedFunction *SymbolTable::addSyntheticFunction(StringRef name,
196
                                                   uint32_t flags,
197
229
                                                   InputFunction *function) {
198
229
  LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << name << "\n");
199
229
  assert(!find(name));
200
229
  syntheticFunctions.emplace_back(function);
201
229
  return replaceSymbol<DefinedFunction>(insertName(name).first, name,
202
229
                                        flags, nullptr, function);
203
229
}
204
205
// Adds an optional, linker generated, data symbols.  The symbol will only be
206
// added if there is an undefine reference to it, or if it is explictly exported
207
// via the --export flag.  Otherwise we don't add the symbol and return nullptr.
208
DefinedData *SymbolTable::addOptionalDataSymbol(StringRef name, uint32_t value,
209
568
                                                uint32_t flags) {
210
568
  Symbol *s = find(name);
211
568
  if (!s && 
(566
config->exportAll566
||
config->exportedSymbols.count(name) != 0559
))
212
15
    s = insertName(name).first;
213
553
  else if (!s || 
s->isDefined()2
)
214
551
    return nullptr;
215
17
  LLVM_DEBUG(dbgs() << "addOptionalDataSymbol: " << name << "\n");
216
17
  auto *rtn = replaceSymbol<DefinedData>(s, name, flags);
217
17
  rtn->setVirtualAddress(value);
218
17
  rtn->referenced = true;
219
17
  return rtn;
220
17
}
221
222
DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef name,
223
194
                                                 uint32_t flags) {
224
194
  LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << name << "\n");
225
194
  assert(!find(name));
226
194
  return replaceSymbol<DefinedData>(insertName(name).first, name, flags);
227
194
}
228
229
DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef name, uint32_t flags,
230
242
                                               InputGlobal *global) {
231
242
  LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << name << " -> " << global
232
242
                    << "\n");
233
242
  assert(!find(name));
234
242
  syntheticGlobals.emplace_back(global);
235
242
  return replaceSymbol<DefinedGlobal>(insertName(name).first, name, flags,
236
242
                                      nullptr, global);
237
242
}
238
239
static bool shouldReplace(const Symbol *existing, InputFile *newFile,
240
93
                          uint32_t newFlags) {
241
93
  // If existing symbol is undefined, replace it.
242
93
  if (!existing->isDefined()) {
243
84
    LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: "
244
84
                      << existing->getName() << "\n");
245
84
    return true;
246
84
  }
247
9
248
9
  // Now we have two defined symbols. If the new one is weak, we can ignore it.
249
9
  if ((newFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
250
6
    LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n");
251
6
    return false;
252
6
  }
253
3
254
3
  // If the existing symbol is weak, we should replace it.
255
3
  if (existing->isWeak()) {
256
0
    LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n");
257
0
    return true;
258
0
  }
259
3
260
3
  // Neither symbol is week. They conflict.
261
3
  error("duplicate symbol: " + toString(*existing) + "\n>>> defined in " +
262
3
        toString(existing->getFile()) + "\n>>> defined in " +
263
3
        toString(newFile));
264
3
  return true;
265
3
}
266
267
Symbol *SymbolTable::addDefinedFunction(StringRef name, uint32_t flags,
268
                                        InputFile *file,
269
543
                                        InputFunction *function) {
270
543
  LLVM_DEBUG(dbgs() << "addDefinedFunction: " << name << " ["
271
543
                    << (function ? toString(function->signature) : "none")
272
543
                    << "]\n");
273
543
  Symbol *s;
274
543
  bool wasInserted;
275
543
  std::tie(s, wasInserted) = insert(name, file);
276
543
277
543
  auto replaceSym = [&](Symbol *sym) {
278
538
    // If the new defined function doesn't have signture (i.e. bitcode
279
538
    // functions) but the old symbol does, then preserve the old signature
280
538
    const WasmSignature *oldSig = s->getSignature();
281
538
    auto* newSym = replaceSymbol<DefinedFunction>(sym, name, flags, file, function);
282
538
    if (!newSym->signature)
283
45
      newSym->signature = oldSig;
284
538
  };
285
543
286
543
  if (wasInserted || 
s->isLazy()109
) {
287
451
    replaceSym(s);
288
451
    return s;
289
451
  }
290
92
291
92
  auto existingFunction = dyn_cast<FunctionSymbol>(s);
292
92
  if (!existingFunction) {
293
1
    reportTypeError(s, file, WASM_SYMBOL_TYPE_FUNCTION);
294
1
    return s;
295
1
  }
296
91
297
91
  bool checkSig = true;
298
91
  if (auto ud = dyn_cast<UndefinedFunction>(existingFunction))
299
84
    checkSig = ud->isCalledDirectly;
300
91
301
91
  if (checkSig && 
function86
&&
!signatureMatches(existingFunction, &function->signature)74
) {
302
8
    Symbol* variant;
303
8
    if (getFunctionVariant(s, &function->signature, file, &variant))
304
7
      // New variant, always replace
305
7
      replaceSym(variant);
306
1
    else if (shouldReplace(s, file, flags))
307
0
      // Variant already exists, replace it after checking shouldReplace
308
0
      replaceSym(variant);
309
8
310
8
    // This variant we found take the place in the symbol table as the primary
311
8
    // variant.
312
8
    replace(name, variant);
313
8
    return variant;
314
8
  }
315
83
316
83
  // Existing function with matching signature.
317
83
  if (shouldReplace(s, file, flags))
318
80
    replaceSym(s);
319
83
320
83
  return s;
321
83
}
322
323
Symbol *SymbolTable::addDefinedData(StringRef name, uint32_t flags,
324
                                    InputFile *file, InputSegment *segment,
325
151
                                    uint32_t address, uint32_t size) {
326
151
  LLVM_DEBUG(dbgs() << "addDefinedData:" << name << " addr:" << address
327
151
                    << "\n");
328
151
  Symbol *s;
329
151
  bool wasInserted;
330
151
  std::tie(s, wasInserted) = insert(name, file);
331
151
332
151
  auto replaceSym = [&]() {
333
150
    replaceSymbol<DefinedData>(s, name, flags, file, segment, address, size);
334
150
  };
335
151
336
151
  if (wasInserted || 
s->isLazy()8
) {
337
143
    replaceSym();
338
143
    return s;
339
143
  }
340
8
341
8
  checkDataType(s, file);
342
8
343
8
  if (shouldReplace(s, file, flags))
344
7
    replaceSym();
345
8
  return s;
346
8
}
347
348
Symbol *SymbolTable::addDefinedGlobal(StringRef name, uint32_t flags,
349
4
                                      InputFile *file, InputGlobal *global) {
350
4
  LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << name << "\n");
351
4
352
4
  Symbol *s;
353
4
  bool wasInserted;
354
4
  std::tie(s, wasInserted) = insert(name, file);
355
4
356
4
  auto replaceSym = [&]() {
357
4
    replaceSymbol<DefinedGlobal>(s, name, flags, file, global);
358
4
  };
359
4
360
4
  if (wasInserted || 
s->isLazy()0
) {
361
4
    replaceSym();
362
4
    return s;
363
4
  }
364
0
365
0
  checkGlobalType(s, file, &global->getType());
366
0
367
0
  if (shouldReplace(s, file, flags))
368
0
    replaceSym();
369
0
  return s;
370
0
}
371
372
Symbol *SymbolTable::addDefinedEvent(StringRef name, uint32_t flags,
373
2
                                     InputFile *file, InputEvent *event) {
374
2
  LLVM_DEBUG(dbgs() << "addDefinedEvent:" << name << "\n");
375
2
376
2
  Symbol *s;
377
2
  bool wasInserted;
378
2
  std::tie(s, wasInserted) = insert(name, file);
379
2
380
2
  auto replaceSym = [&]() {
381
1
    replaceSymbol<DefinedEvent>(s, name, flags, file, event);
382
1
  };
383
2
384
2
  if (wasInserted || 
s->isLazy()1
) {
385
1
    replaceSym();
386
1
    return s;
387
1
  }
388
1
389
1
  checkEventType(s, file, &event->getType(), &event->signature);
390
1
391
1
  if (shouldReplace(s, file, flags))
392
0
    replaceSym();
393
1
  return s;
394
1
}
395
396
Symbol *SymbolTable::addUndefinedFunction(StringRef name, StringRef importName,
397
                                          StringRef importModule,
398
                                          uint32_t flags, InputFile *file,
399
                                          const WasmSignature *sig,
400
124
                                          bool isCalledDirectly) {
401
124
  LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << name << " ["
402
124
                    << (sig ? toString(*sig) : "none")
403
124
                    << "] IsCalledDirectly:" << isCalledDirectly << "\n");
404
124
405
124
  Symbol *s;
406
124
  bool wasInserted;
407
124
  std::tie(s, wasInserted) = insert(name, file);
408
124
  if (s->traced)
409
2
    printTraceSymbolUndefined(name, file);
410
124
411
124
  auto replaceSym = [&]() {
412
88
    replaceSymbol<UndefinedFunction>(s, name, importName, importModule, flags,
413
88
                                     file, sig, isCalledDirectly);
414
88
  };
415
124
416
124
  if (wasInserted)
417
88
    replaceSym();
418
36
  else if (auto *lazy = dyn_cast<LazySymbol>(s))
419
9
    lazy->fetch();
420
27
  else {
421
27
    auto existingFunction = dyn_cast<FunctionSymbol>(s);
422
27
    if (!existingFunction) {
423
0
      reportTypeError(s, file, WASM_SYMBOL_TYPE_FUNCTION);
424
0
      return s;
425
0
    }
426
27
    if (!existingFunction->signature && 
sig5
)
427
5
      existingFunction->signature = sig;
428
27
    if (isCalledDirectly && 
!signatureMatches(existingFunction, sig)19
)
429
0
      if (getFunctionVariant(s, sig, file, &s))
430
0
        replaceSym();
431
27
  }
432
124
433
124
  return s;
434
124
}
435
436
Symbol *SymbolTable::addUndefinedData(StringRef name, uint32_t flags,
437
26
                                      InputFile *file) {
438
26
  LLVM_DEBUG(dbgs() << "addUndefinedData: " << name << "\n");
439
26
440
26
  Symbol *s;
441
26
  bool wasInserted;
442
26
  std::tie(s, wasInserted) = insert(name, file);
443
26
  if (s->traced)
444
0
    printTraceSymbolUndefined(name, file);
445
26
446
26
  if (wasInserted)
447
18
    replaceSymbol<UndefinedData>(s, name, flags, file);
448
8
  else if (auto *lazy = dyn_cast<LazySymbol>(s))
449
0
    lazy->fetch();
450
8
  else if (s->isDefined())
451
6
    checkDataType(s, file);
452
26
  return s;
453
26
}
454
455
Symbol *SymbolTable::addUndefinedGlobal(StringRef name, StringRef importName,
456
                                        StringRef importModule, uint32_t flags,
457
                                        InputFile *file,
458
38
                                        const WasmGlobalType *type) {
459
38
  LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << name << "\n");
460
38
461
38
  Symbol *s;
462
38
  bool wasInserted;
463
38
  std::tie(s, wasInserted) = insert(name, file);
464
38
  if (s->traced)
465
0
    printTraceSymbolUndefined(name, file);
466
38
467
38
  if (wasInserted)
468
26
    replaceSymbol<UndefinedGlobal>(s, name, importName, importModule, flags,
469
26
                                   file, type);
470
12
  else if (auto *lazy = dyn_cast<LazySymbol>(s))
471
0
    lazy->fetch();
472
12
  else if (s->isDefined())
473
8
    checkGlobalType(s, file, type);
474
38
  return s;
475
38
}
476
477
52
void SymbolTable::addLazy(ArchiveFile *file, const Archive::Symbol *sym) {
478
52
  LLVM_DEBUG(dbgs() << "addLazy: " << sym->getName() << "\n");
479
52
  StringRef name = sym->getName();
480
52
481
52
  Symbol *s;
482
52
  bool wasInserted;
483
52
  std::tie(s, wasInserted) = insertName(name);
484
52
485
52
  if (wasInserted) {
486
35
    replaceSymbol<LazySymbol>(s, name, 0, file, *sym);
487
35
    return;
488
35
  }
489
17
490
17
  if (!s->isUndefined())
491
13
    return;
492
4
493
4
  // The existing symbol is undefined, load a new one from the archive,
494
4
  // unless the the existing symbol is weak in which case replace the undefined
495
4
  // symbols with a LazySymbol.
496
4
  if (s->isWeak()) {
497
1
    const WasmSignature *oldSig = nullptr;
498
1
    // In the case of an UndefinedFunction we need to preserve the expected
499
1
    // signature.
500
1
    if (auto *f = dyn_cast<UndefinedFunction>(s))
501
1
      oldSig = f->signature;
502
1
    LLVM_DEBUG(dbgs() << "replacing existing weak undefined symbol\n");
503
1
    auto newSym = replaceSymbol<LazySymbol>(s, name, WASM_SYMBOL_BINDING_WEAK,
504
1
                                            file, *sym);
505
1
    newSym->signature = oldSig;
506
1
    return;
507
1
  }
508
3
509
3
  LLVM_DEBUG(dbgs() << "replacing existing undefined\n");
510
3
  file->addMember(sym);
511
3
}
512
513
7
bool SymbolTable::addComdat(StringRef name) {
514
7
  return comdatGroups.insert(CachedHashStringRef(name)).second;
515
7
}
516
517
// The new signature doesn't match.  Create a variant to the symbol with the
518
// signature encoded in the name and return that instead.  These symbols are
519
// then unified later in handleSymbolVariants.
520
bool SymbolTable::getFunctionVariant(Symbol* sym, const WasmSignature *sig,
521
8
                                     const InputFile *file, Symbol **out) {
522
8
  LLVM_DEBUG(dbgs() << "getFunctionVariant: " << sym->getName() << " -> "
523
8
                    << " " << toString(*sig) << "\n");
524
8
  Symbol *variant = nullptr;
525
8
526
8
  // Linear search through symbol variants.  Should never be more than two
527
8
  // or three entries here.
528
8
  auto &variants = symVariants[CachedHashStringRef(sym->getName())];
529
8
  if (variants.empty())
530
7
    variants.push_back(sym);
531
8
532
8
  for (Symbol* v : variants) {
533
8
    if (*v->getSignature() == *sig) {
534
1
      variant = v;
535
1
      break;
536
1
    }
537
8
  }
538
8
539
8
  bool wasAdded = !variant;
540
8
  if (wasAdded) {
541
7
    // Create a new variant;
542
7
    LLVM_DEBUG(dbgs() << "added new variant\n");
543
7
    variant = reinterpret_cast<Symbol *>(make<SymbolUnion>());
544
7
    variants.push_back(variant);
545
7
  } else {
546
1
    LLVM_DEBUG(dbgs() << "variant already exists: " << toString(*variant) << "\n");
547
1
    assert(*variant->getSignature() == *sig);
548
1
  }
549
8
550
8
  *out = variant;
551
8
  return wasAdded;
552
8
}
553
554
// Set a flag for --trace-symbol so that we can print out a log message
555
// if a new symbol with the same name is inserted into the symbol table.
556
5
void SymbolTable::trace(StringRef name) {
557
5
  symMap.insert({CachedHashStringRef(name), -1});
558
5
}
559
560
2
void SymbolTable::wrap(Symbol *sym, Symbol *real, Symbol *wrap) {
561
2
  // Swap symbols as instructed by -wrap.
562
2
  int &origIdx = symMap[CachedHashStringRef(sym->getName())];
563
2
  int &realIdx= symMap[CachedHashStringRef(real->getName())];
564
2
  int &wrapIdx = symMap[CachedHashStringRef(wrap->getName())];
565
2
  LLVM_DEBUG(dbgs() << "wrap: " << sym->getName() << "\n");
566
2
567
2
  // Anyone looking up __real symbols should get the original
568
2
  realIdx = origIdx;
569
2
  // Anyone looking up the original should get the __wrap symbol
570
2
  origIdx = wrapIdx;
571
2
}
572
573
static const uint8_t unreachableFn[] = {
574
    0x03 /* ULEB length */, 0x00 /* ULEB num locals */,
575
    0x00 /* opcode unreachable */, 0x0b /* opcode end */
576
};
577
578
// Replace the given symbol body with an unreachable function.
579
// This is used by handleWeakUndefines in order to generate a callable
580
// equivalent of an undefined function and also handleSymbolVariants for
581
// undefined functions that don't match the signature of the definition.
582
InputFunction *SymbolTable::replaceWithUnreachable(Symbol *sym,
583
                                                   const WasmSignature &sig,
584
16
                                                   StringRef debugName) {
585
16
  auto *func = make<SyntheticFunction>(sig, sym->getName(), debugName);
586
16
  func->setBody(unreachableFn);
587
16
  syntheticFunctions.emplace_back(func);
588
16
  replaceSymbol<DefinedFunction>(sym, sym->getName(), sym->getFlags(), nullptr,
589
16
                                 func);
590
16
  return func;
591
16
}
592
593
// For weak undefined functions, there may be "call" instructions that reference
594
// the symbol. In this case, we need to synthesise a dummy/stub function that
595
// will abort at runtime, so that relocations can still provided an operand to
596
// the call instruction that passes Wasm validation.
597
175
void SymbolTable::handleWeakUndefines() {
598
1.11k
  for (Symbol *sym : getSymbols()) {
599
1.11k
    if (!sym->isUndefWeak())
600
1.10k
      continue;
601
10
602
10
    const WasmSignature *sig = sym->getSignature();
603
10
    if (!sig) {
604
1
      // It is possible for undefined functions not to have a signature (eg. if
605
1
      // added via "--undefined"), but weak undefined ones do have a signature.
606
1
      // Lazy symbols may not be functions and therefore Sig can still be null
607
1
      // in some circumstantce.
608
1
      assert(!isa<FunctionSymbol>(sym));
609
1
      continue;
610
1
    }
611
9
612
9
    // Add a synthetic dummy for weak undefined functions.  These dummies will
613
9
    // be GC'd if not used as the target of any "call" instructions.
614
9
    StringRef debugName = saver.save("undefined:" + toString(*sym));
615
9
    InputFunction* func = replaceWithUnreachable(sym, *sig, debugName);
616
9
    // Ensure it compares equal to the null pointer, and so that table relocs
617
9
    // don't pull in the stub body (only call-operand relocs should do that).
618
9
    func->setTableIndex(0);
619
9
    // Hide our dummy to prevent export.
620
9
    sym->setHidden(true);
621
9
  }
622
175
}
623
624
static void reportFunctionSignatureMismatch(StringRef symName,
625
                                            FunctionSymbol *a,
626
7
                                            FunctionSymbol *b, bool isError) {
627
7
  std::string msg = ("function signature mismatch: " + symName +
628
7
                     "\n>>> defined as " + toString(*a->signature) + " in " +
629
7
                     toString(a->getFile()) + "\n>>> defined as " +
630
7
                     toString(*b->signature) + " in " + toString(b->getFile()))
631
7
                        .str();
632
7
  if (isError)
633
0
    error(msg);
634
7
  else
635
7
    warn(msg);
636
7
}
637
638
// Remove any variant symbols that were created due to function signature
639
// mismatches.
640
198
void SymbolTable::handleSymbolVariants() {
641
198
  for (auto pair : symVariants) {
642
7
    // Push the initial symbol onto the list of variants.
643
7
    StringRef symName = pair.first.val();
644
7
    std::vector<Symbol *> &variants = pair.second;
645
7
646
#ifndef NDEBUG
647
    LLVM_DEBUG(dbgs() << "symbol with (" << variants.size()
648
                      << ") variants: " << symName << "\n");
649
    for (auto *s: variants) {
650
      auto *f = cast<FunctionSymbol>(s);
651
      LLVM_DEBUG(dbgs() << " variant: " + f->getName() << " "
652
                        << toString(*f->signature) << "\n");
653
    }
654
#endif
655
656
7
    // Find the one definition.
657
7
    DefinedFunction *defined = nullptr;
658
14
    for (auto *symbol : variants) {
659
14
      if (auto f = dyn_cast<DefinedFunction>(symbol)) {
660
7
        defined = f;
661
7
        break;
662
7
      }
663
14
    }
664
7
665
7
    // If there are no definitions, and the undefined symbols disagree on
666
7
    // the signature, there is not we can do since we don't know which one
667
7
    // to use as the signature on the import.
668
7
    if (!defined) {
669
0
      reportFunctionSignatureMismatch(symName,
670
0
                                      cast<FunctionSymbol>(variants[0]),
671
0
                                      cast<FunctionSymbol>(variants[1]), true);
672
0
      return;
673
0
    }
674
7
675
14
    
for (auto *symbol : variants)7
{
676
14
      if (symbol != defined) {
677
7
        auto *f = cast<FunctionSymbol>(symbol);
678
7
        reportFunctionSignatureMismatch(symName, f, defined, false);
679
7
        StringRef debugName = saver.save("unreachable:" + toString(*f));
680
7
        replaceWithUnreachable(f, *f->signature, debugName);
681
7
      }
682
14
    }
683
7
  }
684
198
}