1ece8a530Spatrick //===- Relocations.cpp ----------------------------------------------------===// 2ece8a530Spatrick // 3ece8a530Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4ece8a530Spatrick // See https://llvm.org/LICENSE.txt for license information. 5ece8a530Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6ece8a530Spatrick // 7ece8a530Spatrick //===----------------------------------------------------------------------===// 8ece8a530Spatrick 9ece8a530Spatrick #include "Relocations.h" 10ece8a530Spatrick 11ece8a530Spatrick #include "InputChunks.h" 121cf9926bSpatrick #include "OutputSegment.h" 131cf9926bSpatrick #include "SymbolTable.h" 14ece8a530Spatrick #include "SyntheticSections.h" 15ece8a530Spatrick 16ece8a530Spatrick using namespace llvm; 17ece8a530Spatrick using namespace llvm::wasm; 18ece8a530Spatrick 19ece8a530Spatrick namespace lld { 20ece8a530Spatrick namespace wasm { 211cf9926bSpatrick requiresGOTAccess(const Symbol * sym)22ece8a530Spatrickstatic bool requiresGOTAccess(const Symbol *sym) { 23*dfe94b16Srobert if (!config->isPic && 24*dfe94b16Srobert config->unresolvedSymbols != UnresolvedPolicy::ImportDynamic) 251cf9926bSpatrick return false; 261cf9926bSpatrick if (sym->isHidden() || sym->isLocal()) 271cf9926bSpatrick return false; 281cf9926bSpatrick // With `-Bsymbolic` (or when building an executable) as don't need to use 291cf9926bSpatrick // the GOT for symbols that are defined within the current module. 301cf9926bSpatrick if (sym->isDefined() && (!config->shared || config->bsymbolic)) 311cf9926bSpatrick return false; 321cf9926bSpatrick return true; 33ece8a530Spatrick } 34ece8a530Spatrick allowUndefined(const Symbol * sym)35ece8a530Spatrickstatic bool allowUndefined(const Symbol* sym) { 36*dfe94b16Srobert // Symbols that are explicitly imported are always allowed to be undefined at 37*dfe94b16Srobert // link time. 38*dfe94b16Srobert if (sym->isImported()) 39bb684c34Spatrick return true; 40*dfe94b16Srobert if (isa<UndefinedFunction>(sym) && config->importUndefined) 411cf9926bSpatrick return true; 42*dfe94b16Srobert 431cf9926bSpatrick return config->allowUndefinedSymbols.count(sym->getName()) != 0; 44ece8a530Spatrick } 45ece8a530Spatrick reportUndefined(Symbol * sym)461cf9926bSpatrickstatic void reportUndefined(Symbol *sym) { 471cf9926bSpatrick if (!allowUndefined(sym)) { 481cf9926bSpatrick switch (config->unresolvedSymbols) { 491cf9926bSpatrick case UnresolvedPolicy::ReportError: 50ece8a530Spatrick error(toString(sym->getFile()) + ": undefined symbol: " + toString(*sym)); 511cf9926bSpatrick break; 521cf9926bSpatrick case UnresolvedPolicy::Warn: 531cf9926bSpatrick warn(toString(sym->getFile()) + ": undefined symbol: " + toString(*sym)); 541cf9926bSpatrick break; 551cf9926bSpatrick case UnresolvedPolicy::Ignore: 561cf9926bSpatrick LLVM_DEBUG(dbgs() << "ignoring undefined symbol: " + toString(*sym) + 571cf9926bSpatrick "\n"); 581cf9926bSpatrick if (!config->importUndefined) { 591cf9926bSpatrick if (auto *f = dyn_cast<UndefinedFunction>(sym)) { 601cf9926bSpatrick if (!f->stubFunction) { 611cf9926bSpatrick f->stubFunction = symtab->createUndefinedStub(*f->getSignature()); 621cf9926bSpatrick f->stubFunction->markLive(); 631cf9926bSpatrick // Mark the function itself as a stub which prevents it from being 641cf9926bSpatrick // assigned a table entry. 651cf9926bSpatrick f->isStub = true; 661cf9926bSpatrick } 671cf9926bSpatrick } 681cf9926bSpatrick } 691cf9926bSpatrick break; 70*dfe94b16Srobert case UnresolvedPolicy::ImportDynamic: 71*dfe94b16Srobert break; 721cf9926bSpatrick } 731cf9926bSpatrick } 74ece8a530Spatrick } 75ece8a530Spatrick addGOTEntry(Symbol * sym)76ece8a530Spatrickstatic void addGOTEntry(Symbol *sym) { 771cf9926bSpatrick if (requiresGOTAccess(sym)) 78ece8a530Spatrick out.importSec->addGOTEntry(sym); 79ece8a530Spatrick else 801cf9926bSpatrick out.globalSec->addInternalGOTEntry(sym); 81ece8a530Spatrick } 82ece8a530Spatrick scanRelocations(InputChunk * chunk)83ece8a530Spatrickvoid scanRelocations(InputChunk *chunk) { 84ece8a530Spatrick if (!chunk->live) 85ece8a530Spatrick return; 86ece8a530Spatrick ObjFile *file = chunk->file; 87ece8a530Spatrick ArrayRef<WasmSignature> types = file->getWasmObj()->types(); 88ece8a530Spatrick for (const WasmRelocation &reloc : chunk->getRelocations()) { 89ece8a530Spatrick if (reloc.Type == R_WASM_TYPE_INDEX_LEB) { 90ece8a530Spatrick // Mark target type as live 91ece8a530Spatrick file->typeMap[reloc.Index] = 92ece8a530Spatrick out.typeSec->registerType(types[reloc.Index]); 93ece8a530Spatrick file->typeIsUsed[reloc.Index] = true; 94ece8a530Spatrick continue; 95ece8a530Spatrick } 96ece8a530Spatrick 97ece8a530Spatrick // Other relocation types all have a corresponding symbol 98ece8a530Spatrick Symbol *sym = file->getSymbols()[reloc.Index]; 99ece8a530Spatrick 100ece8a530Spatrick switch (reloc.Type) { 101ece8a530Spatrick case R_WASM_TABLE_INDEX_I32: 1021cf9926bSpatrick case R_WASM_TABLE_INDEX_I64: 103ece8a530Spatrick case R_WASM_TABLE_INDEX_SLEB: 1041cf9926bSpatrick case R_WASM_TABLE_INDEX_SLEB64: 105ece8a530Spatrick case R_WASM_TABLE_INDEX_REL_SLEB: 1061cf9926bSpatrick case R_WASM_TABLE_INDEX_REL_SLEB64: 107ece8a530Spatrick if (requiresGOTAccess(sym)) 108ece8a530Spatrick break; 109ece8a530Spatrick out.elemSec->addEntry(cast<FunctionSymbol>(sym)); 110ece8a530Spatrick break; 111ece8a530Spatrick case R_WASM_GLOBAL_INDEX_LEB: 112bb684c34Spatrick case R_WASM_GLOBAL_INDEX_I32: 113ece8a530Spatrick if (!isa<GlobalSymbol>(sym)) 114ece8a530Spatrick addGOTEntry(sym); 115ece8a530Spatrick break; 1161cf9926bSpatrick case R_WASM_MEMORY_ADDR_TLS_SLEB: 1171cf9926bSpatrick case R_WASM_MEMORY_ADDR_TLS_SLEB64: 118*dfe94b16Srobert if (!sym->isDefined()) { 119*dfe94b16Srobert error(toString(file) + ": relocation " + relocTypeToString(reloc.Type) + 120*dfe94b16Srobert " cannot be used against an undefined symbol `" + toString(*sym) + 121*dfe94b16Srobert "`"); 122*dfe94b16Srobert } 1231cf9926bSpatrick // In single-threaded builds TLS is lowered away and TLS data can be 1241cf9926bSpatrick // merged with normal data and allowing TLS relocation in non-TLS 1251cf9926bSpatrick // segments. 1261cf9926bSpatrick if (config->sharedMemory) { 127*dfe94b16Srobert if (!sym->isTLS()) { 128*dfe94b16Srobert error(toString(file) + ": relocation " + 129*dfe94b16Srobert relocTypeToString(reloc.Type) + 130*dfe94b16Srobert " cannot be used against non-TLS symbol `" + toString(*sym) + 131*dfe94b16Srobert "`"); 132*dfe94b16Srobert } 1331cf9926bSpatrick if (auto *D = dyn_cast<DefinedData>(sym)) { 1341cf9926bSpatrick if (!D->segment->outputSeg->isTLS()) { 1351cf9926bSpatrick error(toString(file) + ": relocation " + 1361cf9926bSpatrick relocTypeToString(reloc.Type) + " cannot be used against `" + 1371cf9926bSpatrick toString(*sym) + 1381cf9926bSpatrick "` in non-TLS section: " + D->segment->outputSeg->name); 1391cf9926bSpatrick } 1401cf9926bSpatrick } 1411cf9926bSpatrick } 1421cf9926bSpatrick break; 143ece8a530Spatrick } 144ece8a530Spatrick 145*dfe94b16Srobert if (config->isPic || 146*dfe94b16Srobert (sym->isUndefined() && 147*dfe94b16Srobert config->unresolvedSymbols == UnresolvedPolicy::ImportDynamic)) { 148ece8a530Spatrick switch (reloc.Type) { 149ece8a530Spatrick case R_WASM_TABLE_INDEX_SLEB: 1501cf9926bSpatrick case R_WASM_TABLE_INDEX_SLEB64: 151ece8a530Spatrick case R_WASM_MEMORY_ADDR_SLEB: 152ece8a530Spatrick case R_WASM_MEMORY_ADDR_LEB: 153bb684c34Spatrick case R_WASM_MEMORY_ADDR_SLEB64: 154bb684c34Spatrick case R_WASM_MEMORY_ADDR_LEB64: 155ece8a530Spatrick // Certain relocation types can't be used when building PIC output, 156ece8a530Spatrick // since they would require absolute symbol addresses at link time. 157ece8a530Spatrick error(toString(file) + ": relocation " + relocTypeToString(reloc.Type) + 158*dfe94b16Srobert " cannot be used against symbol `" + toString(*sym) + 159*dfe94b16Srobert "`; recompile with -fPIC"); 1601cf9926bSpatrick break; 161ece8a530Spatrick case R_WASM_TABLE_INDEX_I32: 1621cf9926bSpatrick case R_WASM_TABLE_INDEX_I64: 163ece8a530Spatrick case R_WASM_MEMORY_ADDR_I32: 164bb684c34Spatrick case R_WASM_MEMORY_ADDR_I64: 165ece8a530Spatrick // These relocation types are only present in the data section and 166ece8a530Spatrick // will be converted into code by `generateRelocationCode`. This code 167*dfe94b16Srobert // requires the symbols to have GOT entries. 168ece8a530Spatrick if (requiresGOTAccess(sym)) 169ece8a530Spatrick addGOTEntry(sym); 170ece8a530Spatrick break; 171ece8a530Spatrick } 1721cf9926bSpatrick } else if (sym->isUndefined() && !config->relocatable && !sym->isWeak()) { 173ece8a530Spatrick // Report undefined symbols 174ece8a530Spatrick reportUndefined(sym); 175ece8a530Spatrick } 176ece8a530Spatrick } 177ece8a530Spatrick } 178ece8a530Spatrick 179ece8a530Spatrick } // namespace wasm 180ece8a530Spatrick } // namespace lld 181