authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-11 19:41:18-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-12 12:00:03-07:00
log6f49233ac6a6569b909b689f22fc260dc8c19234
treea31e9c441b7f2e488613d286f46e21b5c99d9eb9
parentbb8eef8d2403fd5b84ca5fd956f381da1c5cd9b0

Merge pull request #10572 from Luukdegram/wasm-linker-stack

Stage2: wasm-linker - Place stack at the beginning of the linear memory

1 files changed, 26 insertions(+), 12 deletions(-)

src/link/Wasm.zig+26-12
...@@ -495,9 +495,21 @@ fn setupMemory(self: *Wasm) !void {...@@ -495,9 +495,21 @@ fn setupMemory(self: *Wasm) !void {
495 log.debug("Setting up memory layout", .{});495 log.debug("Setting up memory layout", .{});
496 const page_size = 64 * 1024;496 const page_size = 64 * 1024;
497 const stack_size = self.base.options.stack_size_override orelse page_size * 1;497 const stack_size = self.base.options.stack_size_override orelse page_size * 1;
498 const stack_alignment = 16;498 const stack_alignment = 16; // wasm's stack alignment as specified by tool-convention
499 var memory_ptr: u64 = self.base.options.global_base orelse 1024;499 // Always place the stack at the start by default
500 memory_ptr = std.mem.alignForwardGeneric(u64, memory_ptr, stack_alignment);500 // unless the user specified the global-base flag
501 var place_stack_first = true;
502 var memory_ptr: u64 = if (self.base.options.global_base) |base| blk: {
503 place_stack_first = false;
504 break :blk base;
505 } else 0;
506
507 if (place_stack_first) {
508 memory_ptr = std.mem.alignForwardGeneric(u64, memory_ptr, stack_alignment);
509 memory_ptr += stack_size;
510 // We always put the stack pointer global at index 0
511 self.globals.items[0].init.i32_const = @bitCast(i32, @intCast(u32, memory_ptr));
512 }
501513
502 var offset: u32 = @intCast(u32, memory_ptr);514 var offset: u32 = @intCast(u32, memory_ptr);
503 for (self.segments.items) |*segment, i| {515 for (self.segments.items) |*segment, i| {
...@@ -511,8 +523,11 @@ fn setupMemory(self: *Wasm) !void {...@@ -511,8 +523,11 @@ fn setupMemory(self: *Wasm) !void {
511 offset += segment.size;523 offset += segment.size;
512 }524 }
513525
514 memory_ptr = std.mem.alignForwardGeneric(u64, memory_ptr, stack_alignment);526 if (!place_stack_first) {
515 memory_ptr += stack_size;527 memory_ptr = std.mem.alignForwardGeneric(u64, memory_ptr, stack_alignment);
528 memory_ptr += stack_size;
529 self.globals.items[0].init.i32_const = @bitCast(i32, @intCast(u32, memory_ptr));
530 }
516531
517 // Setup the max amount of pages532 // Setup the max amount of pages
518 // For now we only support wasm32 by setting the maximum allowed memory size 2^32-1533 // For now we only support wasm32 by setting the maximum allowed memory size 2^32-1
...@@ -555,9 +570,6 @@ fn setupMemory(self: *Wasm) !void {...@@ -555,9 +570,6 @@ fn setupMemory(self: *Wasm) !void {
555 self.memories.limits.max = @intCast(u32, max_memory / page_size);570 self.memories.limits.max = @intCast(u32, max_memory / page_size);
556 log.debug("Maximum memory pages: {d}", .{self.memories.limits.max});571 log.debug("Maximum memory pages: {d}", .{self.memories.limits.max});
557 }572 }
558
559 // We always put the stack pointer global at index 0
560 self.globals.items[0].init.i32_const = @bitCast(i32, @intCast(u32, memory_ptr));
561}573}
562574
563fn resetState(self: *Wasm) void {575fn resetState(self: *Wasm) void {
...@@ -1105,6 +1117,12 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {...@@ -1105,6 +1117,12 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
1105 if (self.base.options.global_base) |global_base| {1117 if (self.base.options.global_base) |global_base| {
1106 const arg = try std.fmt.allocPrint(arena, "--global-base={d}", .{global_base});1118 const arg = try std.fmt.allocPrint(arena, "--global-base={d}", .{global_base});
1107 try argv.append(arg);1119 try argv.append(arg);
1120 } else {
1121 // We prepend it by default, so when a stack overflow happens the runtime will trap correctly,
1122 // rather than silently overwrite all global declarations. See https://github.com/ziglang/zig/issues/4496
1123 //
1124 // The user can overwrite this behavior by setting the global-base
1125 try argv.append("--stack-first");
1108 }1126 }
11091127
1110 // Users are allowed to specify which symbols they want to export to the wasm host.1128 // Users are allowed to specify which symbols they want to export to the wasm host.
...@@ -1125,10 +1143,6 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {...@@ -1125,10 +1143,6 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
1125 const arg = try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size});1143 const arg = try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size});
1126 try argv.append(arg);1144 try argv.append(arg);
11271145
1128 // Put stack before globals so that stack overflow results in segfault immediately
1129 // before corrupting globals. See https://github.com/ziglang/zig/issues/4496
1130 try argv.append("--stack-first");
1131
1132 if (self.base.options.wasi_exec_model == .reactor) {1146 if (self.base.options.wasi_exec_model == .reactor) {
1133 // Reactor execution model does not have _start so lld doesn't look for it.1147 // Reactor execution model does not have _start so lld doesn't look for it.
1134 try argv.append("--no-entry");1148 try argv.append("--no-entry");