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 "SyntheticSections.h"
13 
14 using namespace llvm;
15 using namespace llvm::wasm;
16 
17 namespace lld {
18 namespace wasm {
19 
20 static bool requiresGOTAccess(const Symbol *sym) {
21   if (!config->isPic)
22     return false;
23   if (sym->isHidden() || sym->isLocal())
24     return false;
25   // With `-Bsymbolic` (or when building an executable) as don't need to use
26   // the GOT for symbols that are defined within the current module.
27   if (sym->isDefined() && (!config->shared || config->bsymbolic))
28     return false;
29   return true;
30 }
31 
32 static bool allowUndefined(const Symbol* sym) {
33   // Undefined functions and globals with explicit import name are allowed to be
34   // undefined at link time.
35   if (auto *f = dyn_cast<UndefinedFunction>(sym))
36     if (f->importName)
37       return true;
38   if (auto *g = dyn_cast<UndefinedGlobal>(sym))
39     if (g->importName)
40       return true;
41   return (config->allowUndefined ||
42           config->allowUndefinedSymbols.count(sym->getName()) != 0);
43 }
44 
45 static void reportUndefined(const Symbol* sym) {
46   assert(sym->isUndefined());
47   assert(!sym->isWeak());
48   if (!allowUndefined(sym))
49     error(toString(sym->getFile()) + ": undefined symbol: " + toString(*sym));
50 }
51 
52 static void addGOTEntry(Symbol *sym) {
53   if (requiresGOTAccess(sym))
54     out.importSec->addGOTEntry(sym);
55   else
56     out.globalSec->addInternalGOTEntry(sym);
57 }
58 
59 void scanRelocations(InputChunk *chunk) {
60   if (!chunk->live)
61     return;
62   ObjFile *file = chunk->file;
63   ArrayRef<WasmSignature> types = file->getWasmObj()->types();
64   for (const WasmRelocation &reloc : chunk->getRelocations()) {
65     if (reloc.Type == R_WASM_TYPE_INDEX_LEB) {
66       // Mark target type as live
67       file->typeMap[reloc.Index] =
68           out.typeSec->registerType(types[reloc.Index]);
69       file->typeIsUsed[reloc.Index] = true;
70       continue;
71     }
72 
73     // Other relocation types all have a corresponding symbol
74     Symbol *sym = file->getSymbols()[reloc.Index];
75 
76     switch (reloc.Type) {
77     case R_WASM_TABLE_INDEX_I32:
78     case R_WASM_TABLE_INDEX_I64:
79     case R_WASM_TABLE_INDEX_SLEB:
80     case R_WASM_TABLE_INDEX_SLEB64:
81     case R_WASM_TABLE_INDEX_REL_SLEB:
82       if (requiresGOTAccess(sym))
83         break;
84       out.elemSec->addEntry(cast<FunctionSymbol>(sym));
85       break;
86     case R_WASM_GLOBAL_INDEX_LEB:
87     case R_WASM_GLOBAL_INDEX_I32:
88       if (!isa<GlobalSymbol>(sym))
89         addGOTEntry(sym);
90       break;
91     }
92 
93     if (config->isPic) {
94       switch (reloc.Type) {
95       case R_WASM_TABLE_INDEX_SLEB:
96       case R_WASM_TABLE_INDEX_SLEB64:
97       case R_WASM_MEMORY_ADDR_SLEB:
98       case R_WASM_MEMORY_ADDR_LEB:
99       case R_WASM_MEMORY_ADDR_SLEB64:
100       case R_WASM_MEMORY_ADDR_LEB64:
101         // Certain relocation types can't be used when building PIC output,
102         // since they would require absolute symbol addresses at link time.
103         error(toString(file) + ": relocation " + relocTypeToString(reloc.Type) +
104               " cannot be used against symbol " + toString(*sym) +
105               "; recompile with -fPIC");
106         break;
107       case R_WASM_TABLE_INDEX_I32:
108       case R_WASM_TABLE_INDEX_I64:
109       case R_WASM_MEMORY_ADDR_I32:
110       case R_WASM_MEMORY_ADDR_I64:
111         // These relocation types are only present in the data section and
112         // will be converted into code by `generateRelocationCode`.  This code
113         // requires the symbols to have GOT entires.
114         if (requiresGOTAccess(sym))
115           addGOTEntry(sym);
116         break;
117       }
118     } else {
119       // Report undefined symbols
120       if (sym->isUndefined() && !config->relocatable && !sym->isWeak())
121         reportUndefined(sym);
122     }
123 
124   }
125 }
126 
127 } // namespace wasm
128 } // namespace lld
129