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