Relocations.cpp
4.16 KB
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
//===- Relocations.cpp ----------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "Relocations.h"
#include "InputChunks.h"
#include "SyntheticSections.h"
using namespace llvm;
using namespace llvm::wasm;
namespace lld {
namespace wasm {
static bool requiresGOTAccess(const Symbol *sym) {
return config->isPic && !sym->isHidden() && !sym->isLocal();
}
static bool allowUndefined(const Symbol* sym) {
// Undefined functions and globals with explicit import name are allowed to be
// undefined at link time.
if (auto *f = dyn_cast<UndefinedFunction>(sym))
if (f->importName)
return true;
if (auto *g = dyn_cast<UndefinedGlobal>(sym))
if (g->importName)
return true;
return (config->allowUndefined ||
config->allowUndefinedSymbols.count(sym->getName()) != 0);
}
static void reportUndefined(const Symbol* sym) {
assert(sym->isUndefined());
assert(!sym->isWeak());
if (!allowUndefined(sym))
error(toString(sym->getFile()) + ": undefined symbol: " + toString(*sym));
}
static void addGOTEntry(Symbol *sym) {
// In PIC mode a GOT entry is an imported global that the dynamic linker
// will assign.
// In non-PIC mode (i.e. when code compiled as fPIC is linked into a static
// binary) we create an internal wasm global with a fixed value that takes the
// place of th GOT entry and effectivly acts as an i32 const. This can
// potentially be optimized away at runtime or with a post-link tool.
// TODO(sbc): Linker relaxation might also be able to optimize this away.
if (config->isPic)
out.importSec->addGOTEntry(sym);
else
out.globalSec->addStaticGOTEntry(sym);
}
void scanRelocations(InputChunk *chunk) {
if (!chunk->live)
return;
ObjFile *file = chunk->file;
ArrayRef<WasmSignature> types = file->getWasmObj()->types();
for (const WasmRelocation &reloc : chunk->getRelocations()) {
if (reloc.Type == R_WASM_TYPE_INDEX_LEB) {
// Mark target type as live
file->typeMap[reloc.Index] =
out.typeSec->registerType(types[reloc.Index]);
file->typeIsUsed[reloc.Index] = true;
continue;
}
// Other relocation types all have a corresponding symbol
Symbol *sym = file->getSymbols()[reloc.Index];
switch (reloc.Type) {
case R_WASM_TABLE_INDEX_I32:
case R_WASM_TABLE_INDEX_I64:
case R_WASM_TABLE_INDEX_SLEB:
case R_WASM_TABLE_INDEX_SLEB64:
case R_WASM_TABLE_INDEX_REL_SLEB:
if (requiresGOTAccess(sym))
break;
out.elemSec->addEntry(cast<FunctionSymbol>(sym));
break;
case R_WASM_GLOBAL_INDEX_LEB:
case R_WASM_GLOBAL_INDEX_I32:
if (!isa<GlobalSymbol>(sym))
addGOTEntry(sym);
break;
}
if (config->isPic) {
switch (reloc.Type) {
case R_WASM_TABLE_INDEX_SLEB:
case R_WASM_TABLE_INDEX_SLEB64:
case R_WASM_MEMORY_ADDR_SLEB:
case R_WASM_MEMORY_ADDR_LEB:
case R_WASM_MEMORY_ADDR_SLEB64:
case R_WASM_MEMORY_ADDR_LEB64:
// Certain relocation types can't be used when building PIC output,
// since they would require absolute symbol addresses at link time.
error(toString(file) + ": relocation " + relocTypeToString(reloc.Type) +
" cannot be used against symbol " + toString(*sym) +
"; recompile with -fPIC");
break;
case R_WASM_TABLE_INDEX_I32:
case R_WASM_TABLE_INDEX_I64:
case R_WASM_MEMORY_ADDR_I32:
case R_WASM_MEMORY_ADDR_I64:
// These relocation types are only present in the data section and
// will be converted into code by `generateRelocationCode`. This code
// requires the symbols to have GOT entires.
if (requiresGOTAccess(sym))
addGOTEntry(sym);
break;
}
} else {
// Report undefined symbols
if (sym->isUndefined() && !config->relocatable && !sym->isWeak())
reportUndefined(sym);
}
}
}
} // namespace wasm
} // namespace lld