authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2021-11-17 08:58:08+01:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2021-11-21 21:07:51+01:00
logc18bc08e3c658f50faf7668f8940a11326f3947a
tree90f40dbeecbcd09c0a96c4aaa716d66496fe5d01
parent05330bbe0ddd3057a1badea92a7823a2b1f4d68a
signaturelock-open Commit is signed but in an unrecognized format.

wasm: Linker - emit stack pointer

The self-hosted wasm linker now emits a mutable global. This entry represents the stack pointer, which has an initial value of offset table size + data size + stack size. Stack size can either be set by the user, or has the default of a single wasm page (64KiB).

1 files changed, 32 insertions(+), 2 deletions(-)

src/link/Wasm.zig+32-2
...@@ -404,6 +404,8 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {...@@ -404,6 +404,8 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
404 // The table contains all decl's with its corresponding offset into404 // The table contains all decl's with its corresponding offset into
405 // the 'data' section405 // the 'data' section
406 const offset_table_size = @intCast(u32, self.offset_table.items.len * ptr_width);406 const offset_table_size = @intCast(u32, self.offset_table.items.len * ptr_width);
407 // The size of the emulated stack
408 const stack_size = @intCast(u32, self.base.options.stack_size_override orelse std.wasm.page_size);
407409
408 // The size of the data, this together with `offset_table_size` amounts to the410 // The size of the data, this together with `offset_table_size` amounts to the
409 // total size of the 'data' section411 // total size of the 'data' section
...@@ -487,7 +489,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {...@@ -487,7 +489,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
487 }489 }
488490
489 // Memory section491 // Memory section
490 if (data_size != 0) {492 {
491 const header_offset = try reserveVecSectionHeader(file);493 const header_offset = try reserveVecSectionHeader(file);
492 const writer = file.writer();494 const writer = file.writer();
493495
...@@ -498,7 +500,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {...@@ -498,7 +500,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
498 writer,500 writer,
499 try std.math.divCeil(501 try std.math.divCeil(
500 u32,502 u32,
501 offset_table_size + data_size,503 offset_table_size + data_size + stack_size,
502 std.wasm.page_size,504 std.wasm.page_size,
503 ),505 ),
504 );506 );
...@@ -511,6 +513,34 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {...@@ -511,6 +513,34 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
511 );513 );
512 }514 }
513515
516 // Global section (used to emit stack pointer)
517 {
518 // We emit the emulated stack at the end of the data section,
519 // 'growing' downwards towards the program memory.
520 // TODO: Have linker resolve the offset table, so we can emit the stack
521 // at the start so we can't overwrite program memory with the stack.
522 const sp_value = offset_table_size + data_size + std.wasm.page_size;
523 const mutable = true; // stack pointer MUST be mutable
524 const header_offset = try reserveVecSectionHeader(file);
525 const writer = file.writer();
526
527 try writer.writeByte(wasm.valtype(.i32));
528 try writer.writeByte(@boolToInt(mutable));
529
530 // set the initial value of the stack pointer to the data size + stack size
531 try writer.writeByte(wasm.opcode(.i32_const));
532 try leb.writeILEB128(writer, @bitCast(i32, sp_value));
533 try writer.writeByte(wasm.opcode(.end));
534
535 try writeVecSectionHeader(
536 file,
537 header_offset,
538 .global,
539 @intCast(u32, (try file.getPos()) - header_offset - header_size),
540 @as(u32, 1),
541 );
542 }
543
514 // Export section544 // Export section
515 if (self.base.options.module) |module| {545 if (self.base.options.module) |module| {
516 const header_offset = try reserveVecSectionHeader(file);546 const header_offset = try reserveVecSectionHeader(file);