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 20 static bool requiresGOTAccess(const Symbol *sym) { 21 if (!config->isPic) 22 return false; 23 if (sym->isHidden() || sym->isLocal()) 24 return false; 25 // With `-Bsymbolic` (or when building an executable) as don't need to use 26 // the GOT for symbols that are defined within the current module. 27 if (sym->isDefined() && (!config->shared || config->bsymbolic)) 28 return false; 29 return true; 30 } 31 32 static bool allowUndefined(const Symbol* sym) { 33 // Undefined functions and globals with explicit import name are allowed to be 34 // undefined at link time. 35 if (auto *f = dyn_cast<UndefinedFunction>(sym)) 36 if (f->importName) 37 return true; 38 if (auto *g = dyn_cast<UndefinedGlobal>(sym)) 39 if (g->importName) 40 return true; 41 return (config->allowUndefined || 42 config->allowUndefinedSymbols.count(sym->getName()) != 0); 43 } 44 45 static void reportUndefined(const Symbol* sym) { 46 assert(sym->isUndefined()); 47 assert(!sym->isWeak()); 48 if (!allowUndefined(sym)) 49 error(toString(sym->getFile()) + ": undefined symbol: " + toString(*sym)); 50 } 51 52 static void addGOTEntry(Symbol *sym) { 53 if (requiresGOTAccess(sym)) 54 out.importSec->addGOTEntry(sym); 55 else 56 out.globalSec->addInternalGOTEntry(sym); 57 } 58 59 void scanRelocations(InputChunk *chunk) { 60 if (!chunk->live) 61 return; 62 ObjFile *file = chunk->file; 63 ArrayRef<WasmSignature> types = file->getWasmObj()->types(); 64 for (const WasmRelocation &reloc : chunk->getRelocations()) { 65 if (reloc.Type == R_WASM_TYPE_INDEX_LEB) { 66 // Mark target type as live 67 file->typeMap[reloc.Index] = 68 out.typeSec->registerType(types[reloc.Index]); 69 file->typeIsUsed[reloc.Index] = true; 70 continue; 71 } 72 73 // Other relocation types all have a corresponding symbol 74 Symbol *sym = file->getSymbols()[reloc.Index]; 75 76 switch (reloc.Type) { 77 case R_WASM_TABLE_INDEX_I32: 78 case R_WASM_TABLE_INDEX_I64: 79 case R_WASM_TABLE_INDEX_SLEB: 80 case R_WASM_TABLE_INDEX_SLEB64: 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 case R_WASM_GLOBAL_INDEX_I32: 88 if (!isa<GlobalSymbol>(sym)) 89 addGOTEntry(sym); 90 break; 91 } 92 93 if (config->isPic) { 94 switch (reloc.Type) { 95 case R_WASM_TABLE_INDEX_SLEB: 96 case R_WASM_TABLE_INDEX_SLEB64: 97 case R_WASM_MEMORY_ADDR_SLEB: 98 case R_WASM_MEMORY_ADDR_LEB: 99 case R_WASM_MEMORY_ADDR_SLEB64: 100 case R_WASM_MEMORY_ADDR_LEB64: 101 // Certain relocation types can't be used when building PIC output, 102 // since they would require absolute symbol addresses at link time. 103 error(toString(file) + ": relocation " + relocTypeToString(reloc.Type) + 104 " cannot be used against symbol " + toString(*sym) + 105 "; recompile with -fPIC"); 106 break; 107 case R_WASM_TABLE_INDEX_I32: 108 case R_WASM_TABLE_INDEX_I64: 109 case R_WASM_MEMORY_ADDR_I32: 110 case R_WASM_MEMORY_ADDR_I64: 111 // These relocation types are only present in the data section and 112 // will be converted into code by `generateRelocationCode`. This code 113 // requires the symbols to have GOT entires. 114 if (requiresGOTAccess(sym)) 115 addGOTEntry(sym); 116 break; 117 } 118 } else { 119 // Report undefined symbols 120 if (sym->isUndefined() && !config->relocatable && !sym->isWeak()) 121 reportUndefined(sym); 122 } 123 124 } 125 } 126 127 } // namespace wasm 128 } // namespace lld 129