@@ -494,9 +494,21 @@ fn setupMemory(self: *Wasm) !void {
494
494
log .debug ("Setting up memory layout" , .{});
495
495
const page_size = 64 * 1024 ;
496
496
const stack_size = self .base .options .stack_size_override orelse page_size * 1 ;
497
- const stack_alignment = 16 ;
498
- var memory_ptr : u64 = self .base .options .global_base orelse 1024 ;
499
- memory_ptr = std .mem .alignForwardGeneric (u64 , memory_ptr , stack_alignment );
497
+ const stack_alignment = 16 ; // wasm's stack alignment as specified by tool-convention
498
+ // Always place the stack at the start by default
499
+ // unless the user specified the global-base flag
500
+ var place_stack_first = true ;
501
+ var memory_ptr : u64 = if (self .base .options .global_base ) | base | blk : {
502
+ place_stack_first = false ;
503
+ break :blk base ;
504
+ } else 0 ;
505
+
506
+ if (place_stack_first ) {
507
+ memory_ptr = std .mem .alignForwardGeneric (u64 , memory_ptr , stack_alignment );
508
+ memory_ptr += stack_size ;
509
+ // We always put the stack pointer global at index 0
510
+ self .globals .items [0 ].init .i32_const = @bitCast (i32 , @intCast (u32 , memory_ptr ));
511
+ }
500
512
501
513
var offset : u32 = @intCast (u32 , memory_ptr );
502
514
for (self .segments .items ) | * segment , i | {
@@ -510,8 +522,11 @@ fn setupMemory(self: *Wasm) !void {
510
522
offset += segment .size ;
511
523
}
512
524
513
- memory_ptr = std .mem .alignForwardGeneric (u64 , memory_ptr , stack_alignment );
514
- memory_ptr += stack_size ;
525
+ if (! place_stack_first ) {
526
+ memory_ptr = std .mem .alignForwardGeneric (u64 , memory_ptr , stack_alignment );
527
+ memory_ptr += stack_size ;
528
+ self .globals .items [0 ].init .i32_const = @bitCast (i32 , @intCast (u32 , memory_ptr ));
529
+ }
515
530
516
531
// Setup the max amount of pages
517
532
// For now we only support wasm32 by setting the maximum allowed memory size 2^32-1
@@ -554,9 +569,6 @@ fn setupMemory(self: *Wasm) !void {
554
569
self .memories .limits .max = @intCast (u32 , max_memory / page_size );
555
570
log .debug ("Maximum memory pages: {d}" , .{self .memories .limits .max });
556
571
}
557
-
558
- // We always put the stack pointer global at index 0
559
- self .globals .items [0 ].init .i32_const = @bitCast (i32 , @intCast (u32 , memory_ptr ));
560
572
}
561
573
562
574
fn resetState (self : * Wasm ) void {
@@ -1231,6 +1243,12 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
1231
1243
if (self .base .options .global_base ) | global_base | {
1232
1244
const arg = try std .fmt .allocPrint (arena , "--global-base={d}" , .{global_base });
1233
1245
try argv .append (arg );
1246
+ } else {
1247
+ // We prepend it by default, so when a stack overflow happens the runtime will trap correctly,
1248
+ // rather than silently overwrite all global declarations. See https://github.com/ziglang/zig/issues/4496
1249
+ //
1250
+ // The user can overwrite this behavior by setting the global-base
1251
+ try argv .append ("--stack-first" );
1234
1252
}
1235
1253
1236
1254
var auto_export_symbols = true ;
@@ -1282,10 +1300,6 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
1282
1300
const arg = try std .fmt .allocPrint (arena , "stack-size={d}" , .{stack_size });
1283
1301
try argv .append (arg );
1284
1302
1285
- // Put stack before globals so that stack overflow results in segfault immediately
1286
- // before corrupting globals. See https://github.com/ziglang/zig/issues/4496
1287
- try argv .append ("--stack-first" );
1288
-
1289
1303
if (self .base .options .wasi_exec_model == .reactor ) {
1290
1304
// Reactor execution model does not have _start so lld doesn't look for it.
1291
1305
try argv .append ("--no-entry" );
0 commit comments