forked from OSchip/llvm-project
116 lines
4.0 KiB
C++
116 lines
4.0 KiB
C++
//===- 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"
|
|
#include "SyntheticSections.h"
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::wasm;
|
|
|
|
using namespace lld;
|
|
using namespace lld::wasm;
|
|
|
|
static bool requiresGOTAccess(const Symbol *sym) {
|
|
return config->isPic && !sym->isHidden() && !sym->isLocal();
|
|
}
|
|
|
|
static bool allowUndefined(const Symbol* sym) {
|
|
// Historically --allow-undefined doesn't work for data symbols since we don't
|
|
// have any way to represent these as imports in the final binary. The idea
|
|
// behind allowing undefined symbols is to allow importing these symbols from
|
|
// the embedder and we can't do this for data symbols (at least not without
|
|
// compiling with -fPIC)
|
|
if (isa<DataSymbol>(sym))
|
|
return false;
|
|
return (config->allowUndefined ||
|
|
config->allowUndefinedSymbols.count(sym->getName()) != 0);
|
|
}
|
|
|
|
static void reportUndefined(const Symbol* sym) {
|
|
assert(sym->isUndefined());
|
|
assert(!sym->isWeak());
|
|
if (!allowUndefined(sym))
|
|
error(toString(sym->getFile()) + ": undefined symbol: " + toString(*sym));
|
|
}
|
|
|
|
static void addGOTEntry(Symbol *sym) {
|
|
// In PIC mode a GOT entry is an imported global that the dynamic linker
|
|
// will assign.
|
|
// In non-PIC mode (i.e. when code compiled as fPIC is linked into a static
|
|
// binary) we create an internal wasm global with a fixed value that takes the
|
|
// place of th GOT entry and effectivly acts as an i32 const. This can
|
|
// potentially be optimized away at runtime or with a post-link tool.
|
|
// TODO(sbc): Linker relaxation might also be able to optimize this away.
|
|
if (config->isPic)
|
|
out.importSec->addGOTEntry(sym);
|
|
else
|
|
out.globalSec->addStaticGOTEntry(sym);
|
|
}
|
|
|
|
void lld::wasm::scanRelocations(InputChunk *chunk) {
|
|
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:
|
|
case R_WASM_TABLE_INDEX_SLEB:
|
|
case R_WASM_TABLE_INDEX_REL_SLEB:
|
|
if (requiresGOTAccess(sym))
|
|
break;
|
|
out.elemSec->addEntry(cast<FunctionSymbol>(sym));
|
|
break;
|
|
case R_WASM_GLOBAL_INDEX_LEB:
|
|
if (!isa<GlobalSymbol>(sym))
|
|
addGOTEntry(sym);
|
|
break;
|
|
}
|
|
|
|
if (config->isPic) {
|
|
switch (reloc.Type) {
|
|
case R_WASM_TABLE_INDEX_SLEB:
|
|
case R_WASM_MEMORY_ADDR_SLEB:
|
|
case R_WASM_MEMORY_ADDR_LEB:
|
|
// 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) +
|
|
" cannot be used against symbol " + toString(*sym) +
|
|
"; recompile with -fPIC");
|
|
break;
|
|
case R_WASM_TABLE_INDEX_I32:
|
|
case R_WASM_MEMORY_ADDR_I32:
|
|
// These relocation types are only present in the data section and
|
|
// will be converted into code by `generateRelocationCode`. This code
|
|
// requires the symbols to have GOT entires.
|
|
if (requiresGOTAccess(sym))
|
|
addGOTEntry(sym);
|
|
break;
|
|
}
|
|
} else {
|
|
// Report undefined symbols
|
|
if (sym->isUndefined() && !config->relocatable && !sym->isWeak())
|
|
reportUndefined(sym);
|
|
}
|
|
|
|
}
|
|
}
|