Commit 2dbf66dd69

Andrew Kelley <andrew@ziglang.org>
2024-12-21 05:18:22
wasm linker: implement stack pointer global
1 parent d1cde84
Changed files (3)
src/link/Wasm/Flush.zig
@@ -565,7 +565,15 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
                 .unresolved => unreachable,
                 .__heap_base => @panic("TODO"),
                 .__heap_end => @panic("TODO"),
-                .__stack_pointer => @panic("TODO"),
+                .__stack_pointer => {
+                    try binary_bytes.appendSlice(gpa, &.{
+                        @intFromEnum(std.wasm.Valtype.i32),
+                        @intFromBool(true), // mutable
+                        @intFromEnum(std.wasm.Opcode.i32_const),
+                        0, // leb128 init value
+                        @intFromEnum(std.wasm.Opcode.end),
+                    });
+                },
                 .__tls_align => @panic("TODO"),
                 .__tls_base => @panic("TODO"),
                 .__tls_size => @panic("TODO"),
src/link/Wasm.zig
@@ -361,12 +361,13 @@ pub const OutputFunctionIndex = enum(u32) {
 pub const GlobalIndex = enum(u32) {
     _,
 
-    /// This is only accurate when there is a Zcu.
+    /// This is only accurate when not emitting an object and there is a Zcu.
     pub const stack_pointer: GlobalIndex = @enumFromInt(0);
 
     /// Same as `stack_pointer` but with a safety assertion.
     pub fn stackPointer(wasm: *const Wasm) Global.Index {
         const comp = wasm.base.comp;
+        assert(comp.config.output_mode != .Obj);
         assert(comp.zcu != null);
         return .stack_pointer;
     }
@@ -2450,7 +2451,7 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index
         .variable => |variable| .{ variable.init, variable.owner_nav },
         else => .{ nav.status.resolved.val, nav_index },
     };
-    log.debug("updateNav {} {}", .{ nav.fqn.fmt(ip), chased_nav_index });
+    //log.debug("updateNav {} {}", .{ nav.fqn.fmt(ip), chased_nav_index });
     assert(!wasm.imports.contains(chased_nav_index));
 
     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
     const comp = wasm.base.comp;
     const gpa = comp.gpa;
     const rdynamic = comp.config.rdynamic;
+    const is_obj = comp.config.output_mode == .Obj;
 
     assert(wasm.missing_exports.entries.len == 0);
     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
 
     if (comp.zcu != null) {
         // Zig always depends on a stack pointer global.
-        try wasm.globals.put(gpa, .__stack_pointer, {});
-        assert(wasm.globals.entries.len - 1 == @intFromEnum(GlobalIndex.stack_pointer));
+        // If emitting an object, it's an import. Otherwise, the linker synthesizes it.
+        if (is_obj) {
+            @panic("TODO");
+        } else {
+            try wasm.globals.put(gpa, .__stack_pointer, {});
+            assert(wasm.globals.entries.len - 1 == @intFromEnum(GlobalIndex.stack_pointer));
+        }
     }
 
     // These loops do both recursive marking of alive symbols well as checking for undefined symbols.
src/Compilation.zig
@@ -118,6 +118,8 @@ link_task_queue_safety: std.debug.SafetyLock = .{},
 link_task_queue_postponed: std.ArrayListUnmanaged(link.Task) = .empty,
 /// Initialized with how many link input tasks are expected. After this reaches zero
 /// the linker will begin the prelink phase.
+/// Initialized in the Compilation main thread before the pipeline; modified only in
+/// the linker task thread.
 remaining_prelink_tasks: u32,
 
 work_queues: [