1 //===- Relocations.cpp ----------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "Relocations.h"
11 #include "InputChunks.h"
12 #include "OutputSegment.h"
13 #include "SymbolTable.h"
14 #include "SyntheticSections.h"
17 using namespace llvm::wasm
;
21 static bool requiresGOTAccess(const Symbol
*sym
) {
25 config
->unresolvedSymbols
!= UnresolvedPolicy::ImportDynamic
)
27 if (sym
->isHidden() || sym
->isLocal())
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
))
36 static bool allowUndefined(const Symbol
* sym
) {
37 // Symbols that are explicitly imported are always allowed to be undefined at
39 if (sym
->isImported())
41 if (isa
<UndefinedFunction
>(sym
) && config
->importUndefined
)
44 return config
->allowUndefinedSymbols
.count(sym
->getName()) != 0;
47 static void reportUndefined(ObjFile
*file
, Symbol
*sym
) {
48 if (!allowUndefined(sym
)) {
49 switch (config
->unresolvedSymbols
) {
50 case UnresolvedPolicy::ReportError
:
51 error(toString(file
) + ": undefined symbol: " + toString(*sym
));
53 case UnresolvedPolicy::Warn
:
54 warn(toString(file
) + ": undefined symbol: " + toString(*sym
));
56 case UnresolvedPolicy::Ignore
:
57 LLVM_DEBUG(dbgs() << "ignoring undefined symbol: " + toString(*sym
) +
60 case UnresolvedPolicy::ImportDynamic
:
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.
78 static void addGOTEntry(Symbol
*sym
) {
79 if (requiresGOTAccess(sym
))
80 out
.importSec
->addGOTEntry(sym
);
82 out
.globalSec
->addInternalGOTEntry(sym
);
85 void scanRelocations(InputChunk
*chunk
) {
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
) {
92 // Mark target type as live
93 file
->typeMap
[reloc
.Index
] =
94 out
.typeSec
->registerType(types
[reloc
.Index
]);
95 file
->typeIsUsed
[reloc
.Index
] = true;
99 // Other relocation types all have a corresponding symbol
100 Symbol
*sym
= file
->getSymbols()[reloc
.Index
];
102 switch (reloc
.Type
) {
103 case R_WASM_TABLE_INDEX_I32
:
104 case R_WASM_TABLE_INDEX_I64
:
105 case R_WASM_TABLE_INDEX_SLEB
:
106 case R_WASM_TABLE_INDEX_SLEB64
:
107 case R_WASM_TABLE_INDEX_REL_SLEB
:
108 case R_WASM_TABLE_INDEX_REL_SLEB64
:
109 if (requiresGOTAccess(sym
))
111 out
.elemSec
->addEntry(cast
<FunctionSymbol
>(sym
));
113 case R_WASM_GLOBAL_INDEX_LEB
:
114 case R_WASM_GLOBAL_INDEX_I32
:
115 if (!isa
<GlobalSymbol
>(sym
))
118 case R_WASM_MEMORY_ADDR_TLS_SLEB
:
119 case R_WASM_MEMORY_ADDR_TLS_SLEB64
:
120 if (!sym
->isDefined()) {
121 error(toString(file
) + ": relocation " + relocTypeToString(reloc
.Type
) +
122 " cannot be used against an undefined symbol `" + toString(*sym
) +
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
128 if (config
->sharedMemory
) {
130 error(toString(file
) + ": relocation " +
131 relocTypeToString(reloc
.Type
) +
132 " cannot be used against non-TLS symbol `" + toString(*sym
) +
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 `" +
140 "` in non-TLS section: " + D
->segment
->outputSeg
->name
);
148 (sym
->isUndefined() &&
149 config
->unresolvedSymbols
== UnresolvedPolicy::ImportDynamic
)) {
150 switch (reloc
.Type
) {
151 case R_WASM_TABLE_INDEX_SLEB
:
152 case R_WASM_TABLE_INDEX_SLEB64
:
153 case R_WASM_MEMORY_ADDR_SLEB
:
154 case R_WASM_MEMORY_ADDR_LEB
:
155 case R_WASM_MEMORY_ADDR_SLEB64
:
156 case R_WASM_MEMORY_ADDR_LEB64
:
157 // Certain relocation types can't be used when building PIC output,
158 // since they would require absolute symbol addresses at link time.
159 error(toString(file
) + ": relocation " + relocTypeToString(reloc
.Type
) +
160 " cannot be used against symbol `" + toString(*sym
) +
161 "`; recompile with -fPIC");
163 case R_WASM_TABLE_INDEX_I32
:
164 case R_WASM_TABLE_INDEX_I64
:
165 case R_WASM_MEMORY_ADDR_I32
:
166 case R_WASM_MEMORY_ADDR_I64
:
167 // These relocation types are only present in the data section and
168 // will be converted into code by `generateRelocationCode`. This
169 // code requires the symbols to have GOT entries.
170 if (requiresGOTAccess(sym
))
176 if (!config
->relocatable
&& sym
->isUndefined()) {
177 switch (reloc
.Type
) {
178 case R_WASM_TABLE_INDEX_REL_SLEB
:
179 case R_WASM_TABLE_INDEX_REL_SLEB64
:
180 case R_WASM_MEMORY_ADDR_REL_SLEB
:
181 case R_WASM_MEMORY_ADDR_REL_SLEB64
:
182 // These relocation types are for symbols that exists relative to
183 // `__memory_base` or `__table_base` and as such only make sense for
185 error(toString(file
) + ": relocation " + relocTypeToString(reloc
.Type
) +
186 " is not supported against an undefined symbol `" +
187 toString(*sym
) + "`");
191 if (!sym
->isWeak()) {
192 // Report undefined symbols
193 reportUndefined(file
, sym
);
199 } // namespace lld::wasm