1 | //===- Relocations.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 "Relocations.h" |
10 | |
11 | #include "InputChunks.h" |
12 | #include "OutputSegment.h" |
13 | #include "SymbolTable.h" |
14 | #include "SyntheticSections.h" |
15 | |
16 | using namespace llvm; |
17 | using namespace llvm::wasm; |
18 | |
19 | namespace lld::wasm { |
20 | |
21 | static bool requiresGOTAccess(const Symbol *sym) { |
22 | if (!ctx.isPic && |
23 | config->unresolvedSymbols != UnresolvedPolicy::ImportDynamic) |
24 | return false; |
25 | if (sym->isHidden() || sym->isLocal()) |
26 | return false; |
27 | // With `-Bsymbolic` (or when building an executable) as don't need to use |
28 | // the GOT for symbols that are defined within the current module. |
29 | if (sym->isDefined() && (!config->shared || config->bsymbolic)) |
30 | return false; |
31 | return true; |
32 | } |
33 | |
34 | static bool allowUndefined(const Symbol* sym) { |
35 | // Symbols that are explicitly imported are always allowed to be undefined at |
36 | // link time. |
37 | if (sym->isImported()) |
38 | return true; |
39 | if (isa<UndefinedFunction>(Val: sym) && config->importUndefined) |
40 | return true; |
41 | |
42 | return config->allowUndefinedSymbols.count(Key: sym->getName()) != 0; |
43 | } |
44 | |
45 | static void reportUndefined(Symbol *sym) { |
46 | if (!allowUndefined(sym)) { |
47 | switch (config->unresolvedSymbols) { |
48 | case UnresolvedPolicy::ReportError: |
49 | error(msg: toString(file: sym->getFile()) + ": undefined symbol: "+ toString(sym: *sym)); |
50 | break; |
51 | case UnresolvedPolicy::Warn: |
52 | warn(msg: toString(file: sym->getFile()) + ": undefined symbol: "+ toString(sym: *sym)); |
53 | break; |
54 | case UnresolvedPolicy::Ignore: |
55 | LLVM_DEBUG(dbgs() << "ignoring undefined symbol: "+ toString(*sym) + |
56 | "\n"); |
57 | break; |
58 | case UnresolvedPolicy::ImportDynamic: |
59 | break; |
60 | } |
61 | |
62 | if (auto *f = dyn_cast<UndefinedFunction>(Val: sym)) { |
63 | if (!f->stubFunction && |
64 | config->unresolvedSymbols != UnresolvedPolicy::ImportDynamic && |
65 | !config->importUndefined) { |
66 | f->stubFunction = symtab->createUndefinedStub(sig: *f->getSignature()); |
67 | f->stubFunction->markLive(); |
68 | // Mark the function itself as a stub which prevents it from being |
69 | // assigned a table entry. |
70 | f->isStub = true; |
71 | } |
72 | } |
73 | } |
74 | } |
75 | |
76 | static void addGOTEntry(Symbol *sym) { |
77 | if (requiresGOTAccess(sym)) |
78 | out.importSec->addGOTEntry(sym); |
79 | else |
80 | out.globalSec->addInternalGOTEntry(sym); |
81 | } |
82 | |
83 | void scanRelocations(InputChunk *chunk) { |
84 | if (!chunk->live) |
85 | return; |
86 | ObjFile *file = chunk->file; |
87 | ArrayRef<WasmSignature> types = file->getWasmObj()->types(); |
88 | for (const WasmRelocation &reloc : chunk->getRelocations()) { |
89 | if (reloc.Type == R_WASM_TYPE_INDEX_LEB) { |
90 | // Mark target type as live |
91 | file->typeMap[reloc.Index] = |
92 | out.typeSec->registerType(sig: types[reloc.Index]); |
93 | file->typeIsUsed[reloc.Index] = true; |
94 | continue; |
95 | } |
96 | |
97 | // Other relocation types all have a corresponding symbol |
98 | Symbol *sym = file->getSymbols()[reloc.Index]; |
99 | |
100 | switch (reloc.Type) { |
101 | case R_WASM_TABLE_INDEX_I32: |
102 | case R_WASM_TABLE_INDEX_I64: |
103 | case R_WASM_TABLE_INDEX_SLEB: |
104 | case R_WASM_TABLE_INDEX_SLEB64: |
105 | case R_WASM_TABLE_INDEX_REL_SLEB: |
106 | case R_WASM_TABLE_INDEX_REL_SLEB64: |
107 | if (requiresGOTAccess(sym)) |
108 | break; |
109 | out.elemSec->addEntry(sym: cast<FunctionSymbol>(Val: sym)); |
110 | break; |
111 | case R_WASM_GLOBAL_INDEX_LEB: |
112 | case R_WASM_GLOBAL_INDEX_I32: |
113 | if (!isa<GlobalSymbol>(Val: sym)) |
114 | addGOTEntry(sym); |
115 | break; |
116 | case R_WASM_MEMORY_ADDR_TLS_SLEB: |
117 | case R_WASM_MEMORY_ADDR_TLS_SLEB64: |
118 | if (!sym->isDefined()) { |
119 | error(msg: toString(file) + ": relocation "+ relocTypeToString(relocType: reloc.Type) + |
120 | " cannot be used against an undefined symbol `"+ toString(sym: *sym) + |
121 | "`"); |
122 | } |
123 | // In single-threaded builds TLS is lowered away and TLS data can be |
124 | // merged with normal data and allowing TLS relocation in non-TLS |
125 | // segments. |
126 | if (config->sharedMemory) { |
127 | if (!sym->isTLS()) { |
128 | error(msg: toString(file) + ": relocation "+ |
129 | relocTypeToString(relocType: reloc.Type) + |
130 | " cannot be used against non-TLS symbol `"+ toString(sym: *sym) + |
131 | "`"); |
132 | } |
133 | if (auto *D = dyn_cast<DefinedData>(Val: sym)) { |
134 | if (!D->segment->outputSeg->isTLS()) { |
135 | error(msg: toString(file) + ": relocation "+ |
136 | relocTypeToString(relocType: reloc.Type) + " cannot be used against `"+ |
137 | toString(sym: *sym) + |
138 | "` in non-TLS section: "+ D->segment->outputSeg->name); |
139 | } |
140 | } |
141 | } |
142 | break; |
143 | } |
144 | |
145 | if (ctx.isPic || |
146 | (sym->isUndefined() && |
147 | config->unresolvedSymbols == UnresolvedPolicy::ImportDynamic)) { |
148 | switch (reloc.Type) { |
149 | case R_WASM_TABLE_INDEX_SLEB: |
150 | case R_WASM_TABLE_INDEX_SLEB64: |
151 | case R_WASM_MEMORY_ADDR_SLEB: |
152 | case R_WASM_MEMORY_ADDR_LEB: |
153 | case R_WASM_MEMORY_ADDR_SLEB64: |
154 | case R_WASM_MEMORY_ADDR_LEB64: |
155 | // Certain relocation types can't be used when building PIC output, |
156 | // since they would require absolute symbol addresses at link time. |
157 | error(msg: toString(file) + ": relocation "+ relocTypeToString(relocType: reloc.Type) + |
158 | " cannot be used against symbol `"+ toString(sym: *sym) + |
159 | "`; recompile with -fPIC"); |
160 | break; |
161 | case R_WASM_TABLE_INDEX_I32: |
162 | case R_WASM_TABLE_INDEX_I64: |
163 | case R_WASM_MEMORY_ADDR_I32: |
164 | case R_WASM_MEMORY_ADDR_I64: |
165 | // These relocation types are only present in the data section and |
166 | // will be converted into code by `generateRelocationCode`. This code |
167 | // requires the symbols to have GOT entries. |
168 | if (requiresGOTAccess(sym)) |
169 | addGOTEntry(sym); |
170 | break; |
171 | } |
172 | } else if (sym->isUndefined() && !config->relocatable && !sym->isWeak()) { |
173 | // Report undefined symbols |
174 | reportUndefined(sym); |
175 | } |
176 | } |
177 | } |
178 | |
179 | } // namespace lld::wasm |
180 |