blob: 6f33a4f28a9d09455e16319eebd9205796d68217 [file] [log] [blame]
Sam Clegg8fcf0122019-05-21 09:13:09 +00001//===- 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 Clegga28a46622020-11-10 17:46:52 -080012#include "OutputSegment.h"
Sam Clegg206884b2020-05-01 09:14:59 -070013#include "SymbolTable.h"
Sam Clegg8fcf0122019-05-21 09:13:09 +000014#include "SyntheticSections.h"
15
16using namespace llvm;
17using namespace llvm::wasm;
18
Sam Cleggd32f71a2023-03-06 09:55:00 -080019namespace lld::wasm {
Sam Clegg25134072020-10-07 14:48:37 -070020
Rui Ueyama136d27a2019-07-11 05:40:30 +000021static bool requiresGOTAccess(const Symbol *sym) {
Sam Clegg22b7b842024-07-12 13:26:52 -070022 if (sym->isShared())
23 return true;
Sam Clegg184c22d2024-01-18 15:01:21 -080024 if (!ctx.isPic &&
Sam Clegg86c90f92020-11-16 10:11:37 -080025 config->unresolvedSymbols != UnresolvedPolicy::ImportDynamic)
Sam Clegg25134072020-10-07 14:48:37 -070026 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 Clegg8fcf0122019-05-21 09:13:09 +000034}
35
Rui Ueyama136d27a2019-07-11 05:40:30 +000036static bool allowUndefined(const Symbol* sym) {
Sam Clegg31117842022-12-06 16:49:13 -080037 // Symbols that are explicitly imported are always allowed to be undefined at
Heejin Ahn9a9ec8e2021-10-04 15:55:37 -070038 // link time.
Sam Clegg31117842022-12-06 16:49:13 -080039 if (sym->isImported())
Heejin Ahn9a9ec8e2021-10-04 15:55:37 -070040 return true;
41 if (isa<UndefinedFunction>(sym) && config->importUndefined)
42 return true;
43
Sam Clegg206884b2020-05-01 09:14:59 -070044 return config->allowUndefinedSymbols.count(sym->getName()) != 0;
Sam Clegg9abe8c42019-07-09 20:45:20 +000045}
46
Sam Clegg4d888372024-07-02 11:23:41 -070047static void reportUndefined(ObjFile *file, Symbol *sym) {
Sam Clegg206884b2020-05-01 09:14:59 -070048 if (!allowUndefined(sym)) {
49 switch (config->unresolvedSymbols) {
50 case UnresolvedPolicy::ReportError:
Sam Clegg4d888372024-07-02 11:23:41 -070051 error(toString(file) + ": undefined symbol: " + toString(*sym));
Sam Clegg206884b2020-05-01 09:14:59 -070052 break;
53 case UnresolvedPolicy::Warn:
Sam Clegg4d888372024-07-02 11:23:41 -070054 warn(toString(file) + ": undefined symbol: " + toString(*sym));
Sam Clegg206884b2020-05-01 09:14:59 -070055 break;
56 case UnresolvedPolicy::Ignore:
Sam Clegg758633f2021-05-27 14:27:10 -070057 LLVM_DEBUG(dbgs() << "ignoring undefined symbol: " + toString(*sym) +
58 "\n");
Sam Clegg206884b2020-05-01 09:14:59 -070059 break;
Sam Clegg86c90f92020-11-16 10:11:37 -080060 case UnresolvedPolicy::ImportDynamic:
61 break;
Sam Clegg206884b2020-05-01 09:14:59 -070062 }
Sam Clegg5b0e45c2024-01-19 09:32:22 -080063
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 Clegg206884b2020-05-01 09:14:59 -070075 }
Sam Clegg9abe8c42019-07-09 20:45:20 +000076}
77
Sam Clegg7185a732019-08-13 17:02:02 +000078static void addGOTEntry(Symbol *sym) {
Sam Clegg25134072020-10-07 14:48:37 -070079 if (requiresGOTAccess(sym))
Sam Clegg7185a732019-08-13 17:02:02 +000080 out.importSec->addGOTEntry(sym);
81 else
Sam Clegg25134072020-10-07 14:48:37 -070082 out.globalSec->addInternalGOTEntry(sym);
Sam Clegg7185a732019-08-13 17:02:02 +000083}
84
Fangrui Song33c59ab2019-10-10 05:25:39 +000085void scanRelocations(InputChunk *chunk) {
Rui Ueyama136d27a2019-07-11 05:40:30 +000086 if (!chunk->live)
Sam Clegg8fcf0122019-05-21 09:13:09 +000087 return;
Rui Ueyama136d27a2019-07-11 05:40:30 +000088 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 Clegg8fcf0122019-05-21 09:13:09 +000092 // Mark target type as live
Rui Ueyama136d27a2019-07-11 05:40:30 +000093 file->typeMap[reloc.Index] =
94 out.typeSec->registerType(types[reloc.Index]);
95 file->typeIsUsed[reloc.Index] = true;
Sam Clegg8fcf0122019-05-21 09:13:09 +000096 continue;
97 }
98
99 // Other relocation types all have a corresponding symbol
Rui Ueyama136d27a2019-07-11 05:40:30 +0000100 Symbol *sym = file->getSymbols()[reloc.Index];
Sam Clegg8fcf0122019-05-21 09:13:09 +0000101
Rui Ueyama136d27a2019-07-11 05:40:30 +0000102 switch (reloc.Type) {
Sam Clegg8fcf0122019-05-21 09:13:09 +0000103 case R_WASM_TABLE_INDEX_I32:
Wouter van Oortmerssencc1b9b62020-07-10 16:51:01 -0700104 case R_WASM_TABLE_INDEX_I64:
Sam Clegg8fcf0122019-05-21 09:13:09 +0000105 case R_WASM_TABLE_INDEX_SLEB:
Wouter van Oortmerssencc1b9b62020-07-10 16:51:01 -0700106 case R_WASM_TABLE_INDEX_SLEB64:
Sam Clegg8fcf0122019-05-21 09:13:09 +0000107 case R_WASM_TABLE_INDEX_REL_SLEB:
Wouter van Oortmerssen3a293cb2021-04-22 16:54:58 -0700108 case R_WASM_TABLE_INDEX_REL_SLEB64:
Rui Ueyama136d27a2019-07-11 05:40:30 +0000109 if (requiresGOTAccess(sym))
Sam Clegg8fcf0122019-05-21 09:13:09 +0000110 break;
Rui Ueyama136d27a2019-07-11 05:40:30 +0000111 out.elemSec->addEntry(cast<FunctionSymbol>(sym));
Sam Clegg8fcf0122019-05-21 09:13:09 +0000112 break;
113 case R_WASM_GLOBAL_INDEX_LEB:
Wouter van Oortmerssen48139eb2020-03-19 19:53:51 -0700114 case R_WASM_GLOBAL_INDEX_I32:
Rui Ueyama136d27a2019-07-11 05:40:30 +0000115 if (!isa<GlobalSymbol>(sym))
Sam Clegg7185a732019-08-13 17:02:02 +0000116 addGOTEntry(sym);
Sam Clegg8fcf0122019-05-21 09:13:09 +0000117 break;
Sam Clegga28a46622020-11-10 17:46:52 -0800118 case R_WASM_MEMORY_ADDR_TLS_SLEB:
Wouter van Oortmerssen670944f2021-07-15 13:24:28 -0700119 case R_WASM_MEMORY_ADDR_TLS_SLEB64:
Sam Clegg37f422f2022-02-11 15:53:28 -0800120 if (!sym->isDefined()) {
121 error(toString(file) + ": relocation " + relocTypeToString(reloc.Type) +
122 " cannot be used against an undefined symbol `" + toString(*sym) +
123 "`");
124 }
Sam Clegg8544b402021-05-21 09:58:21 -0700125 // 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 Clegg44177e52021-09-08 04:53:13 -0400129 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 Clegg8544b402021-05-21 09:58:21 -0700135 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 Clegga28a46622020-11-10 17:46:52 -0800142 }
143 }
144 break;
Sam Clegg8fcf0122019-05-21 09:13:09 +0000145 }
146
Sam Clegg184c22d2024-01-18 15:01:21 -0800147 if (ctx.isPic ||
Sam Clegg86c90f92020-11-16 10:11:37 -0800148 (sym->isUndefined() &&
149 config->unresolvedSymbols == UnresolvedPolicy::ImportDynamic)) {
Rui Ueyama136d27a2019-07-11 05:40:30 +0000150 switch (reloc.Type) {
Sam Clegg8fcf0122019-05-21 09:13:09 +0000151 case R_WASM_TABLE_INDEX_SLEB:
Wouter van Oortmerssencc1b9b62020-07-10 16:51:01 -0700152 case R_WASM_TABLE_INDEX_SLEB64:
Sam Clegg8fcf0122019-05-21 09:13:09 +0000153 case R_WASM_MEMORY_ADDR_SLEB:
154 case R_WASM_MEMORY_ADDR_LEB:
Wouter van Oortmerssen3b293762020-06-05 09:03:12 -0700155 case R_WASM_MEMORY_ADDR_SLEB64:
156 case R_WASM_MEMORY_ADDR_LEB64:
Sam Clegg8fcf0122019-05-21 09:13:09 +0000157 // Certain relocation types can't be used when building PIC output,
158 // since they would require absolute symbol addresses at link time.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000159 error(toString(file) + ": relocation " + relocTypeToString(reloc.Type) +
Sam Clegg86c90f92020-11-16 10:11:37 -0800160 " cannot be used against symbol `" + toString(*sym) +
161 "`; recompile with -fPIC");
Sam Clegg8fcf0122019-05-21 09:13:09 +0000162 break;
163 case R_WASM_TABLE_INDEX_I32:
Wouter van Oortmerssencc1b9b62020-07-10 16:51:01 -0700164 case R_WASM_TABLE_INDEX_I64:
Sam Clegg8fcf0122019-05-21 09:13:09 +0000165 case R_WASM_MEMORY_ADDR_I32:
Wouter van Oortmerssen3b293762020-06-05 09:03:12 -0700166 case R_WASM_MEMORY_ADDR_I64:
Sam Clegg8fcf0122019-05-21 09:13:09 +0000167 // These relocation types are only present in the data section and
Sam Clegg22b7b842024-07-12 13:26:52 -0700168 // will be converted into code by `generateRelocationCode`. This
169 // code requires the symbols to have GOT entries.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000170 if (requiresGOTAccess(sym))
Sam Clegg7185a732019-08-13 17:02:02 +0000171 addGOTEntry(sym);
Sam Clegg8fcf0122019-05-21 09:13:09 +0000172 break;
173 }
Sam Clegg22b7b842024-07-12 13:26:52 -0700174 }
175
176 if (sym->isUndefined() && !config->relocatable && !sym->isWeak()) {
Sam Clegg9abe8c42019-07-09 20:45:20 +0000177 // Report undefined symbols
Sam Clegg4d888372024-07-02 11:23:41 -0700178 reportUndefined(file, sym);
Sam Clegg8fcf0122019-05-21 09:13:09 +0000179 }
Sam Clegg8fcf0122019-05-21 09:13:09 +0000180 }
181}
Fangrui Song33c59ab2019-10-10 05:25:39 +0000182
Sam Cleggd32f71a2023-03-06 09:55:00 -0800183} // namespace lld::wasm