[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