[lld] r331467 - [WebAssembly] Add --stack-first option which places the shadow stack at start of linear memory
Sam Clegg via llvm-commits
llvm-commits at lists.llvm.org
Thu May 3 10:21:53 PDT 2018
Author: sbc
Date: Thu May 3 10:21:53 2018
New Revision: 331467
URL: http://llvm.org/viewvc/llvm-project?rev=331467&view=rev
Log:
[WebAssembly] Add --stack-first option which places the shadow stack at start of linear memory
Fixes https://bugs.llvm.org/show_bug.cgi?id=37181
Differential Revision: https://reviews.llvm.org/D46141
Added:
lld/trunk/test/wasm/stack-first.test
Modified:
lld/trunk/wasm/Config.h
lld/trunk/wasm/Driver.cpp
lld/trunk/wasm/Options.td
lld/trunk/wasm/Writer.cpp
Added: lld/trunk/test/wasm/stack-first.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/stack-first.test?rev=331467&view=auto
==============================================================================
--- lld/trunk/test/wasm/stack-first.test (added)
+++ lld/trunk/test/wasm/stack-first.test Thu May 3 10:21:53 2018
@@ -0,0 +1,42 @@
+; Test that the --stack-first option places the stack at the start of linear
+; memory. In this case the --stack-first option is being passed along with a
+; stack size of 512. This means (since the stack grows down) the stack pointer
+; global should be initialized to 512.
+
+RUN: llc -filetype=obj %p/Inputs/start.ll -o %t.o
+
+RUN: wasm-ld --check-signatures -z stack-size=512 --stack-first --allow-undefined -o %t.wasm %t.o
+RUN: obj2yaml %t.wasm | FileCheck %s
+
+CHECK: - Type: GLOBAL
+CHECK-NEXT: Globals:
+CHECK-NEXT: - Index: 0
+CHECK-NEXT: Type: I32
+CHECK-NEXT: Mutable: true
+CHECK-NEXT: InitExpr:
+CHECK-NEXT: Opcode: I32_CONST
+CHECK-NEXT: Value: 512
+CHECK-NEXT: - Index: 1
+CHECK-NEXT: Type: I32
+CHECK-NEXT: Mutable: false
+CHECK-NEXT: InitExpr:
+CHECK-NEXT: Opcode: I32_CONST
+CHECK-NEXT: Value: 512
+CHECK-NEXT: - Index: 2
+CHECK-NEXT: Type: I32
+CHECK-NEXT: Mutable: false
+CHECK-NEXT: InitExpr:
+CHECK-NEXT: Opcode: I32_CONST
+CHECK-NEXT: Value: 512
+CHECK-NEXT: - Type: EXPORT
+CHECK-NEXT: Exports:
+CHECK-NEXT: - Name: memory
+CHECK-NEXT: Kind: MEMORY
+CHECK-NEXT: Index: 0
+CHECK-NEXT: - Name: __heap_base
+CHECK-NEXT: Kind: GLOBAL
+CHECK-NEXT: Index: 1
+CHECK-NEXT: - Name: __data_end
+CHECK-NEXT: Kind: GLOBAL
+CHECK-NEXT: Index: 2
+
Modified: lld/trunk/wasm/Config.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Config.h?rev=331467&r1=331466&r2=331467&view=diff
==============================================================================
--- lld/trunk/wasm/Config.h (original)
+++ lld/trunk/wasm/Config.h Thu May 3 10:21:53 2018
@@ -29,6 +29,7 @@ struct Configuration {
bool Relocatable;
bool StripAll;
bool StripDebug;
+ bool StackFirst;
uint32_t GlobalBase;
uint32_t InitialMemory;
uint32_t MaxMemory;
Modified: lld/trunk/wasm/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Driver.cpp?rev=331467&r1=331466&r2=331467&view=diff
==============================================================================
--- lld/trunk/wasm/Driver.cpp (original)
+++ lld/trunk/wasm/Driver.cpp Thu May 3 10:21:53 2018
@@ -298,6 +298,7 @@ void LinkerDriver::link(ArrayRef<const c
Config->SearchPaths = args::getStrings(Args, OPT_L);
Config->StripAll = Args.hasArg(OPT_strip_all);
Config->StripDebug = Args.hasArg(OPT_strip_debug);
+ Config->StackFirst = Args.hasArg(OPT_stack_first);
errorHandler().Verbose = Args.hasArg(OPT_verbose);
ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true);
Modified: lld/trunk/wasm/Options.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Options.td?rev=331467&r1=331466&r2=331467&view=diff
==============================================================================
--- lld/trunk/wasm/Options.td (original)
+++ lld/trunk/wasm/Options.td Thu May 3 10:21:53 2018
@@ -124,6 +124,9 @@ def max_memory: J<"max-memory=">,
def no_entry: F<"no-entry">,
HelpText<"Do not output any entry point">;
+def stack_first: F<"stack-first">,
+ HelpText<"Place stack at start of linear memory rather than after data">;
+
// Aliases
def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>;
def alias_entry_entry: J<"entry=">, Alias<entry>;
Modified: lld/trunk/wasm/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Writer.cpp?rev=331467&r1=331466&r2=331467&view=diff
==============================================================================
--- lld/trunk/wasm/Writer.cpp (original)
+++ lld/trunk/wasm/Writer.cpp Thu May 3 10:21:53 2018
@@ -580,22 +580,48 @@ void Writer::writeSections() {
// Fix the memory layout of the output binary. This assigns memory offsets
// to each of the input data sections as well as the explicit stack region.
-// The memory layout is as follows, from low to high.
+// The default memory layout is as follows, from low to high.
+//
// - initialized data (starting at Config->GlobalBase)
// - BSS data (not currently implemented in llvm)
// - explicit stack (Config->ZStackSize)
// - heap start / unallocated
+//
+// The --stack-first option means that stack is placed before any static data.
+// This can be useful since it means that stack overflow traps immediately rather
+// than overwriting global data, but also increases code size since all static
+// data loads and stores requires larger offsets.
void Writer::layoutMemory() {
+ createOutputSegments();
+
uint32_t MemoryPtr = 0;
- MemoryPtr = Config->GlobalBase;
- log("mem: global base = " + Twine(Config->GlobalBase));
- createOutputSegments();
+ auto PlaceStack = [&]() {
+ if (Config->Relocatable)
+ return;
+ MemoryPtr = alignTo(MemoryPtr, kStackAlignment);
+ if (Config->ZStackSize != alignTo(Config->ZStackSize, kStackAlignment))
+ error("stack size must be " + Twine(kStackAlignment) + "-byte aligned");
+ log("mem: stack size = " + Twine(Config->ZStackSize));
+ log("mem: stack base = " + Twine(MemoryPtr));
+ MemoryPtr += Config->ZStackSize;
+ WasmSym::StackPointer->Global->Global.InitExpr.Value.Int32 = MemoryPtr;
+ log("mem: stack top = " + Twine(MemoryPtr));
+ };
+
+ if (Config->StackFirst) {
+ PlaceStack();
+ } else {
+ MemoryPtr = Config->GlobalBase;
+ log("mem: global base = " + Twine(Config->GlobalBase));
+ }
+
+ uint32_t DataStart = MemoryPtr;
// Arbitrarily set __dso_handle handle to point to the start of the data
// segments.
if (WasmSym::DsoHandle)
- WasmSym::DsoHandle->setVirtualAddress(MemoryPtr);
+ WasmSym::DsoHandle->setVirtualAddress(DataStart);
for (OutputSegment *Seg : Segments) {
MemoryPtr = alignTo(MemoryPtr, Seg->Alignment);
@@ -609,22 +635,15 @@ void Writer::layoutMemory() {
if (WasmSym::DataEnd)
WasmSym::DataEnd->setVirtualAddress(MemoryPtr);
- log("mem: static data = " + Twine(MemoryPtr - Config->GlobalBase));
+ log("mem: static data = " + Twine(MemoryPtr - DataStart));
- // Stack comes after static data and bss
- if (!Config->Relocatable) {
- MemoryPtr = alignTo(MemoryPtr, kStackAlignment);
- if (Config->ZStackSize != alignTo(Config->ZStackSize, kStackAlignment))
- error("stack size must be " + Twine(kStackAlignment) + "-byte aligned");
- log("mem: stack size = " + Twine(Config->ZStackSize));
- log("mem: stack base = " + Twine(MemoryPtr));
- MemoryPtr += Config->ZStackSize;
- WasmSym::StackPointer->Global->Global.InitExpr.Value.Int32 = MemoryPtr;
- log("mem: stack top = " + Twine(MemoryPtr));
+ if (!Config->StackFirst)
+ PlaceStack();
- // Set `__heap_base` to directly follow the end of the stack. We don't
- // allocate any heap memory up front, but instead really on the malloc/brk
- // implementation growing the memory at runtime.
+ // Set `__heap_base` to directly follow the end of the stack or global data.
+ // The fact that this comes last means that a malloc/brk implementation
+ // can grow the heap at runtime.
+ if (!Config->Relocatable) {
WasmSym::HeapBase->setVirtualAddress(MemoryPtr);
log("mem: heap base = " + Twine(MemoryPtr));
}
More information about the llvm-commits
mailing list