authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-11 19:41:18-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-01-11 19:41:18-05:00
log1a7c47d966b9f709b5aa842f0f9786b1d6970e3d
tree7ce327192e48b5414b6ff0310e3f22bf40305045
parent7c4c49ff07de31b1b74f3dc26648ad4000113256
parent975049e96e2245022a90368360fe7f3617e5f194
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

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
...@@ -494,9 +494,21 @@ fn setupMemory(self: *Wasm) !void {...@@ -494,9 +494,21 @@ fn setupMemory(self: *Wasm) !void {
494 log.debug("Setting up memory layout", .{});494 log.debug("Setting up memory layout", .{});
495 const page_size = 64 * 1024;495 const page_size = 64 * 1024;
496 const stack_size = self.base.options.stack_size_override orelse page_size * 1;496 const stack_size = self.base.options.stack_size_override orelse page_size * 1;
497 const stack_alignment = 16;497 const stack_alignment = 16; // wasm's stack alignment as specified by tool-convention
498 var memory_ptr: u64 = self.base.options.global_base orelse 1024;498 // Always place the stack at the start by default
499 memory_ptr = std.mem.alignForwardGeneric(u64, memory_ptr, stack_alignment);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
501 var offset: u32 = @intCast(u32, memory_ptr);513 var offset: u32 = @intCast(u32, memory_ptr);
502 for (self.segments.items) |*segment, i| {514 for (self.segments.items) |*segment, i| {
...@@ -510,8 +522,11 @@ fn setupMemory(self: *Wasm) !void {...@@ -510,8 +522,11 @@ fn setupMemory(self: *Wasm) !void {
510 offset += segment.size;522 offset += segment.size;
511 }523 }
512524
513 memory_ptr = std.mem.alignForwardGeneric(u64, memory_ptr, stack_alignment);525 if (!place_stack_first) {
514 memory_ptr += stack_size;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
516 // Setup the max amount of pages531 // Setup the max amount of pages
517 // For now we only support wasm32 by setting the maximum allowed memory size 2^32-1532 // 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,9 +569,6 @@ fn setupMemory(self: *Wasm) !void {
554 self.memories.limits.max = @intCast(u32, max_memory / page_size);569 self.memories.limits.max = @intCast(u32, max_memory / page_size);
555 log.debug("Maximum memory pages: {d}", .{self.memories.limits.max});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}
561573
562fn resetState(self: *Wasm) void {574fn resetState(self: *Wasm) void {
...@@ -1231,6 +1243,12 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {...@@ -1231,6 +1243,12 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
1231 if (self.base.options.global_base) |global_base| {1243 if (self.base.options.global_base) |global_base| {
1232 const arg = try std.fmt.allocPrint(arena, "--global-base={d}", .{global_base});1244 const arg = try std.fmt.allocPrint(arena, "--global-base={d}", .{global_base});
1233 try argv.append(arg);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 }
12351253
1236 var auto_export_symbols = true;1254 var auto_export_symbols = true;
...@@ -1282,10 +1300,6 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {...@@ -1282,10 +1300,6 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
1282 const arg = try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size});1300 const arg = try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size});
1283 try argv.append(arg);1301 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
1289 if (self.base.options.wasi_exec_model == .reactor) {1303 if (self.base.options.wasi_exec_model == .reactor) {
1290 // Reactor execution model does not have _start so lld doesn't look for it.1304 // Reactor execution model does not have _start so lld doesn't look for it.
1291 try argv.append("--no-entry");1305 try argv.append("--no-entry");