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