From 2dad4e2c6d494e997de41f5cc391e6bc6a171e35 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 15 Nov 2018 18:15:54 +0000 Subject: [PATCH] [WebAssembly] Import the stack pointer when building shared libraries Differential Revision: https://reviews.llvm.org/D54558 llvm-svn: 346974 --- lld/test/wasm/shared.ll | 11 +++- lld/wasm/Driver.cpp | 121 +++++++++++++++++++++++++------------------- lld/wasm/OutputSections.cpp | 3 +- lld/wasm/Symbols.cpp | 6 +-- lld/wasm/Symbols.h | 6 +-- lld/wasm/Writer.cpp | 11 ++-- 6 files changed, 92 insertions(+), 66 deletions(-) diff --git a/lld/test/wasm/shared.ll b/lld/test/wasm/shared.ll index bfffa84..c0e947f 100644 --- a/lld/test/wasm/shared.ll +++ b/lld/test/wasm/shared.ll @@ -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' diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index 398205c..c86e0b1 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -431,6 +431,71 @@ static Symbol *handleUndefined(StringRef Name) { return Sym; } +static UndefinedGlobal * +createUndefinedGlobal(StringRef Name, llvm::wasm::WasmGlobalType *Type) { + auto *Sym = + cast(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(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(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 ArgsArr) { WasmOptTable Parser; opt::InputArgList Args = Parser.parse(ArgsArr.slice(1)); @@ -480,59 +545,8 @@ void LinkerDriver::link(ArrayRef 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(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(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 ArgsArr) { Arg->getValue()); } + Symbol *EntrySym = nullptr; if (!Config->Relocatable) { // Add synthetic dummies for weak undefined functions. handleWeakUndefines(); diff --git a/lld/wasm/OutputSections.cpp b/lld/wasm/OutputSections.cpp index 1925e5e..ab27170 100644 --- a/lld/wasm/OutputSections.cpp +++ b/lld/wasm/OutputSections.cpp @@ -141,8 +141,7 @@ DataSection::DataSection(ArrayRef 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(WasmSym::MemoryBase)->getGlobalIndex(); + InitExpr.Value.Global = WasmSym::MemoryBase->getGlobalIndex(); } else { InitExpr.Opcode = WASM_OPCODE_I32_CONST; InitExpr.Value.Int32 = Segment->StartVA; diff --git a/lld/wasm/Symbols.cpp b/lld/wasm/Symbols.cpp index d997d77..dacb5ca 100644 --- a/lld/wasm/Symbols.cpp +++ b/lld/wasm/Symbols.cpp @@ -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(this)) diff --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h index e5d8bf2..ecae5d0 100644 --- a/lld/wasm/Symbols.h +++ b/lld/wasm/Symbols.h @@ -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 diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index 6048508..b5abb6b 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -332,8 +332,7 @@ void Writer::createElemSection() { WasmInitExpr InitExpr; if (Config->Pic) { InitExpr.Opcode = WASM_OPCODE_GET_GLOBAL; - InitExpr.Value.Global = - cast(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(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(); -- 2.7.4