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