xref: /openbsd-src/gnu/llvm/lld/wasm/Relocations.cpp (revision dfe94b169149f14cc1aee2cf6dad58a8d9a1860c)
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 {
20 namespace wasm {
21 
requiresGOTAccess(const Symbol * sym)22 static bool requiresGOTAccess(const Symbol *sym) {
23   if (!config->isPic &&
24       config->unresolvedSymbols != UnresolvedPolicy::ImportDynamic)
25     return false;
26   if (sym->isHidden() || sym->isLocal())
27     return false;
28   // With `-Bsymbolic` (or when building an executable) as don't need to use
29   // the GOT for symbols that are defined within the current module.
30   if (sym->isDefined() && (!config->shared || config->bsymbolic))
31     return false;
32   return true;
33 }
34 
allowUndefined(const Symbol * sym)35 static bool allowUndefined(const Symbol* sym) {
36   // Symbols that are explicitly imported are always allowed to be undefined at
37   // link time.
38   if (sym->isImported())
39     return true;
40   if (isa<UndefinedFunction>(sym) && config->importUndefined)
41     return true;
42 
43   return config->allowUndefinedSymbols.count(sym->getName()) != 0;
44 }
45 
reportUndefined(Symbol * sym)46 static void reportUndefined(Symbol *sym) {
47   if (!allowUndefined(sym)) {
48     switch (config->unresolvedSymbols) {
49     case UnresolvedPolicy::ReportError:
50       error(toString(sym->getFile()) + ": undefined symbol: " + toString(*sym));
51       break;
52     case UnresolvedPolicy::Warn:
53       warn(toString(sym->getFile()) + ": undefined symbol: " + toString(*sym));
54       break;
55     case UnresolvedPolicy::Ignore:
56       LLVM_DEBUG(dbgs() << "ignoring undefined symbol: " + toString(*sym) +
57                                "\n");
58       if (!config->importUndefined) {
59         if (auto *f = dyn_cast<UndefinedFunction>(sym)) {
60           if (!f->stubFunction) {
61             f->stubFunction = symtab->createUndefinedStub(*f->getSignature());
62             f->stubFunction->markLive();
63             // Mark the function itself as a stub which prevents it from being
64             // assigned a table entry.
65             f->isStub = true;
66           }
67         }
68       }
69       break;
70     case UnresolvedPolicy::ImportDynamic:
71       break;
72     }
73   }
74 }
75 
addGOTEntry(Symbol * sym)76 static void addGOTEntry(Symbol *sym) {
77   if (requiresGOTAccess(sym))
78     out.importSec->addGOTEntry(sym);
79   else
80     out.globalSec->addInternalGOTEntry(sym);
81 }
82 
scanRelocations(InputChunk * chunk)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(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(cast<FunctionSymbol>(sym));
110       break;
111     case R_WASM_GLOBAL_INDEX_LEB:
112     case R_WASM_GLOBAL_INDEX_I32:
113       if (!isa<GlobalSymbol>(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(toString(file) + ": relocation " + relocTypeToString(reloc.Type) +
120               " cannot be used against an undefined symbol `" + toString(*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(toString(file) + ": relocation " +
129                 relocTypeToString(reloc.Type) +
130                 " cannot be used against non-TLS symbol `" + toString(*sym) +
131                 "`");
132         }
133         if (auto *D = dyn_cast<DefinedData>(sym)) {
134           if (!D->segment->outputSeg->isTLS()) {
135             error(toString(file) + ": relocation " +
136                   relocTypeToString(reloc.Type) + " cannot be used against `" +
137                   toString(*sym) +
138                   "` in non-TLS section: " + D->segment->outputSeg->name);
139           }
140         }
141       }
142       break;
143     }
144 
145     if (config->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(toString(file) + ": relocation " + relocTypeToString(reloc.Type) +
158               " cannot be used against symbol `" + toString(*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 wasm
180 } // namespace lld
181