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 static bool requiresGOTAccess(const Symbol *sym) {
20   return config->isPic && !sym->isHidden() && !sym->isLocal();
21 }
22 
23 static bool allowUndefined(const Symbol* sym) {
24   // Historically --allow-undefined doesn't work for data symbols since we don't
25   // have any way to represent these as imports in the final binary.  The idea
26   // behind allowing undefined symbols is to allow importing these symbols from
27   // the embedder and we can't do this for data symbols (at least not without
28   // compiling with -fPIC)
29   if (isa<DataSymbol>(sym))
30     return false;
31   // Undefined functions with explicit import name are allowed to be undefined
32   // at link time.
33   if (auto *F = dyn_cast<UndefinedFunction>(sym))
34     if (F->importName)
35       return true;
36   return (config->allowUndefined ||
37           config->allowUndefinedSymbols.count(sym->getName()) != 0);
38 }
39 
40 static void reportUndefined(const Symbol* sym) {
41   assert(sym->isUndefined());
42   assert(!sym->isWeak());
43   if (!allowUndefined(sym))
44     error(toString(sym->getFile()) + ": undefined symbol: " + toString(*sym));
45 }
46 
47 static void addGOTEntry(Symbol *sym) {
48   // In PIC mode a GOT entry is an imported global that the dynamic linker
49   // will assign.
50   // In non-PIC mode (i.e. when code compiled as fPIC is linked into a static
51   // binary) we create an internal wasm global with a fixed value that takes the
52   // place of th GOT entry and effectivly acts as an i32 const. This can
53   // potentially be optimized away at runtime or with a post-link tool.
54   // TODO(sbc): Linker relaxation might also be able to optimize this away.
55   if (config->isPic)
56     out.importSec->addGOTEntry(sym);
57   else
58     out.globalSec->addStaticGOTEntry(sym);
59 }
60 
61 void scanRelocations(InputChunk *chunk) {
62   if (!chunk->live)
63     return;
64   ObjFile *file = chunk->file;
65   ArrayRef<WasmSignature> types = file->getWasmObj()->types();
66   for (const WasmRelocation &reloc : chunk->getRelocations()) {
67     if (reloc.Type == R_WASM_TYPE_INDEX_LEB) {
68       // Mark target type as live
69       file->typeMap[reloc.Index] =
70           out.typeSec->registerType(types[reloc.Index]);
71       file->typeIsUsed[reloc.Index] = true;
72       continue;
73     }
74 
75     // Other relocation types all have a corresponding symbol
76     Symbol *sym = file->getSymbols()[reloc.Index];
77 
78     switch (reloc.Type) {
79     case R_WASM_TABLE_INDEX_I32:
80     case R_WASM_TABLE_INDEX_SLEB:
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       if (!isa<GlobalSymbol>(sym))
88         addGOTEntry(sym);
89       break;
90     }
91 
92     if (config->isPic) {
93       switch (reloc.Type) {
94       case R_WASM_TABLE_INDEX_SLEB:
95       case R_WASM_MEMORY_ADDR_SLEB:
96       case R_WASM_MEMORY_ADDR_LEB:
97         // Certain relocation types can't be used when building PIC output,
98         // since they would require absolute symbol addresses at link time.
99         error(toString(file) + ": relocation " + relocTypeToString(reloc.Type) +
100               " cannot be used against symbol " + toString(*sym) +
101               "; recompile with -fPIC");
102         break;
103       case R_WASM_TABLE_INDEX_I32:
104       case R_WASM_MEMORY_ADDR_I32:
105         // These relocation types are only present in the data section and
106         // will be converted into code by `generateRelocationCode`.  This code
107         // requires the symbols to have GOT entires.
108         if (requiresGOTAccess(sym))
109           addGOTEntry(sym);
110         break;
111       }
112     } else {
113       // Report undefined symbols
114       if (sym->isUndefined() && !config->relocatable && !sym->isWeak())
115         reportUndefined(sym);
116     }
117 
118   }
119 }
120 
121 } // namespace wasm
122 } // namespace lld
123