[WebAssembly] Import the stack pointer when building shared libraries
Differential Revision: https://reviews.llvm.org/D54558
git-svn-id: https://llvm.org/svn/llvm-project/lld/trunk@346974 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/wasm/shared.ll b/test/wasm/shared.ll
index bfffa84..c0e947f 100644
--- a/test/wasm/shared.ll
+++ b/test/wasm/shared.ll
@@ -9,6 +9,8 @@
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 @@
; 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 @@
; 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 @@
; CHECK-NEXT: MemoryIndex: 0
; CHECK-NEXT: Offset:
; CHECK-NEXT: Opcode: GET_GLOBAL
-; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Index: 1
; CHECK-NEXT: Content: '00000000'
diff --git a/wasm/Driver.cpp b/wasm/Driver.cpp
index 398205c..c86e0b1 100644
--- a/wasm/Driver.cpp
+++ b/wasm/Driver.cpp
@@ -431,6 +431,71 @@
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 @@
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 @@
Arg->getValue());
}
+ Symbol *EntrySym = nullptr;
if (!Config->Relocatable) {
// Add synthetic dummies for weak undefined functions.
handleWeakUndefines();
diff --git a/wasm/OutputSections.cpp b/wasm/OutputSections.cpp
index 1925e5e..ab27170 100644
--- a/wasm/OutputSections.cpp
+++ b/wasm/OutputSections.cpp
@@ -141,8 +141,7 @@
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;
diff --git a/wasm/Symbols.cpp b/wasm/Symbols.cpp
index d997d77..dacb5ca 100644
--- a/wasm/Symbols.cpp
+++ b/wasm/Symbols.cpp
@@ -27,9 +27,9 @@
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))
diff --git a/wasm/Symbols.h b/wasm/Symbols.h
index e5d8bf2..ecae5d0 100644
--- a/wasm/Symbols.h
+++ b/wasm/Symbols.h
@@ -291,7 +291,7 @@
// __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 @@
// __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
diff --git a/wasm/Writer.cpp b/wasm/Writer.cpp
index 6048508..b5abb6b 100644
--- a/wasm/Writer.cpp
+++ b/wasm/Writer.cpp
@@ -332,8 +332,7 @@
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 @@
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 @@
log("mem: static data = " + Twine(MemoryPtr - DataStart));
+ if (Config->Shared) {
+ MemSize = MemoryPtr;
+ return;
+ }
+
if (!Config->StackFirst)
PlaceStack();