2019-05-21 09:13:09 +00:00
|
|
|
//===- Relocations.cpp ----------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "Relocations.h"
|
|
|
|
|
|
|
|
#include "InputChunks.h"
|
2020-11-10 17:46:52 -08:00
|
|
|
#include "OutputSegment.h"
|
2020-05-01 09:14:59 -07:00
|
|
|
#include "SymbolTable.h"
|
2019-05-21 09:13:09 +00:00
|
|
|
#include "SyntheticSections.h"
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace llvm::wasm;
|
|
|
|
|
2023-03-06 09:55:00 -08:00
|
|
|
namespace lld::wasm {
|
2020-10-07 14:48:37 -07:00
|
|
|
|
2019-05-21 09:13:09 +00:00
|
|
|
static bool requiresGOTAccess(const Symbol *sym) {
|
2024-07-12 13:26:52 -07:00
|
|
|
if (sym->isShared())
|
|
|
|
return true;
|
2024-01-18 15:01:21 -08:00
|
|
|
if (!ctx.isPic &&
|
2025-01-02 17:08:18 -08:00
|
|
|
ctx.arg.unresolvedSymbols != UnresolvedPolicy::ImportDynamic)
|
2020-10-07 14:48:37 -07:00
|
|
|
return false;
|
|
|
|
if (sym->isHidden() || sym->isLocal())
|
|
|
|
return false;
|
|
|
|
// With `-Bsymbolic` (or when building an executable) as don't need to use
|
|
|
|
// the GOT for symbols that are defined within the current module.
|
2025-01-02 17:08:18 -08:00
|
|
|
if (sym->isDefined() && (!ctx.arg.shared || ctx.arg.bsymbolic))
|
2020-10-07 14:48:37 -07:00
|
|
|
return false;
|
|
|
|
return true;
|
2019-05-21 09:13:09 +00:00
|
|
|
}
|
|
|
|
|
2019-07-09 20:45:20 +00:00
|
|
|
static bool allowUndefined(const Symbol* sym) {
|
2022-12-06 16:49:13 -08:00
|
|
|
// Symbols that are explicitly imported are always allowed to be undefined at
|
2021-10-04 15:55:37 -07:00
|
|
|
// link time.
|
2022-12-06 16:49:13 -08:00
|
|
|
if (sym->isImported())
|
2021-10-04 15:55:37 -07:00
|
|
|
return true;
|
2025-01-02 17:08:18 -08:00
|
|
|
if (isa<UndefinedFunction>(sym) && ctx.arg.importUndefined)
|
2021-10-04 15:55:37 -07:00
|
|
|
return true;
|
|
|
|
|
2025-01-02 17:08:18 -08:00
|
|
|
return ctx.arg.allowUndefinedSymbols.count(sym->getName()) != 0;
|
2019-07-09 20:45:20 +00:00
|
|
|
}
|
|
|
|
|
2024-07-02 11:23:41 -07:00
|
|
|
static void reportUndefined(ObjFile *file, Symbol *sym) {
|
2020-05-01 09:14:59 -07:00
|
|
|
if (!allowUndefined(sym)) {
|
2025-01-02 17:08:18 -08:00
|
|
|
switch (ctx.arg.unresolvedSymbols) {
|
2020-05-01 09:14:59 -07:00
|
|
|
case UnresolvedPolicy::ReportError:
|
2024-07-02 11:23:41 -07:00
|
|
|
error(toString(file) + ": undefined symbol: " + toString(*sym));
|
2020-05-01 09:14:59 -07:00
|
|
|
break;
|
|
|
|
case UnresolvedPolicy::Warn:
|
2024-07-02 11:23:41 -07:00
|
|
|
warn(toString(file) + ": undefined symbol: " + toString(*sym));
|
2020-05-01 09:14:59 -07:00
|
|
|
break;
|
|
|
|
case UnresolvedPolicy::Ignore:
|
2021-05-27 14:27:10 -07:00
|
|
|
LLVM_DEBUG(dbgs() << "ignoring undefined symbol: " + toString(*sym) +
|
|
|
|
"\n");
|
2020-05-01 09:14:59 -07:00
|
|
|
break;
|
2020-11-16 10:11:37 -08:00
|
|
|
case UnresolvedPolicy::ImportDynamic:
|
|
|
|
break;
|
2020-05-01 09:14:59 -07:00
|
|
|
}
|
2024-01-19 09:32:22 -08:00
|
|
|
|
|
|
|
if (auto *f = dyn_cast<UndefinedFunction>(sym)) {
|
|
|
|
if (!f->stubFunction &&
|
2025-01-02 17:08:18 -08:00
|
|
|
ctx.arg.unresolvedSymbols != UnresolvedPolicy::ImportDynamic &&
|
|
|
|
!ctx.arg.importUndefined) {
|
2024-01-19 09:32:22 -08:00
|
|
|
f->stubFunction = symtab->createUndefinedStub(*f->getSignature());
|
|
|
|
f->stubFunction->markLive();
|
|
|
|
// Mark the function itself as a stub which prevents it from being
|
|
|
|
// assigned a table entry.
|
|
|
|
f->isStub = true;
|
|
|
|
}
|
|
|
|
}
|
2020-05-01 09:14:59 -07:00
|
|
|
}
|
2019-07-09 20:45:20 +00:00
|
|
|
}
|
|
|
|
|
2019-08-13 17:02:02 +00:00
|
|
|
static void addGOTEntry(Symbol *sym) {
|
2020-10-07 14:48:37 -07:00
|
|
|
if (requiresGOTAccess(sym))
|
2019-08-13 17:02:02 +00:00
|
|
|
out.importSec->addGOTEntry(sym);
|
|
|
|
else
|
2020-10-07 14:48:37 -07:00
|
|
|
out.globalSec->addInternalGOTEntry(sym);
|
2019-08-13 17:02:02 +00:00
|
|
|
}
|
|
|
|
|
2019-10-10 05:25:39 +00:00
|
|
|
void scanRelocations(InputChunk *chunk) {
|
2019-05-21 09:13:09 +00:00
|
|
|
if (!chunk->live)
|
|
|
|
return;
|
|
|
|
ObjFile *file = chunk->file;
|
|
|
|
ArrayRef<WasmSignature> types = file->getWasmObj()->types();
|
|
|
|
for (const WasmRelocation &reloc : chunk->getRelocations()) {
|
|
|
|
if (reloc.Type == R_WASM_TYPE_INDEX_LEB) {
|
|
|
|
// Mark target type as live
|
|
|
|
file->typeMap[reloc.Index] =
|
|
|
|
out.typeSec->registerType(types[reloc.Index]);
|
|
|
|
file->typeIsUsed[reloc.Index] = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Other relocation types all have a corresponding symbol
|
|
|
|
Symbol *sym = file->getSymbols()[reloc.Index];
|
|
|
|
|
|
|
|
switch (reloc.Type) {
|
|
|
|
case R_WASM_TABLE_INDEX_I32:
|
2020-07-10 16:51:01 -07:00
|
|
|
case R_WASM_TABLE_INDEX_I64:
|
2019-05-21 09:13:09 +00:00
|
|
|
case R_WASM_TABLE_INDEX_SLEB:
|
2020-07-10 16:51:01 -07:00
|
|
|
case R_WASM_TABLE_INDEX_SLEB64:
|
2019-05-21 09:13:09 +00:00
|
|
|
case R_WASM_TABLE_INDEX_REL_SLEB:
|
2021-04-22 16:54:58 -07:00
|
|
|
case R_WASM_TABLE_INDEX_REL_SLEB64:
|
2019-05-21 09:13:09 +00:00
|
|
|
if (requiresGOTAccess(sym))
|
|
|
|
break;
|
|
|
|
out.elemSec->addEntry(cast<FunctionSymbol>(sym));
|
|
|
|
break;
|
|
|
|
case R_WASM_GLOBAL_INDEX_LEB:
|
2020-03-19 19:53:51 -07:00
|
|
|
case R_WASM_GLOBAL_INDEX_I32:
|
2019-05-21 09:13:09 +00:00
|
|
|
if (!isa<GlobalSymbol>(sym))
|
2019-08-13 17:02:02 +00:00
|
|
|
addGOTEntry(sym);
|
2019-05-21 09:13:09 +00:00
|
|
|
break;
|
2020-11-10 17:46:52 -08:00
|
|
|
case R_WASM_MEMORY_ADDR_TLS_SLEB:
|
2021-07-15 13:24:28 -07:00
|
|
|
case R_WASM_MEMORY_ADDR_TLS_SLEB64:
|
2022-02-11 15:53:28 -08:00
|
|
|
if (!sym->isDefined()) {
|
|
|
|
error(toString(file) + ": relocation " + relocTypeToString(reloc.Type) +
|
|
|
|
" cannot be used against an undefined symbol `" + toString(*sym) +
|
|
|
|
"`");
|
|
|
|
}
|
2021-05-21 09:58:21 -07:00
|
|
|
// In single-threaded builds TLS is lowered away and TLS data can be
|
|
|
|
// merged with normal data and allowing TLS relocation in non-TLS
|
|
|
|
// segments.
|
2025-01-02 17:08:18 -08:00
|
|
|
if (ctx.arg.sharedMemory) {
|
2021-09-08 04:53:13 -04:00
|
|
|
if (!sym->isTLS()) {
|
|
|
|
error(toString(file) + ": relocation " +
|
|
|
|
relocTypeToString(reloc.Type) +
|
|
|
|
" cannot be used against non-TLS symbol `" + toString(*sym) +
|
|
|
|
"`");
|
|
|
|
}
|
2021-05-21 09:58:21 -07:00
|
|
|
if (auto *D = dyn_cast<DefinedData>(sym)) {
|
|
|
|
if (!D->segment->outputSeg->isTLS()) {
|
|
|
|
error(toString(file) + ": relocation " +
|
|
|
|
relocTypeToString(reloc.Type) + " cannot be used against `" +
|
|
|
|
toString(*sym) +
|
|
|
|
"` in non-TLS section: " + D->segment->outputSeg->name);
|
|
|
|
}
|
2020-11-10 17:46:52 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2019-05-21 09:13:09 +00:00
|
|
|
}
|
|
|
|
|
2025-01-03 11:53:21 +09:00
|
|
|
if (ctx.isPic || sym->isShared() ||
|
2020-11-16 10:11:37 -08:00
|
|
|
(sym->isUndefined() &&
|
2025-01-02 17:08:18 -08:00
|
|
|
ctx.arg.unresolvedSymbols == UnresolvedPolicy::ImportDynamic)) {
|
2019-05-21 09:13:09 +00:00
|
|
|
switch (reloc.Type) {
|
|
|
|
case R_WASM_TABLE_INDEX_SLEB:
|
2020-07-10 16:51:01 -07:00
|
|
|
case R_WASM_TABLE_INDEX_SLEB64:
|
2019-05-21 09:13:09 +00:00
|
|
|
case R_WASM_MEMORY_ADDR_SLEB:
|
|
|
|
case R_WASM_MEMORY_ADDR_LEB:
|
2020-06-05 09:03:12 -07:00
|
|
|
case R_WASM_MEMORY_ADDR_SLEB64:
|
|
|
|
case R_WASM_MEMORY_ADDR_LEB64:
|
2019-05-21 09:13:09 +00:00
|
|
|
// Certain relocation types can't be used when building PIC output,
|
|
|
|
// since they would require absolute symbol addresses at link time.
|
|
|
|
error(toString(file) + ": relocation " + relocTypeToString(reloc.Type) +
|
2020-11-16 10:11:37 -08:00
|
|
|
" cannot be used against symbol `" + toString(*sym) +
|
|
|
|
"`; recompile with -fPIC");
|
2019-05-21 09:13:09 +00:00
|
|
|
break;
|
|
|
|
case R_WASM_TABLE_INDEX_I32:
|
2020-07-10 16:51:01 -07:00
|
|
|
case R_WASM_TABLE_INDEX_I64:
|
2019-05-21 09:13:09 +00:00
|
|
|
case R_WASM_MEMORY_ADDR_I32:
|
2020-06-05 09:03:12 -07:00
|
|
|
case R_WASM_MEMORY_ADDR_I64:
|
2019-05-21 09:13:09 +00:00
|
|
|
// These relocation types are only present in the data section and
|
2024-07-12 13:26:52 -07:00
|
|
|
// will be converted into code by `generateRelocationCode`. This
|
|
|
|
// code requires the symbols to have GOT entries.
|
2019-05-21 09:13:09 +00:00
|
|
|
if (requiresGOTAccess(sym))
|
2019-08-13 17:02:02 +00:00
|
|
|
addGOTEntry(sym);
|
2019-05-21 09:13:09 +00:00
|
|
|
break;
|
|
|
|
}
|
2024-07-12 13:26:52 -07:00
|
|
|
}
|
|
|
|
|
2025-01-02 17:08:18 -08:00
|
|
|
if (!ctx.arg.relocatable && sym->isUndefined()) {
|
2024-09-18 17:40:30 +02:00
|
|
|
switch (reloc.Type) {
|
|
|
|
case R_WASM_TABLE_INDEX_REL_SLEB:
|
|
|
|
case R_WASM_TABLE_INDEX_REL_SLEB64:
|
|
|
|
case R_WASM_MEMORY_ADDR_REL_SLEB:
|
|
|
|
case R_WASM_MEMORY_ADDR_REL_SLEB64:
|
|
|
|
// These relocation types are for symbols that exists relative to
|
|
|
|
// `__memory_base` or `__table_base` and as such only make sense for
|
|
|
|
// defined symbols.
|
|
|
|
error(toString(file) + ": relocation " + relocTypeToString(reloc.Type) +
|
|
|
|
" is not supported against an undefined symbol `" +
|
|
|
|
toString(*sym) + "`");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-09-24 11:14:07 -07:00
|
|
|
if (!sym->isWeak()) {
|
|
|
|
// Report undefined symbols
|
|
|
|
reportUndefined(file, sym);
|
|
|
|
}
|
2019-05-21 09:13:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-10-10 05:25:39 +00:00
|
|
|
|
2023-03-06 09:55:00 -08:00
|
|
|
} // namespace lld::wasm
|