xref: /llvm-project/lld/wasm/Relocations.cpp (revision 9df375e5eae726c5a90ada70f9535a5e22e90214)
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 (sym->isShared())
23     return true;
24   if (!ctx.isPic &&
25       ctx.arg.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() && (!ctx.arg.shared || ctx.arg.bsymbolic))
32     return false;
33   return true;
34 }
35 
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) && ctx.arg.importUndefined)
42     return true;
43 
44   return ctx.arg.allowUndefinedSymbols.count(sym->getName()) != 0;
45 }
46 
47 static void reportUndefined(ObjFile *file, Symbol *sym) {
48   if (!allowUndefined(sym)) {
49     switch (ctx.arg.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;
62     }
63 
64     if (auto *f = dyn_cast<UndefinedFunction>(sym)) {
65       if (!f->stubFunction &&
66           ctx.arg.unresolvedSymbols != UnresolvedPolicy::ImportDynamic &&
67           !ctx.arg.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;
73       }
74     }
75   }
76 }
77 
78 static void addGOTEntry(Symbol *sym) {
79   if (requiresGOTAccess(sym))
80     out.importSec->addGOTEntry(sym);
81   else
82     out.globalSec->addInternalGOTEntry(sym);
83 }
84 
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;
97     }
98 
99     // Other relocation types all have a corresponding symbol
100     Symbol *sym = file->getSymbols()[reloc.Index];
101 
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               "`");
124       }
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 (ctx.arg.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                 "`");
134         }
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);
141           }
142         }
143       }
144       break;
145     }
146 
147     if (ctx.isPic || sym->isShared() ||
148         (sym->isUndefined() &&
149          ctx.arg.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;
173       }
174     }
175 
176     if (!ctx.arg.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;
189       }
190 
191       if (!sym->isWeak()) {
192         // Report undefined symbols
193         reportUndefined(file, sym);
194       }
195     }
196   }
197 }
198 
199 } // namespace lld::wasm
200