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