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