[WebAssembly] Import the stack pointer when building shared libraries

Differential Revision: https://reviews.llvm.org/D54558

llvm-svn: 346974
This commit is contained in:
Sam Clegg 2018-11-15 18:15:54 +00:00
parent aa3f2494b3
commit 2dad4e2c6d
6 changed files with 92 additions and 66 deletions

View File

@ -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'

View File

@ -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();

View File

@ -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;

View File

@ -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))

View File

@ -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

View File

@ -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();