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