mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-25 20:36:06 +00:00
[WebAssembly] Import the stack pointer when building shared libraries
Differential Revision: https://reviews.llvm.org/D54558 llvm-svn: 346974
This commit is contained in:
parent
aa3f2494b3
commit
2dad4e2c6d
@ -9,6 +9,8 @@ target triple = "wasm32-unknown-unknown"
|
||||
|
||||
define default void @foo() {
|
||||
entry:
|
||||
; To ensure we use __stack_pointer
|
||||
%ptr = alloca i32
|
||||
%0 = load i32, i32* @used_data, align 4
|
||||
%1 = load void ()*, void ()** @indirect_func, align 4
|
||||
call void %1()
|
||||
@ -39,6 +41,11 @@ entry:
|
||||
; CHECK-NEXT: Initial: 0x00000001
|
||||
; CHECK-NEXT: Maximum: 0x00000001
|
||||
; CHECK-NEXT: - Module: env
|
||||
; CHECK-NEXT: Field: __stack_pointer
|
||||
; CHECK-NEXT: Kind: GLOBAL
|
||||
; CHECK-NEXT: GlobalType: I32
|
||||
; CHECK-NEXT: GlobalMutable: true
|
||||
; CHECK-NEXT: - Module: env
|
||||
; CHECK-NEXT: Field: __memory_base
|
||||
; CHECK-NEXT: Kind: GLOBAL
|
||||
; CHECK-NEXT: GlobalType: I32
|
||||
@ -55,7 +62,7 @@ entry:
|
||||
; CHECK-NEXT: Segments:
|
||||
; CHECK-NEXT: - Offset:
|
||||
; CHECK-NEXT: Opcode: GET_GLOBAL
|
||||
; CHECK-NEXT: Index: 1
|
||||
; CHECK-NEXT: Index: 2
|
||||
; CHECK-NEXT: Functions: [ 1 ]
|
||||
|
||||
; check the data segment initialized with __memory_base global as offset
|
||||
@ -66,5 +73,5 @@ entry:
|
||||
; CHECK-NEXT: MemoryIndex: 0
|
||||
; CHECK-NEXT: Offset:
|
||||
; CHECK-NEXT: Opcode: GET_GLOBAL
|
||||
; CHECK-NEXT: Index: 0
|
||||
; CHECK-NEXT: Index: 1
|
||||
; CHECK-NEXT: Content: '00000000'
|
||||
|
@ -431,6 +431,71 @@ static Symbol *handleUndefined(StringRef Name) {
|
||||
return Sym;
|
||||
}
|
||||
|
||||
static UndefinedGlobal *
|
||||
createUndefinedGlobal(StringRef Name, llvm::wasm::WasmGlobalType *Type) {
|
||||
auto *Sym =
|
||||
cast<UndefinedGlobal>(Symtab->addUndefinedGlobal(Name, 0, nullptr, Type));
|
||||
Config->AllowUndefinedSymbols.insert(Sym->getName());
|
||||
Sym->IsUsedInRegularObj = true;
|
||||
return Sym;
|
||||
}
|
||||
|
||||
// Create ABI-defined synthetic symbols
|
||||
static void createSyntheticSymbols() {
|
||||
static WasmSignature NullSignature = {{}, {}};
|
||||
static llvm::wasm::WasmGlobalType GlobalTypeI32 = {WASM_TYPE_I32, false};
|
||||
static llvm::wasm::WasmGlobalType MutableGlobalTypeI32 = {WASM_TYPE_I32,
|
||||
true};
|
||||
|
||||
WasmSym::CallCtors = Symtab->addSyntheticFunction(
|
||||
"__wasm_call_ctors", WASM_SYMBOL_VISIBILITY_HIDDEN,
|
||||
make<SyntheticFunction>(NullSignature, "__wasm_call_ctors"));
|
||||
|
||||
// The __stack_pointer is imported in the shared library case, and exported
|
||||
// in the non-shared (executable) case.
|
||||
if (Config->Shared) {
|
||||
WasmSym::StackPointer =
|
||||
createUndefinedGlobal("__stack_pointer", &MutableGlobalTypeI32);
|
||||
} else {
|
||||
llvm::wasm::WasmGlobal Global;
|
||||
Global.Type = {WASM_TYPE_I32, true};
|
||||
Global.InitExpr.Value.Int32 = 0;
|
||||
Global.InitExpr.Opcode = WASM_OPCODE_I32_CONST;
|
||||
Global.SymbolName = "__stack_pointer";
|
||||
InputGlobal *StackPointer = make<InputGlobal>(Global, nullptr);
|
||||
StackPointer->Live = true;
|
||||
// For non-PIC code
|
||||
// TODO(sbc): Remove WASM_SYMBOL_VISIBILITY_HIDDEN when the mutable global
|
||||
// spec proposal is implemented in all major browsers.
|
||||
// See: https://github.com/WebAssembly/mutable-global
|
||||
WasmSym::StackPointer = Symtab->addSyntheticGlobal(
|
||||
"__stack_pointer", WASM_SYMBOL_VISIBILITY_HIDDEN, StackPointer);
|
||||
WasmSym::HeapBase = Symtab->addSyntheticDataSymbol("__heap_base", 0);
|
||||
WasmSym::DataEnd = Symtab->addSyntheticDataSymbol("__data_end", 0);
|
||||
|
||||
// These two synthetic symbols exist purely for the embedder so we always
|
||||
// want to export them.
|
||||
WasmSym::HeapBase->ForceExport = true;
|
||||
WasmSym::DataEnd->ForceExport = true;
|
||||
}
|
||||
|
||||
if (Config->Pic) {
|
||||
// For PIC code, we import two global variables (__memory_base and
|
||||
// __table_base) from the environment and use these as the offset at
|
||||
// which to load our static data and function table.
|
||||
// See:
|
||||
// https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md
|
||||
WasmSym::MemoryBase =
|
||||
createUndefinedGlobal("__memory_base", &GlobalTypeI32);
|
||||
WasmSym::TableBase = createUndefinedGlobal("__table_base", &GlobalTypeI32);
|
||||
WasmSym::MemoryBase->markLive();
|
||||
WasmSym::TableBase->markLive();
|
||||
}
|
||||
|
||||
WasmSym::DsoHandle = Symtab->addSyntheticDataSymbol(
|
||||
"__dso_handle", WASM_SYMBOL_VISIBILITY_HIDDEN);
|
||||
}
|
||||
|
||||
void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
|
||||
WasmOptTable Parser;
|
||||
opt::InputArgList Args = Parser.parse(ArgsArr.slice(1));
|
||||
@ -480,59 +545,8 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
|
||||
if (Config->Shared)
|
||||
Config->ExportDynamic = true;
|
||||
|
||||
Symbol *EntrySym = nullptr;
|
||||
if (!Config->Relocatable) {
|
||||
llvm::wasm::WasmGlobal Global;
|
||||
Global.Type = {WASM_TYPE_I32, true};
|
||||
Global.InitExpr.Value.Int32 = 0;
|
||||
Global.InitExpr.Opcode = WASM_OPCODE_I32_CONST;
|
||||
Global.SymbolName = "__stack_pointer";
|
||||
InputGlobal *StackPointer = make<InputGlobal>(Global, nullptr);
|
||||
StackPointer->Live = true;
|
||||
|
||||
static WasmSignature NullSignature = {{}, {}};
|
||||
|
||||
// Add synthetic symbols before any others
|
||||
WasmSym::CallCtors = Symtab->addSyntheticFunction(
|
||||
"__wasm_call_ctors", WASM_SYMBOL_VISIBILITY_HIDDEN,
|
||||
make<SyntheticFunction>(NullSignature, "__wasm_call_ctors"));
|
||||
// TODO(sbc): Remove WASM_SYMBOL_VISIBILITY_HIDDEN when the mutable global
|
||||
// spec proposal is implemented in all major browsers.
|
||||
// See: https://github.com/WebAssembly/mutable-global
|
||||
WasmSym::StackPointer = Symtab->addSyntheticGlobal(
|
||||
"__stack_pointer", WASM_SYMBOL_VISIBILITY_HIDDEN, StackPointer);
|
||||
WasmSym::HeapBase = Symtab->addSyntheticDataSymbol("__heap_base", 0);
|
||||
WasmSym::DsoHandle = Symtab->addSyntheticDataSymbol(
|
||||
"__dso_handle", WASM_SYMBOL_VISIBILITY_HIDDEN);
|
||||
WasmSym::DataEnd = Symtab->addSyntheticDataSymbol("__data_end", 0);
|
||||
|
||||
if (Config->Pic) {
|
||||
// For PIC code, we import two global variables (__memory_base and
|
||||
// __table_base) from the environment and use these as the offset at
|
||||
// which to load our static data and function table.
|
||||
// See: https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md
|
||||
static llvm::wasm::WasmGlobalType GlobalTypeI32 = {WASM_TYPE_I32, false};
|
||||
|
||||
WasmSym::MemoryBase = Symtab->addUndefinedGlobal(
|
||||
"__memory_base", WASM_SYMBOL_VISIBILITY_HIDDEN, nullptr,
|
||||
&GlobalTypeI32);
|
||||
Config->AllowUndefinedSymbols.insert(WasmSym::MemoryBase->getName());
|
||||
WasmSym::MemoryBase->IsUsedInRegularObj = true;
|
||||
WasmSym::MemoryBase->markLive();
|
||||
|
||||
WasmSym::TableBase = Symtab->addUndefinedGlobal(
|
||||
"__table_base", WASM_SYMBOL_VISIBILITY_HIDDEN, nullptr,
|
||||
&GlobalTypeI32);
|
||||
Config->AllowUndefinedSymbols.insert(WasmSym::TableBase->getName());
|
||||
WasmSym::TableBase->IsUsedInRegularObj = true;
|
||||
WasmSym::TableBase->markLive();
|
||||
}
|
||||
|
||||
// These two synthetic symbols exist purely for the embedder so we always
|
||||
// want to export them.
|
||||
WasmSym::HeapBase->ForceExport = true;
|
||||
WasmSym::DataEnd->ForceExport = true;
|
||||
}
|
||||
if (!Config->Relocatable)
|
||||
createSyntheticSymbols();
|
||||
|
||||
createFiles(Args);
|
||||
if (errorCount())
|
||||
@ -560,6 +574,7 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
|
||||
Arg->getValue());
|
||||
}
|
||||
|
||||
Symbol *EntrySym = nullptr;
|
||||
if (!Config->Relocatable) {
|
||||
// Add synthetic dummies for weak undefined functions.
|
||||
handleWeakUndefines();
|
||||
|
@ -141,8 +141,7 @@ DataSection::DataSection(ArrayRef<OutputSegment *> Segments)
|
||||
assert(Segments.size() <= 1 &&
|
||||
"Currenly only a single data segment is supported in PIC mode");
|
||||
InitExpr.Opcode = WASM_OPCODE_GET_GLOBAL;
|
||||
InitExpr.Value.Global =
|
||||
cast<GlobalSymbol>(WasmSym::MemoryBase)->getGlobalIndex();
|
||||
InitExpr.Value.Global = WasmSym::MemoryBase->getGlobalIndex();
|
||||
} else {
|
||||
InitExpr.Opcode = WASM_OPCODE_I32_CONST;
|
||||
InitExpr.Value.Int32 = Segment->StartVA;
|
||||
|
@ -27,9 +27,9 @@ DefinedFunction *WasmSym::CallCtors;
|
||||
DefinedData *WasmSym::DsoHandle;
|
||||
DefinedData *WasmSym::DataEnd;
|
||||
DefinedData *WasmSym::HeapBase;
|
||||
DefinedGlobal *WasmSym::StackPointer;
|
||||
Symbol *WasmSym::TableBase;
|
||||
Symbol *WasmSym::MemoryBase;
|
||||
GlobalSymbol *WasmSym::StackPointer;
|
||||
UndefinedGlobal *WasmSym::TableBase;
|
||||
UndefinedGlobal *WasmSym::MemoryBase;
|
||||
|
||||
WasmSymbolType Symbol::getWasmType() const {
|
||||
if (isa<FunctionSymbol>(this))
|
||||
|
@ -291,7 +291,7 @@ struct WasmSym {
|
||||
// __stack_pointer
|
||||
// Global that holds the address of the top of the explicit value stack in
|
||||
// linear memory.
|
||||
static DefinedGlobal *StackPointer;
|
||||
static GlobalSymbol *StackPointer;
|
||||
|
||||
// __data_end
|
||||
// Symbol marking the end of the data and bss.
|
||||
@ -313,11 +313,11 @@ struct WasmSym {
|
||||
|
||||
// __table_base
|
||||
// Used in PIC code for offset of indirect function table
|
||||
static Symbol *TableBase;
|
||||
static UndefinedGlobal *TableBase;
|
||||
|
||||
// __memory_base
|
||||
// Used in PIC code for offset of global data
|
||||
static Symbol *MemoryBase;
|
||||
static UndefinedGlobal *MemoryBase;
|
||||
};
|
||||
|
||||
// A buffer class that is large enough to hold any Symbol-derived
|
||||
|
@ -332,8 +332,7 @@ void Writer::createElemSection() {
|
||||
WasmInitExpr InitExpr;
|
||||
if (Config->Pic) {
|
||||
InitExpr.Opcode = WASM_OPCODE_GET_GLOBAL;
|
||||
InitExpr.Value.Global =
|
||||
cast<GlobalSymbol>(WasmSym::TableBase)->getGlobalIndex();
|
||||
InitExpr.Value.Global = WasmSym::TableBase->getGlobalIndex();
|
||||
} else {
|
||||
InitExpr.Opcode = WASM_OPCODE_I32_CONST;
|
||||
InitExpr.Value.Int32 = TableBase;
|
||||
@ -632,7 +631,8 @@ void Writer::layoutMemory() {
|
||||
log("mem: stack size = " + Twine(Config->ZStackSize));
|
||||
log("mem: stack base = " + Twine(MemoryPtr));
|
||||
MemoryPtr += Config->ZStackSize;
|
||||
WasmSym::StackPointer->Global->Global.InitExpr.Value.Int32 = MemoryPtr;
|
||||
auto *SP = cast<DefinedGlobal>(WasmSym::StackPointer);
|
||||
SP->Global->Global.InitExpr.Value.Int32 = MemoryPtr;
|
||||
log("mem: stack top = " + Twine(MemoryPtr));
|
||||
};
|
||||
|
||||
@ -666,6 +666,11 @@ void Writer::layoutMemory() {
|
||||
|
||||
log("mem: static data = " + Twine(MemoryPtr - DataStart));
|
||||
|
||||
if (Config->Shared) {
|
||||
MemSize = MemoryPtr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Config->StackFirst)
|
||||
PlaceStack();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user