@@ -580,22 +580,48 @@ void Writer::writeSections() {
580580
581581// Fix the memory layout of the output binary. This assigns memory offsets
582582// to each of the input data sections as well as the explicit stack region.
583- // The memory layout is as follows, from low to high.
583+ // The default memory layout is as follows, from low to high.
584+ //
584585// - initialized data (starting at Config->GlobalBase)
585586// - BSS data (not currently implemented in llvm)
586587// - explicit stack (Config->ZStackSize)
587588// - heap start / unallocated
589+ //
590+ // The --stack-first option means that stack is placed before any static data.
591+ // This can be useful since it means that stack overflow traps immediately rather
592+ // than overwriting global data, but also increases code size since all static
593+ // data loads and stores requires larger offsets.
588594void Writer::layoutMemory () {
595+ createOutputSegments ();
596+
589597 uint32_t MemoryPtr = 0 ;
590- MemoryPtr = Config->GlobalBase ;
591- log (" mem: global base = " + Twine (Config->GlobalBase ));
592598
593- createOutputSegments ();
599+ auto PlaceStack = [&]() {
600+ if (Config->Relocatable )
601+ return ;
602+ MemoryPtr = alignTo (MemoryPtr, kStackAlignment );
603+ if (Config->ZStackSize != alignTo (Config->ZStackSize , kStackAlignment ))
604+ error (" stack size must be " + Twine (kStackAlignment ) + " -byte aligned" );
605+ log (" mem: stack size = " + Twine (Config->ZStackSize ));
606+ log (" mem: stack base = " + Twine (MemoryPtr));
607+ MemoryPtr += Config->ZStackSize ;
608+ WasmSym::StackPointer->Global ->Global .InitExpr .Value .Int32 = MemoryPtr;
609+ log (" mem: stack top = " + Twine (MemoryPtr));
610+ };
611+
612+ if (Config->StackFirst ) {
613+ PlaceStack ();
614+ } else {
615+ MemoryPtr = Config->GlobalBase ;
616+ log (" mem: global base = " + Twine (Config->GlobalBase ));
617+ }
618+
619+ uint32_t DataStart = MemoryPtr;
594620
595621 // Arbitrarily set __dso_handle handle to point to the start of the data
596622 // segments.
597623 if (WasmSym::DsoHandle)
598- WasmSym::DsoHandle->setVirtualAddress (MemoryPtr );
624+ WasmSym::DsoHandle->setVirtualAddress (DataStart );
599625
600626 for (OutputSegment *Seg : Segments) {
601627 MemoryPtr = alignTo (MemoryPtr, Seg->Alignment );
@@ -609,22 +635,15 @@ void Writer::layoutMemory() {
609635 if (WasmSym::DataEnd)
610636 WasmSym::DataEnd->setVirtualAddress (MemoryPtr);
611637
612- log (" mem: static data = " + Twine (MemoryPtr - Config-> GlobalBase ));
638+ log (" mem: static data = " + Twine (MemoryPtr - DataStart ));
613639
614- // Stack comes after static data and bss
615- if (!Config->Relocatable ) {
616- MemoryPtr = alignTo (MemoryPtr, kStackAlignment );
617- if (Config->ZStackSize != alignTo (Config->ZStackSize , kStackAlignment ))
618- error (" stack size must be " + Twine (kStackAlignment ) + " -byte aligned" );
619- log (" mem: stack size = " + Twine (Config->ZStackSize ));
620- log (" mem: stack base = " + Twine (MemoryPtr));
621- MemoryPtr += Config->ZStackSize ;
622- WasmSym::StackPointer->Global ->Global .InitExpr .Value .Int32 = MemoryPtr;
623- log (" mem: stack top = " + Twine (MemoryPtr));
640+ if (!Config->StackFirst )
641+ PlaceStack ();
624642
625- // Set `__heap_base` to directly follow the end of the stack. We don't
626- // allocate any heap memory up front, but instead really on the malloc/brk
627- // implementation growing the memory at runtime.
643+ // Set `__heap_base` to directly follow the end of the stack or global data.
644+ // The fact that this comes last means that a malloc/brk implementation
645+ // can grow the heap at runtime.
646+ if (!Config->Relocatable ) {
628647 WasmSym::HeapBase->setVirtualAddress (MemoryPtr);
629648 log (" mem: heap base = " + Twine (MemoryPtr));
630649 }
0 commit comments