[wasm-ld] Refactor WasmSym from static globals to per-link context (#134970)
Towards This change moves WasmSym from a static global struct to an instance owned by Ctx, allowing it to be reset cleanly between linker runs. This enables safe support for multiple invocations of wasm-ld within the same process Changes done - Converted WasmSym from a static struct to a regular struct with instance members. - Added a std::unique_ptr<WasmSym> wasmSym field inside Ctx. - Reset wasmSym in Ctx::reset() to clear state between links. - Replaced all WasmSym:: references with ctx.wasmSym->. - Removed global symbol definitions from Symbols.cpp that are no longer needed. Clearing wasmSym in ctx.reset() ensures a clean slate for each link invocation, preventing symbol leakage across runs—critical when using wasm-ld/lld as a reentrant library where global state can cause subtle, hard-to-debug errors. --------- Co-authored-by: Vassil Vassilev <v.g.vassilev@gmail.com> (cherry picked from commit 9cbbb74d370c09e13b8412f21dccb7d2c4afc6a4)
This commit is contained in:
parent
b7b834e2a2
commit
0019b7d0ae
@ -32,6 +32,11 @@ class InputTable;
|
|||||||
class InputGlobal;
|
class InputGlobal;
|
||||||
class InputFunction;
|
class InputFunction;
|
||||||
class Symbol;
|
class Symbol;
|
||||||
|
class DefinedData;
|
||||||
|
class GlobalSymbol;
|
||||||
|
class DefinedFunction;
|
||||||
|
class UndefinedGlobal;
|
||||||
|
class TableSymbol;
|
||||||
|
|
||||||
// For --unresolved-symbols.
|
// For --unresolved-symbols.
|
||||||
enum class UnresolvedPolicy { ReportError, Warn, Ignore, ImportDynamic };
|
enum class UnresolvedPolicy { ReportError, Warn, Ignore, ImportDynamic };
|
||||||
@ -139,6 +144,107 @@ struct Ctx {
|
|||||||
llvm::SmallVector<InputGlobal *, 0> syntheticGlobals;
|
llvm::SmallVector<InputGlobal *, 0> syntheticGlobals;
|
||||||
llvm::SmallVector<InputTable *, 0> syntheticTables;
|
llvm::SmallVector<InputTable *, 0> syntheticTables;
|
||||||
|
|
||||||
|
// linker-generated symbols
|
||||||
|
struct WasmSym {
|
||||||
|
// __global_base
|
||||||
|
// Symbol marking the start of the global section.
|
||||||
|
DefinedData *globalBase;
|
||||||
|
|
||||||
|
// __stack_pointer/__stack_low/__stack_high
|
||||||
|
// Global that holds current value of stack pointer and data symbols marking
|
||||||
|
// the start and end of the stack region. stackPointer is initialized to
|
||||||
|
// stackHigh and grows downwards towards stackLow
|
||||||
|
GlobalSymbol *stackPointer;
|
||||||
|
DefinedData *stackLow;
|
||||||
|
DefinedData *stackHigh;
|
||||||
|
|
||||||
|
// __tls_base
|
||||||
|
// Global that holds the address of the base of the current thread's
|
||||||
|
// TLS block.
|
||||||
|
GlobalSymbol *tlsBase;
|
||||||
|
|
||||||
|
// __tls_size
|
||||||
|
// Symbol whose value is the size of the TLS block.
|
||||||
|
GlobalSymbol *tlsSize;
|
||||||
|
|
||||||
|
// __tls_size
|
||||||
|
// Symbol whose value is the alignment of the TLS block.
|
||||||
|
GlobalSymbol *tlsAlign;
|
||||||
|
|
||||||
|
// __data_end
|
||||||
|
// Symbol marking the end of the data and bss.
|
||||||
|
DefinedData *dataEnd;
|
||||||
|
|
||||||
|
// __heap_base/__heap_end
|
||||||
|
// Symbols marking the beginning and end of the "heap". It starts at the end
|
||||||
|
// of the data, bss and explicit stack, and extends to the end of the linear
|
||||||
|
// memory allocated by wasm-ld. This region of memory is not used by the
|
||||||
|
// linked code, so it may be used as a backing store for `sbrk` or `malloc`
|
||||||
|
// implementations.
|
||||||
|
DefinedData *heapBase;
|
||||||
|
DefinedData *heapEnd;
|
||||||
|
|
||||||
|
// __wasm_init_memory_flag
|
||||||
|
// Symbol whose contents are nonzero iff memory has already been
|
||||||
|
// initialized.
|
||||||
|
DefinedData *initMemoryFlag;
|
||||||
|
|
||||||
|
// __wasm_init_memory
|
||||||
|
// Function that initializes passive data segments during instantiation.
|
||||||
|
DefinedFunction *initMemory;
|
||||||
|
|
||||||
|
// __wasm_call_ctors
|
||||||
|
// Function that directly calls all ctors in priority order.
|
||||||
|
DefinedFunction *callCtors;
|
||||||
|
|
||||||
|
// __wasm_call_dtors
|
||||||
|
// Function that calls the libc/etc. cleanup function.
|
||||||
|
DefinedFunction *callDtors;
|
||||||
|
|
||||||
|
// __wasm_apply_global_relocs
|
||||||
|
// Function that applies relocations to wasm globals post-instantiation.
|
||||||
|
// Unlike __wasm_apply_data_relocs this needs to run on every thread.
|
||||||
|
DefinedFunction *applyGlobalRelocs;
|
||||||
|
|
||||||
|
// __wasm_apply_tls_relocs
|
||||||
|
// Like __wasm_apply_data_relocs but for TLS section. These must be
|
||||||
|
// delayed until __wasm_init_tls.
|
||||||
|
DefinedFunction *applyTLSRelocs;
|
||||||
|
|
||||||
|
// __wasm_apply_global_tls_relocs
|
||||||
|
// Like applyGlobalRelocs but for globals that hold TLS addresses. These
|
||||||
|
// must be delayed until __wasm_init_tls.
|
||||||
|
DefinedFunction *applyGlobalTLSRelocs;
|
||||||
|
|
||||||
|
// __wasm_init_tls
|
||||||
|
// Function that allocates thread-local storage and initializes it.
|
||||||
|
DefinedFunction *initTLS;
|
||||||
|
|
||||||
|
// Pointer to the function that is to be used in the start section.
|
||||||
|
// (normally an alias of initMemory, or applyGlobalRelocs).
|
||||||
|
DefinedFunction *startFunction;
|
||||||
|
|
||||||
|
// __dso_handle
|
||||||
|
// Symbol used in calls to __cxa_atexit to determine current DLL
|
||||||
|
DefinedData *dsoHandle;
|
||||||
|
|
||||||
|
// __table_base
|
||||||
|
// Used in PIC code for offset of indirect function table
|
||||||
|
UndefinedGlobal *tableBase;
|
||||||
|
DefinedData *definedTableBase;
|
||||||
|
|
||||||
|
// __memory_base
|
||||||
|
// Used in PIC code for offset of global data
|
||||||
|
UndefinedGlobal *memoryBase;
|
||||||
|
DefinedData *definedMemoryBase;
|
||||||
|
|
||||||
|
// __indirect_function_table
|
||||||
|
// Used as an address space for function pointers, with each function that
|
||||||
|
// is used as a function pointer being allocated a slot.
|
||||||
|
TableSymbol *indirectFunctionTable;
|
||||||
|
};
|
||||||
|
WasmSym sym;
|
||||||
|
|
||||||
// True if we are creating position-independent code.
|
// True if we are creating position-independent code.
|
||||||
bool isPic = false;
|
bool isPic = false;
|
||||||
|
|
||||||
|
@ -70,6 +70,7 @@ void Ctx::reset() {
|
|||||||
isPic = false;
|
isPic = false;
|
||||||
legacyFunctionTable = false;
|
legacyFunctionTable = false;
|
||||||
emitBssSegments = false;
|
emitBssSegments = false;
|
||||||
|
sym = WasmSym{};
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -941,14 +942,14 @@ static void createSyntheticSymbols() {
|
|||||||
true};
|
true};
|
||||||
static llvm::wasm::WasmGlobalType mutableGlobalTypeI64 = {WASM_TYPE_I64,
|
static llvm::wasm::WasmGlobalType mutableGlobalTypeI64 = {WASM_TYPE_I64,
|
||||||
true};
|
true};
|
||||||
WasmSym::callCtors = symtab->addSyntheticFunction(
|
ctx.sym.callCtors = symtab->addSyntheticFunction(
|
||||||
"__wasm_call_ctors", WASM_SYMBOL_VISIBILITY_HIDDEN,
|
"__wasm_call_ctors", WASM_SYMBOL_VISIBILITY_HIDDEN,
|
||||||
make<SyntheticFunction>(nullSignature, "__wasm_call_ctors"));
|
make<SyntheticFunction>(nullSignature, "__wasm_call_ctors"));
|
||||||
|
|
||||||
bool is64 = ctx.arg.is64.value_or(false);
|
bool is64 = ctx.arg.is64.value_or(false);
|
||||||
|
|
||||||
if (ctx.isPic) {
|
if (ctx.isPic) {
|
||||||
WasmSym::stackPointer =
|
ctx.sym.stackPointer =
|
||||||
createUndefinedGlobal("__stack_pointer", ctx.arg.is64.value_or(false)
|
createUndefinedGlobal("__stack_pointer", ctx.arg.is64.value_or(false)
|
||||||
? &mutableGlobalTypeI64
|
? &mutableGlobalTypeI64
|
||||||
: &mutableGlobalTypeI32);
|
: &mutableGlobalTypeI32);
|
||||||
@ -958,25 +959,24 @@ static void createSyntheticSymbols() {
|
|||||||
// See:
|
// See:
|
||||||
// https://github.com/WebAssembly/tool-conventions/blob/main/DynamicLinking.md
|
// https://github.com/WebAssembly/tool-conventions/blob/main/DynamicLinking.md
|
||||||
auto *globalType = is64 ? &globalTypeI64 : &globalTypeI32;
|
auto *globalType = is64 ? &globalTypeI64 : &globalTypeI32;
|
||||||
WasmSym::memoryBase = createUndefinedGlobal("__memory_base", globalType);
|
ctx.sym.memoryBase = createUndefinedGlobal("__memory_base", globalType);
|
||||||
WasmSym::tableBase = createUndefinedGlobal("__table_base", globalType);
|
ctx.sym.tableBase = createUndefinedGlobal("__table_base", globalType);
|
||||||
WasmSym::memoryBase->markLive();
|
ctx.sym.memoryBase->markLive();
|
||||||
WasmSym::tableBase->markLive();
|
ctx.sym.tableBase->markLive();
|
||||||
} else {
|
} else {
|
||||||
// For non-PIC code
|
// For non-PIC code
|
||||||
WasmSym::stackPointer = createGlobalVariable("__stack_pointer", true);
|
ctx.sym.stackPointer = createGlobalVariable("__stack_pointer", true);
|
||||||
WasmSym::stackPointer->markLive();
|
ctx.sym.stackPointer->markLive();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.arg.sharedMemory) {
|
if (ctx.arg.sharedMemory) {
|
||||||
WasmSym::tlsBase = createGlobalVariable("__tls_base", true);
|
ctx.sym.tlsBase = createGlobalVariable("__tls_base", true);
|
||||||
WasmSym::tlsSize = createGlobalVariable("__tls_size", false);
|
ctx.sym.tlsSize = createGlobalVariable("__tls_size", false);
|
||||||
WasmSym::tlsAlign = createGlobalVariable("__tls_align", false);
|
ctx.sym.tlsAlign = createGlobalVariable("__tls_align", false);
|
||||||
WasmSym::initTLS = symtab->addSyntheticFunction(
|
ctx.sym.initTLS = symtab->addSyntheticFunction(
|
||||||
"__wasm_init_tls", WASM_SYMBOL_VISIBILITY_HIDDEN,
|
"__wasm_init_tls", WASM_SYMBOL_VISIBILITY_HIDDEN,
|
||||||
make<SyntheticFunction>(
|
make<SyntheticFunction>(is64 ? i64ArgSignature : i32ArgSignature,
|
||||||
is64 ? i64ArgSignature : i32ArgSignature,
|
"__wasm_init_tls"));
|
||||||
"__wasm_init_tls"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -984,19 +984,19 @@ static void createOptionalSymbols() {
|
|||||||
if (ctx.arg.relocatable)
|
if (ctx.arg.relocatable)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
WasmSym::dsoHandle = symtab->addOptionalDataSymbol("__dso_handle");
|
ctx.sym.dsoHandle = symtab->addOptionalDataSymbol("__dso_handle");
|
||||||
|
|
||||||
if (!ctx.arg.shared)
|
if (!ctx.arg.shared)
|
||||||
WasmSym::dataEnd = symtab->addOptionalDataSymbol("__data_end");
|
ctx.sym.dataEnd = symtab->addOptionalDataSymbol("__data_end");
|
||||||
|
|
||||||
if (!ctx.isPic) {
|
if (!ctx.isPic) {
|
||||||
WasmSym::stackLow = symtab->addOptionalDataSymbol("__stack_low");
|
ctx.sym.stackLow = symtab->addOptionalDataSymbol("__stack_low");
|
||||||
WasmSym::stackHigh = symtab->addOptionalDataSymbol("__stack_high");
|
ctx.sym.stackHigh = symtab->addOptionalDataSymbol("__stack_high");
|
||||||
WasmSym::globalBase = symtab->addOptionalDataSymbol("__global_base");
|
ctx.sym.globalBase = symtab->addOptionalDataSymbol("__global_base");
|
||||||
WasmSym::heapBase = symtab->addOptionalDataSymbol("__heap_base");
|
ctx.sym.heapBase = symtab->addOptionalDataSymbol("__heap_base");
|
||||||
WasmSym::heapEnd = symtab->addOptionalDataSymbol("__heap_end");
|
ctx.sym.heapEnd = symtab->addOptionalDataSymbol("__heap_end");
|
||||||
WasmSym::definedMemoryBase = symtab->addOptionalDataSymbol("__memory_base");
|
ctx.sym.definedMemoryBase = symtab->addOptionalDataSymbol("__memory_base");
|
||||||
WasmSym::definedTableBase = symtab->addOptionalDataSymbol("__table_base");
|
ctx.sym.definedTableBase = symtab->addOptionalDataSymbol("__table_base");
|
||||||
}
|
}
|
||||||
|
|
||||||
// For non-shared memory programs we still need to define __tls_base since we
|
// For non-shared memory programs we still need to define __tls_base since we
|
||||||
@ -1009,7 +1009,7 @@ static void createOptionalSymbols() {
|
|||||||
// __tls_size and __tls_align are not needed in this case since they are only
|
// __tls_size and __tls_align are not needed in this case since they are only
|
||||||
// needed for __wasm_init_tls (which we do not create in this case).
|
// needed for __wasm_init_tls (which we do not create in this case).
|
||||||
if (!ctx.arg.sharedMemory)
|
if (!ctx.arg.sharedMemory)
|
||||||
WasmSym::tlsBase = createOptionalGlobal("__tls_base", false);
|
ctx.sym.tlsBase = createOptionalGlobal("__tls_base", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void processStubLibrariesPreLTO() {
|
static void processStubLibrariesPreLTO() {
|
||||||
@ -1384,9 +1384,9 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
|
|||||||
// by libc/etc., because destructors are registered dynamically with
|
// by libc/etc., because destructors are registered dynamically with
|
||||||
// `__cxa_atexit` and friends.
|
// `__cxa_atexit` and friends.
|
||||||
if (!ctx.arg.relocatable && !ctx.arg.shared &&
|
if (!ctx.arg.relocatable && !ctx.arg.shared &&
|
||||||
!WasmSym::callCtors->isUsedInRegularObj &&
|
!ctx.sym.callCtors->isUsedInRegularObj &&
|
||||||
WasmSym::callCtors->getName() != ctx.arg.entry &&
|
ctx.sym.callCtors->getName() != ctx.arg.entry &&
|
||||||
!ctx.arg.exportedSymbols.count(WasmSym::callCtors->getName())) {
|
!ctx.arg.exportedSymbols.count(ctx.sym.callCtors->getName())) {
|
||||||
if (Symbol *callDtors =
|
if (Symbol *callDtors =
|
||||||
handleUndefined("__wasm_call_dtors", "<internal>")) {
|
handleUndefined("__wasm_call_dtors", "<internal>")) {
|
||||||
if (auto *callDtorsFunc = dyn_cast<DefinedFunction>(callDtors)) {
|
if (auto *callDtorsFunc = dyn_cast<DefinedFunction>(callDtors)) {
|
||||||
@ -1395,7 +1395,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
|
|||||||
!callDtorsFunc->signature->Returns.empty())) {
|
!callDtorsFunc->signature->Returns.empty())) {
|
||||||
error("__wasm_call_dtors must have no argument or return values");
|
error("__wasm_call_dtors must have no argument or return values");
|
||||||
}
|
}
|
||||||
WasmSym::callDtors = callDtorsFunc;
|
ctx.sym.callDtors = callDtorsFunc;
|
||||||
} else {
|
} else {
|
||||||
error("__wasm_call_dtors must be a function");
|
error("__wasm_call_dtors must be a function");
|
||||||
}
|
}
|
||||||
@ -1488,7 +1488,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
|
|||||||
markLive();
|
markLive();
|
||||||
|
|
||||||
// Provide the indirect function table if needed.
|
// Provide the indirect function table if needed.
|
||||||
WasmSym::indirectFunctionTable =
|
ctx.sym.indirectFunctionTable =
|
||||||
symtab->resolveIndirectFunctionTable(/*required =*/false);
|
symtab->resolveIndirectFunctionTable(/*required =*/false);
|
||||||
|
|
||||||
if (errorCount())
|
if (errorCount())
|
||||||
|
@ -397,9 +397,9 @@ bool InputChunk::generateRelocationCode(raw_ostream &os) const {
|
|||||||
if (ctx.isPic) {
|
if (ctx.isPic) {
|
||||||
writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
|
writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
|
||||||
if (isTLS())
|
if (isTLS())
|
||||||
writeUleb128(os, WasmSym::tlsBase->getGlobalIndex(), "tls_base");
|
writeUleb128(os, ctx.sym.tlsBase->getGlobalIndex(), "tls_base");
|
||||||
else
|
else
|
||||||
writeUleb128(os, WasmSym::memoryBase->getGlobalIndex(), "memory_base");
|
writeUleb128(os, ctx.sym.memoryBase->getGlobalIndex(), "memory_base");
|
||||||
writeU8(os, opcode_ptr_add, "ADD");
|
writeU8(os, opcode_ptr_add, "ADD");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -422,12 +422,12 @@ bool InputChunk::generateRelocationCode(raw_ostream &os) const {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
assert(ctx.isPic);
|
assert(ctx.isPic);
|
||||||
const GlobalSymbol* baseSymbol = WasmSym::memoryBase;
|
const GlobalSymbol *baseSymbol = ctx.sym.memoryBase;
|
||||||
if (rel.Type == R_WASM_TABLE_INDEX_I32 ||
|
if (rel.Type == R_WASM_TABLE_INDEX_I32 ||
|
||||||
rel.Type == R_WASM_TABLE_INDEX_I64)
|
rel.Type == R_WASM_TABLE_INDEX_I64)
|
||||||
baseSymbol = WasmSym::tableBase;
|
baseSymbol = ctx.sym.tableBase;
|
||||||
else if (sym->isTLS())
|
else if (sym->isTLS())
|
||||||
baseSymbol = WasmSym::tlsBase;
|
baseSymbol = ctx.sym.tlsBase;
|
||||||
writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
|
writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
|
||||||
writeUleb128(os, baseSymbol->getGlobalIndex(), "base");
|
writeUleb128(os, baseSymbol->getGlobalIndex(), "base");
|
||||||
writeU8(os, opcode_reloc_const, "CONST");
|
writeU8(os, opcode_reloc_const, "CONST");
|
||||||
|
@ -114,8 +114,8 @@ void MarkLive::run() {
|
|||||||
if (sym->isNoStrip() || sym->isExported())
|
if (sym->isNoStrip() || sym->isExported())
|
||||||
enqueue(sym);
|
enqueue(sym);
|
||||||
|
|
||||||
if (WasmSym::callDtors)
|
if (ctx.sym.callDtors)
|
||||||
enqueue(WasmSym::callDtors);
|
enqueue(ctx.sym.callDtors);
|
||||||
|
|
||||||
for (const ObjFile *obj : ctx.objectFiles)
|
for (const ObjFile *obj : ctx.objectFiles)
|
||||||
if (obj->isLive()) {
|
if (obj->isLive()) {
|
||||||
@ -131,7 +131,7 @@ void MarkLive::run() {
|
|||||||
// If we have any non-discarded init functions, mark `__wasm_call_ctors` as
|
// If we have any non-discarded init functions, mark `__wasm_call_ctors` as
|
||||||
// live so that we assign it an index and call it.
|
// live so that we assign it an index and call it.
|
||||||
if (isCallCtorsLive())
|
if (isCallCtorsLive())
|
||||||
WasmSym::callCtors->markLive();
|
ctx.sym.callCtors->markLive();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MarkLive::mark() {
|
void MarkLive::mark() {
|
||||||
|
@ -123,7 +123,7 @@ void DataSection::finalizeContents() {
|
|||||||
if ((segment->initFlags & WASM_DATA_SEGMENT_IS_PASSIVE) == 0) {
|
if ((segment->initFlags & WASM_DATA_SEGMENT_IS_PASSIVE) == 0) {
|
||||||
if (ctx.isPic && ctx.arg.extendedConst) {
|
if (ctx.isPic && ctx.arg.extendedConst) {
|
||||||
writeU8(os, WASM_OPCODE_GLOBAL_GET, "global get");
|
writeU8(os, WASM_OPCODE_GLOBAL_GET, "global get");
|
||||||
writeUleb128(os, WasmSym::memoryBase->getGlobalIndex(),
|
writeUleb128(os, ctx.sym.memoryBase->getGlobalIndex(),
|
||||||
"literal (global index)");
|
"literal (global index)");
|
||||||
if (segment->startVA) {
|
if (segment->startVA) {
|
||||||
writePtrConst(os, segment->startVA, is64, "offset");
|
writePtrConst(os, segment->startVA, is64, "offset");
|
||||||
@ -136,7 +136,7 @@ void DataSection::finalizeContents() {
|
|||||||
if (ctx.isPic) {
|
if (ctx.isPic) {
|
||||||
assert(segment->startVA == 0);
|
assert(segment->startVA == 0);
|
||||||
initExpr.Inst.Opcode = WASM_OPCODE_GLOBAL_GET;
|
initExpr.Inst.Opcode = WASM_OPCODE_GLOBAL_GET;
|
||||||
initExpr.Inst.Value.Global = WasmSym::memoryBase->getGlobalIndex();
|
initExpr.Inst.Value.Global = ctx.sym.memoryBase->getGlobalIndex();
|
||||||
} else {
|
} else {
|
||||||
initExpr = intConst(segment->startVA, is64);
|
initExpr = intConst(segment->startVA, is64);
|
||||||
}
|
}
|
||||||
|
@ -77,31 +77,6 @@ std::string toString(wasm::Symbol::Kind kind) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace wasm {
|
namespace wasm {
|
||||||
DefinedFunction *WasmSym::callCtors;
|
|
||||||
DefinedFunction *WasmSym::callDtors;
|
|
||||||
DefinedFunction *WasmSym::initMemory;
|
|
||||||
DefinedFunction *WasmSym::applyGlobalRelocs;
|
|
||||||
DefinedFunction *WasmSym::applyTLSRelocs;
|
|
||||||
DefinedFunction *WasmSym::applyGlobalTLSRelocs;
|
|
||||||
DefinedFunction *WasmSym::initTLS;
|
|
||||||
DefinedFunction *WasmSym::startFunction;
|
|
||||||
DefinedData *WasmSym::dsoHandle;
|
|
||||||
DefinedData *WasmSym::dataEnd;
|
|
||||||
DefinedData *WasmSym::globalBase;
|
|
||||||
DefinedData *WasmSym::heapBase;
|
|
||||||
DefinedData *WasmSym::heapEnd;
|
|
||||||
DefinedData *WasmSym::initMemoryFlag;
|
|
||||||
GlobalSymbol *WasmSym::stackPointer;
|
|
||||||
DefinedData *WasmSym::stackLow;
|
|
||||||
DefinedData *WasmSym::stackHigh;
|
|
||||||
GlobalSymbol *WasmSym::tlsBase;
|
|
||||||
GlobalSymbol *WasmSym::tlsSize;
|
|
||||||
GlobalSymbol *WasmSym::tlsAlign;
|
|
||||||
UndefinedGlobal *WasmSym::tableBase;
|
|
||||||
DefinedData *WasmSym::definedTableBase;
|
|
||||||
UndefinedGlobal *WasmSym::memoryBase;
|
|
||||||
DefinedData *WasmSym::definedMemoryBase;
|
|
||||||
TableSymbol *WasmSym::indirectFunctionTable;
|
|
||||||
|
|
||||||
WasmSymbolType Symbol::getWasmType() const {
|
WasmSymbolType Symbol::getWasmType() const {
|
||||||
if (isa<FunctionSymbol>(this))
|
if (isa<FunctionSymbol>(this))
|
||||||
|
@ -537,105 +537,6 @@ public:
|
|||||||
const WasmSignature *signature = nullptr;
|
const WasmSignature *signature = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
// linker-generated symbols
|
|
||||||
struct WasmSym {
|
|
||||||
// __global_base
|
|
||||||
// Symbol marking the start of the global section.
|
|
||||||
static DefinedData *globalBase;
|
|
||||||
|
|
||||||
// __stack_pointer/__stack_low/__stack_high
|
|
||||||
// Global that holds current value of stack pointer and data symbols marking
|
|
||||||
// the start and end of the stack region. stackPointer is initialized to
|
|
||||||
// stackHigh and grows downwards towards stackLow
|
|
||||||
static GlobalSymbol *stackPointer;
|
|
||||||
static DefinedData *stackLow;
|
|
||||||
static DefinedData *stackHigh;
|
|
||||||
|
|
||||||
// __tls_base
|
|
||||||
// Global that holds the address of the base of the current thread's
|
|
||||||
// TLS block.
|
|
||||||
static GlobalSymbol *tlsBase;
|
|
||||||
|
|
||||||
// __tls_size
|
|
||||||
// Symbol whose value is the size of the TLS block.
|
|
||||||
static GlobalSymbol *tlsSize;
|
|
||||||
|
|
||||||
// __tls_size
|
|
||||||
// Symbol whose value is the alignment of the TLS block.
|
|
||||||
static GlobalSymbol *tlsAlign;
|
|
||||||
|
|
||||||
// __data_end
|
|
||||||
// Symbol marking the end of the data and bss.
|
|
||||||
static DefinedData *dataEnd;
|
|
||||||
|
|
||||||
// __heap_base/__heap_end
|
|
||||||
// Symbols marking the beginning and end of the "heap". It starts at the end
|
|
||||||
// of the data, bss and explicit stack, and extends to the end of the linear
|
|
||||||
// memory allocated by wasm-ld. This region of memory is not used by the
|
|
||||||
// linked code, so it may be used as a backing store for `sbrk` or `malloc`
|
|
||||||
// implementations.
|
|
||||||
static DefinedData *heapBase;
|
|
||||||
static DefinedData *heapEnd;
|
|
||||||
|
|
||||||
// __wasm_init_memory_flag
|
|
||||||
// Symbol whose contents are nonzero iff memory has already been initialized.
|
|
||||||
static DefinedData *initMemoryFlag;
|
|
||||||
|
|
||||||
// __wasm_init_memory
|
|
||||||
// Function that initializes passive data segments during instantiation.
|
|
||||||
static DefinedFunction *initMemory;
|
|
||||||
|
|
||||||
// __wasm_call_ctors
|
|
||||||
// Function that directly calls all ctors in priority order.
|
|
||||||
static DefinedFunction *callCtors;
|
|
||||||
|
|
||||||
// __wasm_call_dtors
|
|
||||||
// Function that calls the libc/etc. cleanup function.
|
|
||||||
static DefinedFunction *callDtors;
|
|
||||||
|
|
||||||
// __wasm_apply_global_relocs
|
|
||||||
// Function that applies relocations to wasm globals post-instantiation.
|
|
||||||
// Unlike __wasm_apply_data_relocs this needs to run on every thread.
|
|
||||||
static DefinedFunction *applyGlobalRelocs;
|
|
||||||
|
|
||||||
// __wasm_apply_tls_relocs
|
|
||||||
// Like __wasm_apply_data_relocs but for TLS section. These must be
|
|
||||||
// delayed until __wasm_init_tls.
|
|
||||||
static DefinedFunction *applyTLSRelocs;
|
|
||||||
|
|
||||||
// __wasm_apply_global_tls_relocs
|
|
||||||
// Like applyGlobalRelocs but for globals that hold TLS addresses. These
|
|
||||||
// must be delayed until __wasm_init_tls.
|
|
||||||
static DefinedFunction *applyGlobalTLSRelocs;
|
|
||||||
|
|
||||||
// __wasm_init_tls
|
|
||||||
// Function that allocates thread-local storage and initializes it.
|
|
||||||
static DefinedFunction *initTLS;
|
|
||||||
|
|
||||||
// Pointer to the function that is to be used in the start section.
|
|
||||||
// (normally an alias of initMemory, or applyGlobalRelocs).
|
|
||||||
static DefinedFunction *startFunction;
|
|
||||||
|
|
||||||
// __dso_handle
|
|
||||||
// Symbol used in calls to __cxa_atexit to determine current DLL
|
|
||||||
static DefinedData *dsoHandle;
|
|
||||||
|
|
||||||
// __table_base
|
|
||||||
// Used in PIC code for offset of indirect function table
|
|
||||||
static UndefinedGlobal *tableBase;
|
|
||||||
static DefinedData *definedTableBase;
|
|
||||||
|
|
||||||
// __memory_base
|
|
||||||
// Used in PIC code for offset of global data
|
|
||||||
static UndefinedGlobal *memoryBase;
|
|
||||||
static DefinedData *definedMemoryBase;
|
|
||||||
|
|
||||||
// __indirect_function_table
|
|
||||||
// Used as an address space for function pointers, with each function that is
|
|
||||||
// used as a function pointer being allocated a slot.
|
|
||||||
static TableSymbol *indirectFunctionTable;
|
|
||||||
};
|
|
||||||
|
|
||||||
// A buffer class that is large enough to hold any Symbol-derived
|
// A buffer class that is large enough to hold any Symbol-derived
|
||||||
// object. We allocate memory using this class and instantiate a symbol
|
// object. We allocate memory using this class and instantiate a symbol
|
||||||
// using the placement new.
|
// using the placement new.
|
||||||
|
@ -319,8 +319,8 @@ void TableSection::addTable(InputTable *table) {
|
|||||||
// Some inputs require that the indirect function table be assigned to table
|
// Some inputs require that the indirect function table be assigned to table
|
||||||
// number 0.
|
// number 0.
|
||||||
if (ctx.legacyFunctionTable &&
|
if (ctx.legacyFunctionTable &&
|
||||||
isa<DefinedTable>(WasmSym::indirectFunctionTable) &&
|
isa<DefinedTable>(ctx.sym.indirectFunctionTable) &&
|
||||||
cast<DefinedTable>(WasmSym::indirectFunctionTable)->table == table) {
|
cast<DefinedTable>(ctx.sym.indirectFunctionTable)->table == table) {
|
||||||
if (out.importSec->getNumImportedTables()) {
|
if (out.importSec->getNumImportedTables()) {
|
||||||
// Alack! Some other input imported a table, meaning that we are unable
|
// Alack! Some other input imported a table, meaning that we are unable
|
||||||
// to assign table number 0 to the indirect function table.
|
// to assign table number 0 to the indirect function table.
|
||||||
@ -395,8 +395,8 @@ void GlobalSection::assignIndexes() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void ensureIndirectFunctionTable() {
|
static void ensureIndirectFunctionTable() {
|
||||||
if (!WasmSym::indirectFunctionTable)
|
if (!ctx.sym.indirectFunctionTable)
|
||||||
WasmSym::indirectFunctionTable =
|
ctx.sym.indirectFunctionTable =
|
||||||
symtab->resolveIndirectFunctionTable(/*required =*/true);
|
symtab->resolveIndirectFunctionTable(/*required =*/true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -430,10 +430,9 @@ void GlobalSection::generateRelocationCode(raw_ostream &os, bool TLS) const {
|
|||||||
// Get __memory_base
|
// Get __memory_base
|
||||||
writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
|
writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
|
||||||
if (sym->isTLS())
|
if (sym->isTLS())
|
||||||
writeUleb128(os, WasmSym::tlsBase->getGlobalIndex(), "__tls_base");
|
writeUleb128(os, ctx.sym.tlsBase->getGlobalIndex(), "__tls_base");
|
||||||
else
|
else
|
||||||
writeUleb128(os, WasmSym::memoryBase->getGlobalIndex(),
|
writeUleb128(os, ctx.sym.memoryBase->getGlobalIndex(), "__memory_base");
|
||||||
"__memory_base");
|
|
||||||
|
|
||||||
// Add the virtual address of the data symbol
|
// Add the virtual address of the data symbol
|
||||||
writeU8(os, opcode_ptr_const, "CONST");
|
writeU8(os, opcode_ptr_const, "CONST");
|
||||||
@ -443,7 +442,7 @@ void GlobalSection::generateRelocationCode(raw_ostream &os, bool TLS) const {
|
|||||||
continue;
|
continue;
|
||||||
// Get __table_base
|
// Get __table_base
|
||||||
writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
|
writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
|
||||||
writeUleb128(os, WasmSym::tableBase->getGlobalIndex(), "__table_base");
|
writeUleb128(os, ctx.sym.tableBase->getGlobalIndex(), "__table_base");
|
||||||
|
|
||||||
// Add the table index to __table_base
|
// Add the table index to __table_base
|
||||||
writeU8(os, opcode_ptr_const, "CONST");
|
writeU8(os, opcode_ptr_const, "CONST");
|
||||||
@ -490,13 +489,13 @@ void GlobalSection::writeBody() {
|
|||||||
if (ctx.arg.extendedConst && ctx.isPic) {
|
if (ctx.arg.extendedConst && ctx.isPic) {
|
||||||
if (auto *d = dyn_cast<DefinedData>(sym)) {
|
if (auto *d = dyn_cast<DefinedData>(sym)) {
|
||||||
if (!sym->isTLS()) {
|
if (!sym->isTLS()) {
|
||||||
globalIdx = WasmSym::memoryBase->getGlobalIndex();
|
globalIdx = ctx.sym.memoryBase->getGlobalIndex();
|
||||||
offset = d->getVA();
|
offset = d->getVA();
|
||||||
useExtendedConst = true;
|
useExtendedConst = true;
|
||||||
}
|
}
|
||||||
} else if (auto *f = dyn_cast<FunctionSymbol>(sym)) {
|
} else if (auto *f = dyn_cast<FunctionSymbol>(sym)) {
|
||||||
if (!sym->isStub) {
|
if (!sym->isStub) {
|
||||||
globalIdx = WasmSym::tableBase->getGlobalIndex();
|
globalIdx = ctx.sym.tableBase->getGlobalIndex();
|
||||||
offset = f->getTableIndex();
|
offset = f->getTableIndex();
|
||||||
useExtendedConst = true;
|
useExtendedConst = true;
|
||||||
}
|
}
|
||||||
@ -550,14 +549,11 @@ void ExportSection::writeBody() {
|
|||||||
writeExport(os, export_);
|
writeExport(os, export_);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StartSection::isNeeded() const {
|
bool StartSection::isNeeded() const { return ctx.sym.startFunction != nullptr; }
|
||||||
return WasmSym::startFunction != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StartSection::writeBody() {
|
void StartSection::writeBody() {
|
||||||
raw_ostream &os = bodyOutputStream;
|
raw_ostream &os = bodyOutputStream;
|
||||||
writeUleb128(os, WasmSym::startFunction->getFunctionIndex(),
|
writeUleb128(os, ctx.sym.startFunction->getFunctionIndex(), "function index");
|
||||||
"function index");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ElemSection::addEntry(FunctionSymbol *sym) {
|
void ElemSection::addEntry(FunctionSymbol *sym) {
|
||||||
@ -573,9 +569,9 @@ void ElemSection::addEntry(FunctionSymbol *sym) {
|
|||||||
void ElemSection::writeBody() {
|
void ElemSection::writeBody() {
|
||||||
raw_ostream &os = bodyOutputStream;
|
raw_ostream &os = bodyOutputStream;
|
||||||
|
|
||||||
assert(WasmSym::indirectFunctionTable);
|
assert(ctx.sym.indirectFunctionTable);
|
||||||
writeUleb128(os, 1, "segment count");
|
writeUleb128(os, 1, "segment count");
|
||||||
uint32_t tableNumber = WasmSym::indirectFunctionTable->getTableNumber();
|
uint32_t tableNumber = ctx.sym.indirectFunctionTable->getTableNumber();
|
||||||
uint32_t flags = 0;
|
uint32_t flags = 0;
|
||||||
if (tableNumber)
|
if (tableNumber)
|
||||||
flags |= WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER;
|
flags |= WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER;
|
||||||
@ -587,7 +583,7 @@ void ElemSection::writeBody() {
|
|||||||
initExpr.Extended = false;
|
initExpr.Extended = false;
|
||||||
if (ctx.isPic) {
|
if (ctx.isPic) {
|
||||||
initExpr.Inst.Opcode = WASM_OPCODE_GLOBAL_GET;
|
initExpr.Inst.Opcode = WASM_OPCODE_GLOBAL_GET;
|
||||||
initExpr.Inst.Value.Global = WasmSym::tableBase->getGlobalIndex();
|
initExpr.Inst.Value.Global = ctx.sym.tableBase->getGlobalIndex();
|
||||||
} else {
|
} else {
|
||||||
bool is64 = ctx.arg.is64.value_or(false);
|
bool is64 = ctx.arg.is64.value_or(false);
|
||||||
initExpr = intConst(ctx.arg.tableBase, is64);
|
initExpr = intConst(ctx.arg.tableBase, is64);
|
||||||
|
@ -340,16 +340,16 @@ void Writer::layoutMemory() {
|
|||||||
if (ctx.arg.relocatable || ctx.isPic)
|
if (ctx.arg.relocatable || ctx.isPic)
|
||||||
return;
|
return;
|
||||||
memoryPtr = alignTo(memoryPtr, stackAlignment);
|
memoryPtr = alignTo(memoryPtr, stackAlignment);
|
||||||
if (WasmSym::stackLow)
|
if (ctx.sym.stackLow)
|
||||||
WasmSym::stackLow->setVA(memoryPtr);
|
ctx.sym.stackLow->setVA(memoryPtr);
|
||||||
if (ctx.arg.zStackSize != alignTo(ctx.arg.zStackSize, stackAlignment))
|
if (ctx.arg.zStackSize != alignTo(ctx.arg.zStackSize, stackAlignment))
|
||||||
error("stack size must be " + Twine(stackAlignment) + "-byte aligned");
|
error("stack size must be " + Twine(stackAlignment) + "-byte aligned");
|
||||||
log("mem: stack size = " + Twine(ctx.arg.zStackSize));
|
log("mem: stack size = " + Twine(ctx.arg.zStackSize));
|
||||||
log("mem: stack base = " + Twine(memoryPtr));
|
log("mem: stack base = " + Twine(memoryPtr));
|
||||||
memoryPtr += ctx.arg.zStackSize;
|
memoryPtr += ctx.arg.zStackSize;
|
||||||
setGlobalPtr(cast<DefinedGlobal>(WasmSym::stackPointer), memoryPtr);
|
setGlobalPtr(cast<DefinedGlobal>(ctx.sym.stackPointer), memoryPtr);
|
||||||
if (WasmSym::stackHigh)
|
if (ctx.sym.stackHigh)
|
||||||
WasmSym::stackHigh->setVA(memoryPtr);
|
ctx.sym.stackHigh->setVA(memoryPtr);
|
||||||
log("mem: stack top = " + Twine(memoryPtr));
|
log("mem: stack top = " + Twine(memoryPtr));
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -367,15 +367,15 @@ void Writer::layoutMemory() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log("mem: global base = " + Twine(memoryPtr));
|
log("mem: global base = " + Twine(memoryPtr));
|
||||||
if (WasmSym::globalBase)
|
if (ctx.sym.globalBase)
|
||||||
WasmSym::globalBase->setVA(memoryPtr);
|
ctx.sym.globalBase->setVA(memoryPtr);
|
||||||
|
|
||||||
uint64_t dataStart = memoryPtr;
|
uint64_t dataStart = memoryPtr;
|
||||||
|
|
||||||
// Arbitrarily set __dso_handle handle to point to the start of the data
|
// Arbitrarily set __dso_handle handle to point to the start of the data
|
||||||
// segments.
|
// segments.
|
||||||
if (WasmSym::dsoHandle)
|
if (ctx.sym.dsoHandle)
|
||||||
WasmSym::dsoHandle->setVA(dataStart);
|
ctx.sym.dsoHandle->setVA(dataStart);
|
||||||
|
|
||||||
out.dylinkSec->memAlign = 0;
|
out.dylinkSec->memAlign = 0;
|
||||||
for (OutputSegment *seg : segments) {
|
for (OutputSegment *seg : segments) {
|
||||||
@ -386,16 +386,16 @@ void Writer::layoutMemory() {
|
|||||||
memoryPtr, seg->size, seg->alignment));
|
memoryPtr, seg->size, seg->alignment));
|
||||||
|
|
||||||
if (!ctx.arg.relocatable && seg->isTLS()) {
|
if (!ctx.arg.relocatable && seg->isTLS()) {
|
||||||
if (WasmSym::tlsSize) {
|
if (ctx.sym.tlsSize) {
|
||||||
auto *tlsSize = cast<DefinedGlobal>(WasmSym::tlsSize);
|
auto *tlsSize = cast<DefinedGlobal>(ctx.sym.tlsSize);
|
||||||
setGlobalPtr(tlsSize, seg->size);
|
setGlobalPtr(tlsSize, seg->size);
|
||||||
}
|
}
|
||||||
if (WasmSym::tlsAlign) {
|
if (ctx.sym.tlsAlign) {
|
||||||
auto *tlsAlign = cast<DefinedGlobal>(WasmSym::tlsAlign);
|
auto *tlsAlign = cast<DefinedGlobal>(ctx.sym.tlsAlign);
|
||||||
setGlobalPtr(tlsAlign, int64_t{1} << seg->alignment);
|
setGlobalPtr(tlsAlign, int64_t{1} << seg->alignment);
|
||||||
}
|
}
|
||||||
if (!ctx.arg.sharedMemory && WasmSym::tlsBase) {
|
if (!ctx.arg.sharedMemory && ctx.sym.tlsBase) {
|
||||||
auto *tlsBase = cast<DefinedGlobal>(WasmSym::tlsBase);
|
auto *tlsBase = cast<DefinedGlobal>(ctx.sym.tlsBase);
|
||||||
setGlobalPtr(tlsBase, memoryPtr);
|
setGlobalPtr(tlsBase, memoryPtr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -406,17 +406,17 @@ void Writer::layoutMemory() {
|
|||||||
// Make space for the memory initialization flag
|
// Make space for the memory initialization flag
|
||||||
if (ctx.arg.sharedMemory && hasPassiveInitializedSegments()) {
|
if (ctx.arg.sharedMemory && hasPassiveInitializedSegments()) {
|
||||||
memoryPtr = alignTo(memoryPtr, 4);
|
memoryPtr = alignTo(memoryPtr, 4);
|
||||||
WasmSym::initMemoryFlag = symtab->addSyntheticDataSymbol(
|
ctx.sym.initMemoryFlag = symtab->addSyntheticDataSymbol(
|
||||||
"__wasm_init_memory_flag", WASM_SYMBOL_VISIBILITY_HIDDEN);
|
"__wasm_init_memory_flag", WASM_SYMBOL_VISIBILITY_HIDDEN);
|
||||||
WasmSym::initMemoryFlag->markLive();
|
ctx.sym.initMemoryFlag->markLive();
|
||||||
WasmSym::initMemoryFlag->setVA(memoryPtr);
|
ctx.sym.initMemoryFlag->setVA(memoryPtr);
|
||||||
log(formatv("mem: {0,-15} offset={1,-8} size={2,-8} align={3}",
|
log(formatv("mem: {0,-15} offset={1,-8} size={2,-8} align={3}",
|
||||||
"__wasm_init_memory_flag", memoryPtr, 4, 4));
|
"__wasm_init_memory_flag", memoryPtr, 4, 4));
|
||||||
memoryPtr += 4;
|
memoryPtr += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WasmSym::dataEnd)
|
if (ctx.sym.dataEnd)
|
||||||
WasmSym::dataEnd->setVA(memoryPtr);
|
ctx.sym.dataEnd->setVA(memoryPtr);
|
||||||
|
|
||||||
uint64_t staticDataSize = memoryPtr - dataStart;
|
uint64_t staticDataSize = memoryPtr - dataStart;
|
||||||
log("mem: static data = " + Twine(staticDataSize));
|
log("mem: static data = " + Twine(staticDataSize));
|
||||||
@ -426,7 +426,7 @@ void Writer::layoutMemory() {
|
|||||||
if (!ctx.arg.stackFirst)
|
if (!ctx.arg.stackFirst)
|
||||||
placeStack();
|
placeStack();
|
||||||
|
|
||||||
if (WasmSym::heapBase) {
|
if (ctx.sym.heapBase) {
|
||||||
// Set `__heap_base` to follow the end of the stack or global data. The
|
// Set `__heap_base` to follow the end of the stack or global data. The
|
||||||
// fact that this comes last means that a malloc/brk implementation can
|
// fact that this comes last means that a malloc/brk implementation can
|
||||||
// grow the heap at runtime.
|
// grow the heap at runtime.
|
||||||
@ -434,7 +434,7 @@ void Writer::layoutMemory() {
|
|||||||
// __heap_base to be aligned already.
|
// __heap_base to be aligned already.
|
||||||
memoryPtr = alignTo(memoryPtr, heapAlignment);
|
memoryPtr = alignTo(memoryPtr, heapAlignment);
|
||||||
log("mem: heap base = " + Twine(memoryPtr));
|
log("mem: heap base = " + Twine(memoryPtr));
|
||||||
WasmSym::heapBase->setVA(memoryPtr);
|
ctx.sym.heapBase->setVA(memoryPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t maxMemorySetting = 1ULL << 32;
|
uint64_t maxMemorySetting = 1ULL << 32;
|
||||||
@ -470,12 +470,12 @@ void Writer::layoutMemory() {
|
|||||||
out.memorySec->numMemoryPages = memoryPtr / WasmPageSize;
|
out.memorySec->numMemoryPages = memoryPtr / WasmPageSize;
|
||||||
log("mem: total pages = " + Twine(out.memorySec->numMemoryPages));
|
log("mem: total pages = " + Twine(out.memorySec->numMemoryPages));
|
||||||
|
|
||||||
if (WasmSym::heapEnd) {
|
if (ctx.sym.heapEnd) {
|
||||||
// Set `__heap_end` to follow the end of the statically allocated linear
|
// Set `__heap_end` to follow the end of the statically allocated linear
|
||||||
// memory. The fact that this comes last means that a malloc/brk
|
// memory. The fact that this comes last means that a malloc/brk
|
||||||
// implementation can grow the heap at runtime.
|
// implementation can grow the heap at runtime.
|
||||||
log("mem: heap end = " + Twine(memoryPtr));
|
log("mem: heap end = " + Twine(memoryPtr));
|
||||||
WasmSym::heapEnd->setVA(memoryPtr);
|
ctx.sym.heapEnd->setVA(memoryPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t maxMemory = 0;
|
uint64_t maxMemory = 0;
|
||||||
@ -758,14 +758,14 @@ void Writer::calculateImports() {
|
|||||||
// Some inputs require that the indirect function table be assigned to table
|
// Some inputs require that the indirect function table be assigned to table
|
||||||
// number 0, so if it is present and is an import, allocate it before any
|
// number 0, so if it is present and is an import, allocate it before any
|
||||||
// other tables.
|
// other tables.
|
||||||
if (WasmSym::indirectFunctionTable &&
|
if (ctx.sym.indirectFunctionTable &&
|
||||||
shouldImport(WasmSym::indirectFunctionTable))
|
shouldImport(ctx.sym.indirectFunctionTable))
|
||||||
out.importSec->addImport(WasmSym::indirectFunctionTable);
|
out.importSec->addImport(ctx.sym.indirectFunctionTable);
|
||||||
|
|
||||||
for (Symbol *sym : symtab->symbols()) {
|
for (Symbol *sym : symtab->symbols()) {
|
||||||
if (!shouldImport(sym))
|
if (!shouldImport(sym))
|
||||||
continue;
|
continue;
|
||||||
if (sym == WasmSym::indirectFunctionTable)
|
if (sym == ctx.sym.indirectFunctionTable)
|
||||||
continue;
|
continue;
|
||||||
LLVM_DEBUG(dbgs() << "import: " << sym->getName() << "\n");
|
LLVM_DEBUG(dbgs() << "import: " << sym->getName() << "\n");
|
||||||
out.importSec->addImport(sym);
|
out.importSec->addImport(sym);
|
||||||
@ -879,7 +879,7 @@ void Writer::createCommandExportWrappers() {
|
|||||||
|
|
||||||
// If there are no ctors and there's no libc `__wasm_call_dtors` to
|
// If there are no ctors and there's no libc `__wasm_call_dtors` to
|
||||||
// call, don't wrap the exports.
|
// call, don't wrap the exports.
|
||||||
if (initFunctions.empty() && WasmSym::callDtors == nullptr)
|
if (initFunctions.empty() && ctx.sym.callDtors == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::vector<DefinedFunction *> toWrap;
|
std::vector<DefinedFunction *> toWrap;
|
||||||
@ -919,27 +919,27 @@ void Writer::createCommandExportWrappers() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void finalizeIndirectFunctionTable() {
|
static void finalizeIndirectFunctionTable() {
|
||||||
if (!WasmSym::indirectFunctionTable)
|
if (!ctx.sym.indirectFunctionTable)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (shouldImport(WasmSym::indirectFunctionTable) &&
|
if (shouldImport(ctx.sym.indirectFunctionTable) &&
|
||||||
!WasmSym::indirectFunctionTable->hasTableNumber()) {
|
!ctx.sym.indirectFunctionTable->hasTableNumber()) {
|
||||||
// Processing -Bsymbolic relocations resulted in a late requirement that the
|
// Processing -Bsymbolic relocations resulted in a late requirement that the
|
||||||
// indirect function table be present, and we are running in --import-table
|
// indirect function table be present, and we are running in --import-table
|
||||||
// mode. Add the table now to the imports section. Otherwise it will be
|
// mode. Add the table now to the imports section. Otherwise it will be
|
||||||
// added to the tables section later in assignIndexes.
|
// added to the tables section later in assignIndexes.
|
||||||
out.importSec->addImport(WasmSym::indirectFunctionTable);
|
out.importSec->addImport(ctx.sym.indirectFunctionTable);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t tableSize = ctx.arg.tableBase + out.elemSec->numEntries();
|
uint32_t tableSize = ctx.arg.tableBase + out.elemSec->numEntries();
|
||||||
WasmLimits limits = {0, tableSize, 0};
|
WasmLimits limits = {0, tableSize, 0};
|
||||||
if (WasmSym::indirectFunctionTable->isDefined() && !ctx.arg.growableTable) {
|
if (ctx.sym.indirectFunctionTable->isDefined() && !ctx.arg.growableTable) {
|
||||||
limits.Flags |= WASM_LIMITS_FLAG_HAS_MAX;
|
limits.Flags |= WASM_LIMITS_FLAG_HAS_MAX;
|
||||||
limits.Maximum = limits.Minimum;
|
limits.Maximum = limits.Minimum;
|
||||||
}
|
}
|
||||||
if (ctx.arg.is64.value_or(false))
|
if (ctx.arg.is64.value_or(false))
|
||||||
limits.Flags |= WASM_LIMITS_FLAG_IS_64;
|
limits.Flags |= WASM_LIMITS_FLAG_IS_64;
|
||||||
WasmSym::indirectFunctionTable->setLimits(limits);
|
ctx.sym.indirectFunctionTable->setLimits(limits);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void scanRelocations() {
|
static void scanRelocations() {
|
||||||
@ -1142,26 +1142,26 @@ void Writer::createSyntheticInitFunctions() {
|
|||||||
// We also initialize bss segments (using memory.fill) as part of this
|
// We also initialize bss segments (using memory.fill) as part of this
|
||||||
// function.
|
// function.
|
||||||
if (hasPassiveInitializedSegments()) {
|
if (hasPassiveInitializedSegments()) {
|
||||||
WasmSym::initMemory = symtab->addSyntheticFunction(
|
ctx.sym.initMemory = symtab->addSyntheticFunction(
|
||||||
"__wasm_init_memory", WASM_SYMBOL_VISIBILITY_HIDDEN,
|
"__wasm_init_memory", WASM_SYMBOL_VISIBILITY_HIDDEN,
|
||||||
make<SyntheticFunction>(nullSignature, "__wasm_init_memory"));
|
make<SyntheticFunction>(nullSignature, "__wasm_init_memory"));
|
||||||
WasmSym::initMemory->markLive();
|
ctx.sym.initMemory->markLive();
|
||||||
if (ctx.arg.sharedMemory) {
|
if (ctx.arg.sharedMemory) {
|
||||||
// This global is assigned during __wasm_init_memory in the shared memory
|
// This global is assigned during __wasm_init_memory in the shared memory
|
||||||
// case.
|
// case.
|
||||||
WasmSym::tlsBase->markLive();
|
ctx.sym.tlsBase->markLive();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.arg.sharedMemory) {
|
if (ctx.arg.sharedMemory) {
|
||||||
if (out.globalSec->needsTLSRelocations()) {
|
if (out.globalSec->needsTLSRelocations()) {
|
||||||
WasmSym::applyGlobalTLSRelocs = symtab->addSyntheticFunction(
|
ctx.sym.applyGlobalTLSRelocs = symtab->addSyntheticFunction(
|
||||||
"__wasm_apply_global_tls_relocs", WASM_SYMBOL_VISIBILITY_HIDDEN,
|
"__wasm_apply_global_tls_relocs", WASM_SYMBOL_VISIBILITY_HIDDEN,
|
||||||
make<SyntheticFunction>(nullSignature,
|
make<SyntheticFunction>(nullSignature,
|
||||||
"__wasm_apply_global_tls_relocs"));
|
"__wasm_apply_global_tls_relocs"));
|
||||||
WasmSym::applyGlobalTLSRelocs->markLive();
|
ctx.sym.applyGlobalTLSRelocs->markLive();
|
||||||
// TLS relocations depend on the __tls_base symbols
|
// TLS relocations depend on the __tls_base symbols
|
||||||
WasmSym::tlsBase->markLive();
|
ctx.sym.tlsBase->markLive();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto hasTLSRelocs = [](const OutputSegment *segment) {
|
auto hasTLSRelocs = [](const OutputSegment *segment) {
|
||||||
@ -1172,40 +1172,39 @@ void Writer::createSyntheticInitFunctions() {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
if (llvm::any_of(segments, hasTLSRelocs)) {
|
if (llvm::any_of(segments, hasTLSRelocs)) {
|
||||||
WasmSym::applyTLSRelocs = symtab->addSyntheticFunction(
|
ctx.sym.applyTLSRelocs = symtab->addSyntheticFunction(
|
||||||
"__wasm_apply_tls_relocs", WASM_SYMBOL_VISIBILITY_HIDDEN,
|
"__wasm_apply_tls_relocs", WASM_SYMBOL_VISIBILITY_HIDDEN,
|
||||||
make<SyntheticFunction>(nullSignature,
|
make<SyntheticFunction>(nullSignature, "__wasm_apply_tls_relocs"));
|
||||||
"__wasm_apply_tls_relocs"));
|
ctx.sym.applyTLSRelocs->markLive();
|
||||||
WasmSym::applyTLSRelocs->markLive();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.isPic && out.globalSec->needsRelocations()) {
|
if (ctx.isPic && out.globalSec->needsRelocations()) {
|
||||||
WasmSym::applyGlobalRelocs = symtab->addSyntheticFunction(
|
ctx.sym.applyGlobalRelocs = symtab->addSyntheticFunction(
|
||||||
"__wasm_apply_global_relocs", WASM_SYMBOL_VISIBILITY_HIDDEN,
|
"__wasm_apply_global_relocs", WASM_SYMBOL_VISIBILITY_HIDDEN,
|
||||||
make<SyntheticFunction>(nullSignature, "__wasm_apply_global_relocs"));
|
make<SyntheticFunction>(nullSignature, "__wasm_apply_global_relocs"));
|
||||||
WasmSym::applyGlobalRelocs->markLive();
|
ctx.sym.applyGlobalRelocs->markLive();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is only one start function we can just use that function
|
// If there is only one start function we can just use that function
|
||||||
// itself as the Wasm start function, otherwise we need to synthesize
|
// itself as the Wasm start function, otherwise we need to synthesize
|
||||||
// a new function to call them in sequence.
|
// a new function to call them in sequence.
|
||||||
if (WasmSym::applyGlobalRelocs && WasmSym::initMemory) {
|
if (ctx.sym.applyGlobalRelocs && ctx.sym.initMemory) {
|
||||||
WasmSym::startFunction = symtab->addSyntheticFunction(
|
ctx.sym.startFunction = symtab->addSyntheticFunction(
|
||||||
"__wasm_start", WASM_SYMBOL_VISIBILITY_HIDDEN,
|
"__wasm_start", WASM_SYMBOL_VISIBILITY_HIDDEN,
|
||||||
make<SyntheticFunction>(nullSignature, "__wasm_start"));
|
make<SyntheticFunction>(nullSignature, "__wasm_start"));
|
||||||
WasmSym::startFunction->markLive();
|
ctx.sym.startFunction->markLive();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Writer::createInitMemoryFunction() {
|
void Writer::createInitMemoryFunction() {
|
||||||
LLVM_DEBUG(dbgs() << "createInitMemoryFunction\n");
|
LLVM_DEBUG(dbgs() << "createInitMemoryFunction\n");
|
||||||
assert(WasmSym::initMemory);
|
assert(ctx.sym.initMemory);
|
||||||
assert(hasPassiveInitializedSegments());
|
assert(hasPassiveInitializedSegments());
|
||||||
uint64_t flagAddress;
|
uint64_t flagAddress;
|
||||||
if (ctx.arg.sharedMemory) {
|
if (ctx.arg.sharedMemory) {
|
||||||
assert(WasmSym::initMemoryFlag);
|
assert(ctx.sym.initMemoryFlag);
|
||||||
flagAddress = WasmSym::initMemoryFlag->getVA();
|
flagAddress = ctx.sym.initMemoryFlag->getVA();
|
||||||
}
|
}
|
||||||
bool is64 = ctx.arg.is64.value_or(false);
|
bool is64 = ctx.arg.is64.value_or(false);
|
||||||
std::string bodyContent;
|
std::string bodyContent;
|
||||||
@ -1278,7 +1277,7 @@ void Writer::createInitMemoryFunction() {
|
|||||||
writeUleb128(os, 2, "local count");
|
writeUleb128(os, 2, "local count");
|
||||||
writeU8(os, is64 ? WASM_TYPE_I64 : WASM_TYPE_I32, "address type");
|
writeU8(os, is64 ? WASM_TYPE_I64 : WASM_TYPE_I32, "address type");
|
||||||
writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
|
writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
|
||||||
writeUleb128(os, WasmSym::memoryBase->getGlobalIndex(), "memory_base");
|
writeUleb128(os, ctx.sym.memoryBase->getGlobalIndex(), "memory_base");
|
||||||
writePtrConst(os, flagAddress, is64, "flag address");
|
writePtrConst(os, flagAddress, is64, "flag address");
|
||||||
writeU8(os, is64 ? WASM_OPCODE_I64_ADD : WASM_OPCODE_I32_ADD, "add");
|
writeU8(os, is64 ? WASM_OPCODE_I64_ADD : WASM_OPCODE_I32_ADD, "add");
|
||||||
writeU8(os, WASM_OPCODE_LOCAL_SET, "local.set");
|
writeU8(os, WASM_OPCODE_LOCAL_SET, "local.set");
|
||||||
@ -1325,7 +1324,7 @@ void Writer::createInitMemoryFunction() {
|
|||||||
writePtrConst(os, s->startVA, is64, "destination address");
|
writePtrConst(os, s->startVA, is64, "destination address");
|
||||||
if (ctx.isPic) {
|
if (ctx.isPic) {
|
||||||
writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
|
writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
|
||||||
writeUleb128(os, WasmSym::memoryBase->getGlobalIndex(),
|
writeUleb128(os, ctx.sym.memoryBase->getGlobalIndex(),
|
||||||
"__memory_base");
|
"__memory_base");
|
||||||
writeU8(os, is64 ? WASM_OPCODE_I64_ADD : WASM_OPCODE_I32_ADD,
|
writeU8(os, is64 ? WASM_OPCODE_I64_ADD : WASM_OPCODE_I32_ADD,
|
||||||
"i32.add");
|
"i32.add");
|
||||||
@ -1343,8 +1342,7 @@ void Writer::createInitMemoryFunction() {
|
|||||||
writePtrConst(os, s->startVA, is64, "destination address");
|
writePtrConst(os, s->startVA, is64, "destination address");
|
||||||
}
|
}
|
||||||
writeU8(os, WASM_OPCODE_GLOBAL_SET, "GLOBAL_SET");
|
writeU8(os, WASM_OPCODE_GLOBAL_SET, "GLOBAL_SET");
|
||||||
writeUleb128(os, WasmSym::tlsBase->getGlobalIndex(),
|
writeUleb128(os, ctx.sym.tlsBase->getGlobalIndex(), "__tls_base");
|
||||||
"__tls_base");
|
|
||||||
if (ctx.isPic) {
|
if (ctx.isPic) {
|
||||||
writeU8(os, WASM_OPCODE_LOCAL_GET, "local.tee");
|
writeU8(os, WASM_OPCODE_LOCAL_GET, "local.tee");
|
||||||
writeUleb128(os, 1, "local 1");
|
writeUleb128(os, 1, "local 1");
|
||||||
@ -1420,30 +1418,30 @@ void Writer::createInitMemoryFunction() {
|
|||||||
writeU8(os, WASM_OPCODE_END, "END");
|
writeU8(os, WASM_OPCODE_END, "END");
|
||||||
}
|
}
|
||||||
|
|
||||||
createFunction(WasmSym::initMemory, bodyContent);
|
createFunction(ctx.sym.initMemory, bodyContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Writer::createStartFunction() {
|
void Writer::createStartFunction() {
|
||||||
// If the start function exists when we have more than one function to call.
|
// If the start function exists when we have more than one function to call.
|
||||||
if (WasmSym::initMemory && WasmSym::applyGlobalRelocs) {
|
if (ctx.sym.initMemory && ctx.sym.applyGlobalRelocs) {
|
||||||
assert(WasmSym::startFunction);
|
assert(ctx.sym.startFunction);
|
||||||
std::string bodyContent;
|
std::string bodyContent;
|
||||||
{
|
{
|
||||||
raw_string_ostream os(bodyContent);
|
raw_string_ostream os(bodyContent);
|
||||||
writeUleb128(os, 0, "num locals");
|
writeUleb128(os, 0, "num locals");
|
||||||
writeU8(os, WASM_OPCODE_CALL, "CALL");
|
writeU8(os, WASM_OPCODE_CALL, "CALL");
|
||||||
writeUleb128(os, WasmSym::applyGlobalRelocs->getFunctionIndex(),
|
writeUleb128(os, ctx.sym.applyGlobalRelocs->getFunctionIndex(),
|
||||||
"function index");
|
"function index");
|
||||||
writeU8(os, WASM_OPCODE_CALL, "CALL");
|
writeU8(os, WASM_OPCODE_CALL, "CALL");
|
||||||
writeUleb128(os, WasmSym::initMemory->getFunctionIndex(),
|
writeUleb128(os, ctx.sym.initMemory->getFunctionIndex(),
|
||||||
"function index");
|
"function index");
|
||||||
writeU8(os, WASM_OPCODE_END, "END");
|
writeU8(os, WASM_OPCODE_END, "END");
|
||||||
}
|
}
|
||||||
createFunction(WasmSym::startFunction, bodyContent);
|
createFunction(ctx.sym.startFunction, bodyContent);
|
||||||
} else if (WasmSym::initMemory) {
|
} else if (ctx.sym.initMemory) {
|
||||||
WasmSym::startFunction = WasmSym::initMemory;
|
ctx.sym.startFunction = ctx.sym.initMemory;
|
||||||
} else if (WasmSym::applyGlobalRelocs) {
|
} else if (ctx.sym.applyGlobalRelocs) {
|
||||||
WasmSym::startFunction = WasmSym::applyGlobalRelocs;
|
ctx.sym.startFunction = ctx.sym.applyGlobalRelocs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1497,7 +1495,7 @@ void Writer::createApplyTLSRelocationsFunction() {
|
|||||||
writeU8(os, WASM_OPCODE_END, "END");
|
writeU8(os, WASM_OPCODE_END, "END");
|
||||||
}
|
}
|
||||||
|
|
||||||
createFunction(WasmSym::applyTLSRelocs, bodyContent);
|
createFunction(ctx.sym.applyTLSRelocs, bodyContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Similar to createApplyDataRelocationsFunction but generates relocation code
|
// Similar to createApplyDataRelocationsFunction but generates relocation code
|
||||||
@ -1513,7 +1511,7 @@ void Writer::createApplyGlobalRelocationsFunction() {
|
|||||||
writeU8(os, WASM_OPCODE_END, "END");
|
writeU8(os, WASM_OPCODE_END, "END");
|
||||||
}
|
}
|
||||||
|
|
||||||
createFunction(WasmSym::applyGlobalRelocs, bodyContent);
|
createFunction(ctx.sym.applyGlobalRelocs, bodyContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Similar to createApplyGlobalRelocationsFunction but for
|
// Similar to createApplyGlobalRelocationsFunction but for
|
||||||
@ -1529,7 +1527,7 @@ void Writer::createApplyGlobalTLSRelocationsFunction() {
|
|||||||
writeU8(os, WASM_OPCODE_END, "END");
|
writeU8(os, WASM_OPCODE_END, "END");
|
||||||
}
|
}
|
||||||
|
|
||||||
createFunction(WasmSym::applyGlobalTLSRelocs, bodyContent);
|
createFunction(ctx.sym.applyGlobalTLSRelocs, bodyContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create synthetic "__wasm_call_ctors" function based on ctor functions
|
// Create synthetic "__wasm_call_ctors" function based on ctor functions
|
||||||
@ -1537,7 +1535,7 @@ void Writer::createApplyGlobalTLSRelocationsFunction() {
|
|||||||
void Writer::createCallCtorsFunction() {
|
void Writer::createCallCtorsFunction() {
|
||||||
// If __wasm_call_ctors isn't referenced, there aren't any ctors, don't
|
// If __wasm_call_ctors isn't referenced, there aren't any ctors, don't
|
||||||
// define the `__wasm_call_ctors` function.
|
// define the `__wasm_call_ctors` function.
|
||||||
if (!WasmSym::callCtors->isLive() && initFunctions.empty())
|
if (!ctx.sym.callCtors->isLive() && initFunctions.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// First write the body's contents to a string.
|
// First write the body's contents to a string.
|
||||||
@ -1558,7 +1556,7 @@ void Writer::createCallCtorsFunction() {
|
|||||||
writeU8(os, WASM_OPCODE_END, "END");
|
writeU8(os, WASM_OPCODE_END, "END");
|
||||||
}
|
}
|
||||||
|
|
||||||
createFunction(WasmSym::callCtors, bodyContent);
|
createFunction(ctx.sym.callCtors, bodyContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a wrapper around a function export which calls the
|
// Create a wrapper around a function export which calls the
|
||||||
@ -1573,10 +1571,9 @@ void Writer::createCommandExportWrapper(uint32_t functionIndex,
|
|||||||
|
|
||||||
// Call `__wasm_call_ctors` which call static constructors (and
|
// Call `__wasm_call_ctors` which call static constructors (and
|
||||||
// applies any runtime relocations in Emscripten-style PIC mode)
|
// applies any runtime relocations in Emscripten-style PIC mode)
|
||||||
if (WasmSym::callCtors->isLive()) {
|
if (ctx.sym.callCtors->isLive()) {
|
||||||
writeU8(os, WASM_OPCODE_CALL, "CALL");
|
writeU8(os, WASM_OPCODE_CALL, "CALL");
|
||||||
writeUleb128(os, WasmSym::callCtors->getFunctionIndex(),
|
writeUleb128(os, ctx.sym.callCtors->getFunctionIndex(), "function index");
|
||||||
"function index");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call the user's code, leaving any return values on the operand stack.
|
// Call the user's code, leaving any return values on the operand stack.
|
||||||
@ -1588,7 +1585,7 @@ void Writer::createCommandExportWrapper(uint32_t functionIndex,
|
|||||||
writeUleb128(os, functionIndex, "function index");
|
writeUleb128(os, functionIndex, "function index");
|
||||||
|
|
||||||
// Call the function that calls the destructors.
|
// Call the function that calls the destructors.
|
||||||
if (DefinedFunction *callDtors = WasmSym::callDtors) {
|
if (DefinedFunction *callDtors = ctx.sym.callDtors) {
|
||||||
writeU8(os, WASM_OPCODE_CALL, "CALL");
|
writeU8(os, WASM_OPCODE_CALL, "CALL");
|
||||||
writeUleb128(os, callDtors->getFunctionIndex(), "function index");
|
writeUleb128(os, callDtors->getFunctionIndex(), "function index");
|
||||||
}
|
}
|
||||||
@ -1619,7 +1616,7 @@ void Writer::createInitTLSFunction() {
|
|||||||
writeUleb128(os, 0, "local index");
|
writeUleb128(os, 0, "local index");
|
||||||
|
|
||||||
writeU8(os, WASM_OPCODE_GLOBAL_SET, "global.set");
|
writeU8(os, WASM_OPCODE_GLOBAL_SET, "global.set");
|
||||||
writeUleb128(os, WasmSym::tlsBase->getGlobalIndex(), "global index");
|
writeUleb128(os, ctx.sym.tlsBase->getGlobalIndex(), "global index");
|
||||||
|
|
||||||
// FIXME(wvo): this local needs to be I64 in wasm64, or we need an extend op.
|
// FIXME(wvo): this local needs to be I64 in wasm64, or we need an extend op.
|
||||||
writeU8(os, WASM_OPCODE_LOCAL_GET, "local.get");
|
writeU8(os, WASM_OPCODE_LOCAL_GET, "local.get");
|
||||||
@ -1635,28 +1632,28 @@ void Writer::createInitTLSFunction() {
|
|||||||
writeU8(os, 0, "memory index immediate");
|
writeU8(os, 0, "memory index immediate");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WasmSym::applyTLSRelocs) {
|
if (ctx.sym.applyTLSRelocs) {
|
||||||
writeU8(os, WASM_OPCODE_CALL, "CALL");
|
writeU8(os, WASM_OPCODE_CALL, "CALL");
|
||||||
writeUleb128(os, WasmSym::applyTLSRelocs->getFunctionIndex(),
|
writeUleb128(os, ctx.sym.applyTLSRelocs->getFunctionIndex(),
|
||||||
"function index");
|
"function index");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WasmSym::applyGlobalTLSRelocs) {
|
if (ctx.sym.applyGlobalTLSRelocs) {
|
||||||
writeU8(os, WASM_OPCODE_CALL, "CALL");
|
writeU8(os, WASM_OPCODE_CALL, "CALL");
|
||||||
writeUleb128(os, WasmSym::applyGlobalTLSRelocs->getFunctionIndex(),
|
writeUleb128(os, ctx.sym.applyGlobalTLSRelocs->getFunctionIndex(),
|
||||||
"function index");
|
"function index");
|
||||||
}
|
}
|
||||||
writeU8(os, WASM_OPCODE_END, "end function");
|
writeU8(os, WASM_OPCODE_END, "end function");
|
||||||
}
|
}
|
||||||
|
|
||||||
createFunction(WasmSym::initTLS, bodyContent);
|
createFunction(ctx.sym.initTLS, bodyContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Populate InitFunctions vector with init functions from all input objects.
|
// Populate InitFunctions vector with init functions from all input objects.
|
||||||
// This is then used either when creating the output linking section or to
|
// This is then used either when creating the output linking section or to
|
||||||
// synthesize the "__wasm_call_ctors" function.
|
// synthesize the "__wasm_call_ctors" function.
|
||||||
void Writer::calculateInitFunctions() {
|
void Writer::calculateInitFunctions() {
|
||||||
if (!ctx.arg.relocatable && !WasmSym::callCtors->isLive())
|
if (!ctx.arg.relocatable && !ctx.sym.callCtors->isLive())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (ObjFile *file : ctx.objectFiles) {
|
for (ObjFile *file : ctx.objectFiles) {
|
||||||
@ -1707,8 +1704,8 @@ void Writer::createSyntheticSectionsPostLayout() {
|
|||||||
void Writer::run() {
|
void Writer::run() {
|
||||||
// For PIC code the table base is assigned dynamically by the loader.
|
// For PIC code the table base is assigned dynamically by the loader.
|
||||||
// For non-PIC, we start at 1 so that accessing table index 0 always traps.
|
// For non-PIC, we start at 1 so that accessing table index 0 always traps.
|
||||||
if (!ctx.isPic && WasmSym::definedTableBase)
|
if (!ctx.isPic && ctx.sym.definedTableBase)
|
||||||
WasmSym::definedTableBase->setVA(ctx.arg.tableBase);
|
ctx.sym.definedTableBase->setVA(ctx.arg.tableBase);
|
||||||
|
|
||||||
log("-- createOutputSegments");
|
log("-- createOutputSegments");
|
||||||
createOutputSegments();
|
createOutputSegments();
|
||||||
@ -1776,14 +1773,18 @@ void Writer::run() {
|
|||||||
|
|
||||||
if (!ctx.arg.relocatable) {
|
if (!ctx.arg.relocatable) {
|
||||||
// Create linker synthesized functions
|
// Create linker synthesized functions
|
||||||
if (WasmSym::applyGlobalRelocs)
|
if (ctx.sym.applyGlobalRelocs) {
|
||||||
createApplyGlobalRelocationsFunction();
|
createApplyGlobalRelocationsFunction();
|
||||||
if (WasmSym::applyTLSRelocs)
|
}
|
||||||
|
if (ctx.sym.applyTLSRelocs) {
|
||||||
createApplyTLSRelocationsFunction();
|
createApplyTLSRelocationsFunction();
|
||||||
if (WasmSym::applyGlobalTLSRelocs)
|
}
|
||||||
|
if (ctx.sym.applyGlobalTLSRelocs) {
|
||||||
createApplyGlobalTLSRelocationsFunction();
|
createApplyGlobalTLSRelocationsFunction();
|
||||||
if (WasmSym::initMemory)
|
}
|
||||||
|
if (ctx.sym.initMemory) {
|
||||||
createInitMemoryFunction();
|
createInitMemoryFunction();
|
||||||
|
}
|
||||||
createStartFunction();
|
createStartFunction();
|
||||||
|
|
||||||
createCallCtorsFunction();
|
createCallCtorsFunction();
|
||||||
@ -1794,14 +1795,14 @@ void Writer::run() {
|
|||||||
// the input objects or an explicit export from the command-line, we
|
// the input objects or an explicit export from the command-line, we
|
||||||
// assume ctors and dtors are taken care of already.
|
// assume ctors and dtors are taken care of already.
|
||||||
if (!ctx.arg.relocatable && !ctx.isPic &&
|
if (!ctx.arg.relocatable && !ctx.isPic &&
|
||||||
!WasmSym::callCtors->isUsedInRegularObj &&
|
!ctx.sym.callCtors->isUsedInRegularObj &&
|
||||||
!WasmSym::callCtors->isExported()) {
|
!ctx.sym.callCtors->isExported()) {
|
||||||
log("-- createCommandExportWrappers");
|
log("-- createCommandExportWrappers");
|
||||||
createCommandExportWrappers();
|
createCommandExportWrappers();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WasmSym::initTLS && WasmSym::initTLS->isLive()) {
|
if (ctx.sym.initTLS && ctx.sym.initTLS->isLive()) {
|
||||||
log("-- createInitTLSFunction");
|
log("-- createInitTLSFunction");
|
||||||
createInitTLSFunction();
|
createInitTLSFunction();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user