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
16using namespace llvm;
17using namespace llvm::wasm;
18
19namespace lld::wasm {
20
21static 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
34static 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
45static 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
76static void addGOTEntry(Symbol *sym) {
77 if (requiresGOTAccess(sym))
78 out.importSec->addGOTEntry(sym);
79 else
80 out.globalSec->addInternalGOTEntry(sym);
81}
82
83void 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

source code of lld/wasm/Relocations.cpp