@@ -580,22 +580,48 @@ void Writer::writeSections() {
580
580
581
581
// Fix the memory layout of the output binary. This assigns memory offsets
582
582
// 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
+ //
584
585
// - initialized data (starting at Config->GlobalBase)
585
586
// - BSS data (not currently implemented in llvm)
586
587
// - explicit stack (Config->ZStackSize)
587
588
// - 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.
588
594
void Writer::layoutMemory () {
595
+ createOutputSegments ();
596
+
589
597
uint32_t MemoryPtr = 0 ;
590
- MemoryPtr = Config->GlobalBase ;
591
- log (" mem: global base = " + Twine (Config->GlobalBase ));
592
598
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;
594
620
595
621
// Arbitrarily set __dso_handle handle to point to the start of the data
596
622
// segments.
597
623
if (WasmSym::DsoHandle)
598
- WasmSym::DsoHandle->setVirtualAddress (MemoryPtr );
624
+ WasmSym::DsoHandle->setVirtualAddress (DataStart );
599
625
600
626
for (OutputSegment *Seg : Segments) {
601
627
MemoryPtr = alignTo (MemoryPtr, Seg->Alignment );
@@ -609,22 +635,15 @@ void Writer::layoutMemory() {
609
635
if (WasmSym::DataEnd)
610
636
WasmSym::DataEnd->setVirtualAddress (MemoryPtr);
611
637
612
- log (" mem: static data = " + Twine (MemoryPtr - Config-> GlobalBase ));
638
+ log (" mem: static data = " + Twine (MemoryPtr - DataStart ));
613
639
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 ();
624
642
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 ) {
628
647
WasmSym::HeapBase->setVirtualAddress (MemoryPtr);
629
648
log (" mem: heap base = " + Twine (MemoryPtr));
630
649
}
0 commit comments