Skip to content

Commit 1a7c47d

Browse files
authoredJan 12, 2022
Merge pull request #10572 from Luukdegram/wasm-linker-stack
Stage2: wasm-linker - Place stack at the beginning of the linear memory
2 parents 7c4c49f + 975049e commit 1a7c47d

File tree

1 file changed

+26
-12
lines changed

1 file changed

+26
-12
lines changed
 

‎src/link/Wasm.zig

+26-12
Original file line numberDiff line numberDiff line change
@@ -494,9 +494,21 @@ fn setupMemory(self: *Wasm) !void {
494494
log.debug("Setting up memory layout", .{});
495495
const page_size = 64 * 1024;
496496
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+
}
500512

501513
var offset: u32 = @intCast(u32, memory_ptr);
502514
for (self.segments.items) |*segment, i| {
@@ -510,8 +522,11 @@ fn setupMemory(self: *Wasm) !void {
510522
offset += segment.size;
511523
}
512524

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+
}
515530

516531
// Setup the max amount of pages
517532
// 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 {
554569
self.memories.limits.max = @intCast(u32, max_memory / page_size);
555570
log.debug("Maximum memory pages: {d}", .{self.memories.limits.max});
556571
}
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));
560572
}
561573

562574
fn resetState(self: *Wasm) void {
@@ -1231,6 +1243,12 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
12311243
if (self.base.options.global_base) |global_base| {
12321244
const arg = try std.fmt.allocPrint(arena, "--global-base={d}", .{global_base});
12331245
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");
12341252
}
12351253

12361254
var auto_export_symbols = true;
@@ -1282,10 +1300,6 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
12821300
const arg = try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size});
12831301
try argv.append(arg);
12841302

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-
12891303
if (self.base.options.wasi_exec_model == .reactor) {
12901304
// Reactor execution model does not have _start so lld doesn't look for it.
12911305
try argv.append("--no-entry");

0 commit comments

Comments
 (0)