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