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