Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / lld / wasm / Relocations.cpp
blobce41cdcb3e07f4e56d61749a735dd8f2e78ee295
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 (!config->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;
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>(sym) && config->importUndefined)
40 return true;
42 return config->allowUndefinedSymbols.count(sym->getName()) != 0;
45 static void reportUndefined(Symbol *sym) {
46 if (!allowUndefined(sym)) {
47 switch (config->unresolvedSymbols) {
48 case UnresolvedPolicy::ReportError:
49 error(toString(sym->getFile()) + ": undefined symbol: " + toString(*sym));
50 break;
51 case UnresolvedPolicy::Warn:
52 warn(toString(sym->getFile()) + ": undefined symbol: " + toString(*sym));
53 break;
54 case UnresolvedPolicy::Ignore:
55 LLVM_DEBUG(dbgs() << "ignoring undefined symbol: " + toString(*sym) +
56 "\n");
57 if (!config->importUndefined) {
58 if (auto *f = dyn_cast<UndefinedFunction>(sym)) {
59 if (!f->stubFunction) {
60 f->stubFunction = symtab->createUndefinedStub(*f->getSignature());
61 f->stubFunction->markLive();
62 // Mark the function itself as a stub which prevents it from being
63 // assigned a table entry.
64 f->isStub = true;
68 break;
69 case UnresolvedPolicy::ImportDynamic:
70 break;
75 static void addGOTEntry(Symbol *sym) {
76 if (requiresGOTAccess(sym))
77 out.importSec->addGOTEntry(sym);
78 else
79 out.globalSec->addInternalGOTEntry(sym);
82 void scanRelocations(InputChunk *chunk) {
83 if (!chunk->live)
84 return;
85 ObjFile *file = chunk->file;
86 ArrayRef<WasmSignature> types = file->getWasmObj()->types();
87 for (const WasmRelocation &reloc : chunk->getRelocations()) {
88 if (reloc.Type == R_WASM_TYPE_INDEX_LEB) {
89 // Mark target type as live
90 file->typeMap[reloc.Index] =
91 out.typeSec->registerType(types[reloc.Index]);
92 file->typeIsUsed[reloc.Index] = true;
93 continue;
96 // Other relocation types all have a corresponding symbol
97 Symbol *sym = file->getSymbols()[reloc.Index];
99 switch (reloc.Type) {
100 case R_WASM_TABLE_INDEX_I32:
101 case R_WASM_TABLE_INDEX_I64:
102 case R_WASM_TABLE_INDEX_SLEB:
103 case R_WASM_TABLE_INDEX_SLEB64:
104 case R_WASM_TABLE_INDEX_REL_SLEB:
105 case R_WASM_TABLE_INDEX_REL_SLEB64:
106 if (requiresGOTAccess(sym))
107 break;
108 out.elemSec->addEntry(cast<FunctionSymbol>(sym));
109 break;
110 case R_WASM_GLOBAL_INDEX_LEB:
111 case R_WASM_GLOBAL_INDEX_I32:
112 if (!isa<GlobalSymbol>(sym))
113 addGOTEntry(sym);
114 break;
115 case R_WASM_MEMORY_ADDR_TLS_SLEB:
116 case R_WASM_MEMORY_ADDR_TLS_SLEB64:
117 if (!sym->isDefined()) {
118 error(toString(file) + ": relocation " + relocTypeToString(reloc.Type) +
119 " cannot be used against an undefined symbol `" + toString(*sym) +
120 "`");
122 // In single-threaded builds TLS is lowered away and TLS data can be
123 // merged with normal data and allowing TLS relocation in non-TLS
124 // segments.
125 if (config->sharedMemory) {
126 if (!sym->isTLS()) {
127 error(toString(file) + ": relocation " +
128 relocTypeToString(reloc.Type) +
129 " cannot be used against non-TLS symbol `" + toString(*sym) +
130 "`");
132 if (auto *D = dyn_cast<DefinedData>(sym)) {
133 if (!D->segment->outputSeg->isTLS()) {
134 error(toString(file) + ": relocation " +
135 relocTypeToString(reloc.Type) + " cannot be used against `" +
136 toString(*sym) +
137 "` in non-TLS section: " + D->segment->outputSeg->name);
141 break;
144 if (config->isPic ||
145 (sym->isUndefined() &&
146 config->unresolvedSymbols == UnresolvedPolicy::ImportDynamic)) {
147 switch (reloc.Type) {
148 case R_WASM_TABLE_INDEX_SLEB:
149 case R_WASM_TABLE_INDEX_SLEB64:
150 case R_WASM_MEMORY_ADDR_SLEB:
151 case R_WASM_MEMORY_ADDR_LEB:
152 case R_WASM_MEMORY_ADDR_SLEB64:
153 case R_WASM_MEMORY_ADDR_LEB64:
154 // Certain relocation types can't be used when building PIC output,
155 // since they would require absolute symbol addresses at link time.
156 error(toString(file) + ": relocation " + relocTypeToString(reloc.Type) +
157 " cannot be used against symbol `" + toString(*sym) +
158 "`; recompile with -fPIC");
159 break;
160 case R_WASM_TABLE_INDEX_I32:
161 case R_WASM_TABLE_INDEX_I64:
162 case R_WASM_MEMORY_ADDR_I32:
163 case R_WASM_MEMORY_ADDR_I64:
164 // These relocation types are only present in the data section and
165 // will be converted into code by `generateRelocationCode`. This code
166 // requires the symbols to have GOT entries.
167 if (requiresGOTAccess(sym))
168 addGOTEntry(sym);
169 break;
171 } else if (sym->isUndefined() && !config->relocatable && !sym->isWeak()) {
172 // Report undefined symbols
173 reportUndefined(sym);
178 } // namespace lld::wasm