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