| ... | ... | @@ -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"); |