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