authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-12-20 20:18:22-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-15 15:11:36-08:00
log2dbf66dd698601ae8aaee86d5ba6a9078dda0a8e
tree99a3638fd838df2472dd1e051e0ec0b9838e6605
parentd1cde847a367c526c63d65714583189fa2912731

wasm linker: implement stack pointer global


3 files changed, 22 insertions(+), 5 deletions(-)

src/Compilation.zig+2
...@@ -118,6 +118,8 @@ link_task_queue_safety: std.debug.SafetyLock = .{},...@@ -118,6 +118,8 @@ link_task_queue_safety: std.debug.SafetyLock = .{},
118link_task_queue_postponed: std.ArrayListUnmanaged(link.Task) = .empty,118link_task_queue_postponed: std.ArrayListUnmanaged(link.Task) = .empty,
119/// Initialized with how many link input tasks are expected. After this reaches zero119/// Initialized with how many link input tasks are expected. After this reaches zero
120/// the linker will begin the prelink phase.120/// the linker will begin the prelink phase.
121/// Initialized in the Compilation main thread before the pipeline; modified only in
122/// the linker task thread.
121remaining_prelink_tasks: u32,123remaining_prelink_tasks: u32,
122124
123work_queues: [125work_queues: [
src/link/Wasm.zig+11-4
...@@ -361,12 +361,13 @@ pub const OutputFunctionIndex = enum(u32) {...@@ -361,12 +361,13 @@ pub const OutputFunctionIndex = enum(u32) {
361pub const GlobalIndex = enum(u32) {361pub const GlobalIndex = enum(u32) {
362 _,362 _,
363363
364 /// This is only accurate when there is a Zcu.364 /// This is only accurate when not emitting an object and there is a Zcu.
365 pub const stack_pointer: GlobalIndex = @enumFromInt(0);365 pub const stack_pointer: GlobalIndex = @enumFromInt(0);
366366
367 /// Same as `stack_pointer` but with a safety assertion.367 /// Same as `stack_pointer` but with a safety assertion.
368 pub fn stackPointer(wasm: *const Wasm) Global.Index {368 pub fn stackPointer(wasm: *const Wasm) Global.Index {
369 const comp = wasm.base.comp;369 const comp = wasm.base.comp;
370 assert(comp.config.output_mode != .Obj);
370 assert(comp.zcu != null);371 assert(comp.zcu != null);
371 return .stack_pointer;372 return .stack_pointer;
372 }373 }
...@@ -2450,7 +2451,7 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index...@@ -2450,7 +2451,7 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index
2450 .variable => |variable| .{ variable.init, variable.owner_nav },2451 .variable => |variable| .{ variable.init, variable.owner_nav },
2451 else => .{ nav.status.resolved.val, nav_index },2452 else => .{ nav.status.resolved.val, nav_index },
2452 };2453 };
2453 log.debug("updateNav {} {}", .{ nav.fqn.fmt(ip), chased_nav_index });2454 //log.debug("updateNav {} {}", .{ nav.fqn.fmt(ip), chased_nav_index });
2454 assert(!wasm.imports.contains(chased_nav_index));2455 assert(!wasm.imports.contains(chased_nav_index));
24552456
2456 if (nav_init != .none and !Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(zcu)) {2457 if (nav_init != .none and !Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(zcu)) {
...@@ -2578,6 +2579,7 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v...@@ -2578,6 +2579,7 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v
2578 const comp = wasm.base.comp;2579 const comp = wasm.base.comp;
2579 const gpa = comp.gpa;2580 const gpa = comp.gpa;
2580 const rdynamic = comp.config.rdynamic;2581 const rdynamic = comp.config.rdynamic;
2582 const is_obj = comp.config.output_mode == .Obj;
25812583
2582 assert(wasm.missing_exports.entries.len == 0);2584 assert(wasm.missing_exports.entries.len == 0);
2583 for (wasm.export_symbol_names) |exp_name| {2585 for (wasm.export_symbol_names) |exp_name| {
...@@ -2614,8 +2616,13 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v...@@ -2614,8 +2616,13 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v
26142616
2615 if (comp.zcu != null) {2617 if (comp.zcu != null) {
2616 // Zig always depends on a stack pointer global.2618 // Zig always depends on a stack pointer global.
2617 try wasm.globals.put(gpa, .__stack_pointer, {});2619 // If emitting an object, it's an import. Otherwise, the linker synthesizes it.
2618 assert(wasm.globals.entries.len - 1 == @intFromEnum(GlobalIndex.stack_pointer));2620 if (is_obj) {
2621 @panic("TODO");
2622 } else {
2623 try wasm.globals.put(gpa, .__stack_pointer, {});
2624 assert(wasm.globals.entries.len - 1 == @intFromEnum(GlobalIndex.stack_pointer));
2625 }
2619 }2626 }
26202627
2621 // These loops do both recursive marking of alive symbols well as checking for undefined symbols.2628 // These loops do both recursive marking of alive symbols well as checking for undefined symbols.
src/link/Wasm/Flush.zig+9-1
...@@ -565,7 +565,15 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -565,7 +565,15 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
565 .unresolved => unreachable,565 .unresolved => unreachable,
566 .__heap_base => @panic("TODO"),566 .__heap_base => @panic("TODO"),
567 .__heap_end => @panic("TODO"),567 .__heap_end => @panic("TODO"),
568 .__stack_pointer => @panic("TODO"),568 .__stack_pointer => {
569 try binary_bytes.appendSlice(gpa, &.{
570 @intFromEnum(std.wasm.Valtype.i32),
571 @intFromBool(true), // mutable
572 @intFromEnum(std.wasm.Opcode.i32_const),
573 0, // leb128 init value
574 @intFromEnum(std.wasm.Opcode.end),
575 });
576 },
569 .__tls_align => @panic("TODO"),577 .__tls_align => @panic("TODO"),
570 .__tls_base => @panic("TODO"),578 .__tls_base => @panic("TODO"),
571 .__tls_size => @panic("TODO"),579 .__tls_size => @panic("TODO"),