authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2024-01-14 17:24:18+01:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2024-02-29 15:23:02+01:00
log9b3c8fd3a8aef81f3a6face78f9e0b34508edc1b
tree7026f5e6baf349298971e6dd3aa68cf0d8edb452
parente54177e852e5674ff14a850586b7517697e52297
signaturelock-open Commit is signed but in an unrecognized format.

wasm: initialize a `ZigObject` when required

When we have a ZigCompileUnit and don't use LLVM, we initialize the ZigObject which will encapsulate the Zig Module as an object file in- memory. During initialization we also create symbols which the object will need such as the stack pointer.

2 files changed, 82 insertions(+), 30 deletions(-)

src/link/Wasm.zig+48-21
...@@ -1,37 +1,41 @@...@@ -1,37 +1,41 @@
1const Wasm = @This();1const Wasm = @This();
22
3const std = @import("std");3const std = @import("std");
4const builtin = @import("builtin");4
5const mem = std.mem;
6const Allocator = std.mem.Allocator;
7const assert = std.debug.assert;5const assert = std.debug.assert;
6const build_options = @import("build_options");
7const builtin = @import("builtin");
8const codegen = @import("../codegen.zig");
8const fs = std.fs;9const fs = std.fs;
9const leb = std.leb;10const leb = std.leb;
10const log = std.log.scoped(.link);
11
12pub const Atom = @import("Wasm/Atom.zig");
13const Dwarf = @import("Dwarf.zig");
14const Module = @import("../Module.zig");
15const InternPool = @import("../InternPool.zig");
16const Compilation = @import("../Compilation.zig");
17const CodeGen = @import("../arch/wasm/CodeGen.zig");
18const codegen = @import("../codegen.zig");
19const link = @import("../link.zig");11const link = @import("../link.zig");
20const lldMain = @import("../main.zig").lldMain;12const lldMain = @import("../main.zig").lldMain;
13const log = std.log.scoped(.link);
14const mem = std.mem;
21const trace = @import("../tracy.zig").trace;15const trace = @import("../tracy.zig").trace;
22const build_options = @import("build_options");16const types = @import("Wasm/types.zig");
23const wasi_libc = @import("../wasi_libc.zig");17const wasi_libc = @import("../wasi_libc.zig");
24const Cache = std.Build.Cache;18
25const Type = @import("../type.zig").Type;
26const Value = @import("../Value.zig");
27const TypedValue = @import("../TypedValue.zig");
28const LlvmObject = @import("../codegen/llvm.zig").Object;
29const Air = @import("../Air.zig");19const Air = @import("../Air.zig");
20const Allocator = std.mem.Allocator;
21const Archive = @import("Wasm/Archive.zig");
22const Cache = std.Build.Cache;
23const CodeGen = @import("../arch/wasm/CodeGen.zig");
24const Compilation = @import("../Compilation.zig");
25const Dwarf = @import("Dwarf.zig");
26const File = @import("Wasm/file.zig").File;
27const InternPool = @import("../InternPool.zig");
30const Liveness = @import("../Liveness.zig");28const Liveness = @import("../Liveness.zig");
31const Symbol = @import("Wasm/Symbol.zig");29const LlvmObject = @import("../codegen/llvm.zig").Object;
30const Module = @import("../Module.zig");
32const Object = @import("Wasm/Object.zig");31const Object = @import("Wasm/Object.zig");
33const Archive = @import("Wasm/Archive.zig");32const Symbol = @import("Wasm/Symbol.zig");
34const types = @import("Wasm/types.zig");33const Type = @import("../type.zig").Type;
34const TypedValue = @import("../TypedValue.zig");
35const Value = @import("../value.zig").Value;
36const ZigObject = @import("Wasm/ZigObject.zig");
37
38pub const Atom = @import("Wasm/Atom.zig");
35pub const Relocation = types.Relocation;39pub const Relocation = types.Relocation;
3640
37pub const base_tag: link.File.Tag = .wasm;41pub const base_tag: link.File.Tag = .wasm;
...@@ -57,6 +61,11 @@ export_table: bool,...@@ -57,6 +61,11 @@ export_table: bool,
57name: []const u8,61name: []const u8,
58/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.62/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
59llvm_object: ?*LlvmObject = null,63llvm_object: ?*LlvmObject = null,
64/// The file index of a `ZigObject`. This will only contain a valid index when a zcu exists,
65/// and the chosen backend is the Wasm backend.
66zig_object_index: File.Index = .null,
67/// List of relocatable files to be linked into the final binary.
68files: std.MultiArrayList(File.Entry) = .{},
60/// When importing objects from the host environment, a name must be supplied.69/// When importing objects from the host environment, a name must be supplied.
61/// LLVM uses "env" by default when none is given. This would be a good default for Zig70/// LLVM uses "env" by default when none is given. This would be a good default for Zig
62/// to support existing code.71/// to support existing code.
...@@ -556,9 +565,27 @@ pub fn createEmpty(...@@ -556,9 +565,27 @@ pub fn createEmpty(
556 }565 }
557 }566 }
558567
568 if (comp.module) |zcu| {
569 if (!use_llvm) {
570 const index: File.Index = @enumFromInt(wasm.files.len);
571 var zig_object: ZigObject = .{
572 .path = try std.fmt.allocPrint(gpa, "{s}.o", .{std.fs.path.stem(zcu.main_mod.root_src_path)}),
573 .stack_pointer_sym = undefined,
574 };
575 try zig_object.init(wasm);
576 try wasm.files.append(gpa, .{ .zig_object = zig_object });
577 wasm.zig_object_index = index;
578 }
579 }
580
559 return wasm;581 return wasm;
560}582}
561583
584fn zigObjectPtr(wasm: *Wasm) ?*ZigObject {
585 if (wasm.zig_object_index == .null) return null;
586 return &wasm.files.items(.data)[@intFromEnum(wasm.zig_object_index)].zig_object;
587}
588
562/// For a given name, creates a new global synthetic symbol.589/// For a given name, creates a new global synthetic symbol.
563/// Leaves index undefined and the default flags (0).590/// Leaves index undefined and the default flags (0).
564fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !SymbolLoc {591fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !SymbolLoc {
src/link/Wasm/ZigObject.zig+34-9
...@@ -3,6 +3,7 @@...@@ -3,6 +3,7 @@
3//! and any relocations that may have been emitted.3//! and any relocations that may have been emitted.
4//! Think about this as fake in-memory Object file for the Zig module.4//! Think about this as fake in-memory Object file for the Zig module.
55
6path: []const u8,
6/// List of all `Decl` that are currently alive.7/// List of all `Decl` that are currently alive.
7/// Each index maps to the corresponding `Atom.Index`.8/// Each index maps to the corresponding `Atom.Index`.
8decls: std.AutoHashMapUnmanaged(InternPool.DeclIndex, Atom.Index) = .{},9decls: std.AutoHashMapUnmanaged(InternPool.DeclIndex, Atom.Index) = .{},
...@@ -22,7 +23,7 @@ global_syms: std.AutoHashMapUnmanaged(u32, u32) = .{},...@@ -22,7 +23,7 @@ global_syms: std.AutoHashMapUnmanaged(u32, u32) = .{},
22/// List of symbol indexes which are free to be used.23/// List of symbol indexes which are free to be used.
23symbols_free_list: std.ArrayListUnmanaged(u32) = .{},24symbols_free_list: std.ArrayListUnmanaged(u32) = .{},
24/// Extra metadata about the linking section, such as alignment of segments and their name.25/// Extra metadata about the linking section, such as alignment of segments and their name.
25segment_info: std.ArrayListUnmanage(types.Segment) = &.{},26segment_info: std.ArrayListUnmanaged(types.Segment) = .{},
26/// File encapsulated string table, used to deduplicate strings within the generated file.27/// File encapsulated string table, used to deduplicate strings within the generated file.
27string_table: StringTable = .{},28string_table: StringTable = .{},
28/// Map for storing anonymous declarations. Each anonymous decl maps to its Atom's index.29/// Map for storing anonymous declarations. Each anonymous decl maps to its Atom's index.
...@@ -72,6 +73,30 @@ debug_str_index: ?u32 = null,...@@ -72,6 +73,30 @@ debug_str_index: ?u32 = null,
72/// The index of the segment representing the custom '.debug_pubtypes' section.73/// The index of the segment representing the custom '.debug_pubtypes' section.
73debug_abbrev_index: ?u32 = null,74debug_abbrev_index: ?u32 = null,
7475
76/// Initializes the `ZigObject` with initial symbols.
77pub fn init(zig_object: *ZigObject, wasm_file: *Wasm) !void {
78 // Initialize an undefined global with the name __stack_pointer. Codegen will use
79 // this to generate relocations when moving the stack pointer. This symbol will be
80 // resolved automatically by the final linking stage.
81 try zig_object.createStackPointer(wasm_file);
82
83 // TODO: Initialize debug information when we reimplement Dwarf support.
84}
85
86fn createStackPointer(zig_object: *ZigObject, wasm_file: *Wasm) !void {
87 const gpa = wasm_file.base.comp.gpa;
88 const sym_index = try zig_object.getGlobalSymbol(gpa, "__stack_pointer", .global);
89 zig_object.symbols.items[sym_index].index = zig_object.imported_globals_count;
90 const is_wasm32 = wasm_file.base.comp.root_mod.resolved_target.result.cpu.arch == .wasm32;
91 try zig_object.imports.putNoClobber(gpa, sym_index, .{
92 .name = zig_object.symbols.items[sym_index].name,
93 .module_name = try zig_object.string_table.insert(gpa, wasm_file.host_name),
94 .kind = .{ .global = .{ .valtype = if (is_wasm32) .i32 else .i64, .mutable = true } },
95 });
96 zig_object.imported_globals_count += 1;
97 zig_object.stack_pointer_sym = sym_index;
98}
99
75/// Frees and invalidates all memory of the incrementally compiled Zig module.100/// Frees and invalidates all memory of the incrementally compiled Zig module.
76/// It is illegal behavior to access the `ZigObject` after calling `deinit`.101/// It is illegal behavior to access the `ZigObject` after calling `deinit`.
77pub fn deinit(zig_object: *ZigObject, gpa: std.mem.Allocator) void {102pub fn deinit(zig_object: *ZigObject, gpa: std.mem.Allocator) void {
...@@ -113,6 +138,7 @@ pub fn deinit(zig_object: *ZigObject, gpa: std.mem.Allocator) void {...@@ -113,6 +138,7 @@ pub fn deinit(zig_object: *ZigObject, gpa: std.mem.Allocator) void {
113 if (zig_object.dwarf) |*dwarf| {138 if (zig_object.dwarf) |*dwarf| {
114 dwarf.deinit();139 dwarf.deinit();
115 }140 }
141 gpa.free(zig_object.path);
116 zig_object.* = undefined;142 zig_object.* = undefined;
117}143}
118144
...@@ -531,32 +557,31 @@ pub fn addOrUpdateImport(...@@ -531,32 +557,31 @@ pub fn addOrUpdateImport(
531/// such as an exported or imported symbol.557/// such as an exported or imported symbol.
532/// If the symbol does not yet exist, creates a new one symbol instead558/// If the symbol does not yet exist, creates a new one symbol instead
533/// and then returns the index to it.559/// and then returns the index to it.
534pub fn getGlobalSymbol(zig_object: *ZigObject, wasm_file: *Wasm, name: []const u8) !u32 {560pub fn getGlobalSymbol(zig_object: *ZigObject, gpa: std.mem.Allocator, name: []const u8, tag: Symbol.Tag) !u32 {
535 const gpa = wasm_file.base.comp.gpa;
536 const name_index = try zig_object.string_table.insert(gpa, name);561 const name_index = try zig_object.string_table.insert(gpa, name);
537 const gop = try zig_object.global_syms.getOrPut(gpa, name_index);562 const gop = try zig_object.global_syms.getOrPut(gpa, name_index);
538 if (gop.found_existing) {563 if (gop.found_existing) {
539 return gop.value_ptr.index;564 return gop.value_ptr.*;
540 }565 }
541566
542 var symbol: Symbol = .{567 var symbol: Symbol = .{
543 .name = name_index,568 .name = name_index,
544 .flags = 0,569 .flags = 0,
545 .index = undefined, // index to type will be set after merging function symbols570 .index = undefined, // index to type will be set after merging symbols
546 .tag = .function,571 .tag = tag,
547 .virtual_address = undefined,572 .virtual_address = std.math.maxInt(u32),
548 };573 };
549 symbol.setGlobal(true);574 symbol.setGlobal(true);
550 symbol.setUndefined(true);575 symbol.setUndefined(true);
551576
552 const sym_index = if (zig_object.symbol.popOrNull()) |index| index else blk: {577 const sym_index = if (zig_object.symbols_free_list.popOrNull()) |index| index else blk: {
553 const index: u32 = @intCast(zig_object.symbols.items.len);578 const index: u32 = @intCast(zig_object.symbols.items.len);
554 try zig_object.symbols.ensureUnusedCapacity(gpa, 1);579 try zig_object.symbols.ensureUnusedCapacity(gpa, 1);
555 zig_object.symbols.items.len += 1;580 zig_object.symbols.items.len += 1;
556 break :blk index;581 break :blk index;
557 };582 };
558 zig_object.symbols.items[sym_index] = symbol;583 zig_object.symbols.items[sym_index] = symbol;
559 gop.value_ptr.* = .{ .index = sym_index, .file = null };584 gop.value_ptr.* = sym_index;
560 return sym_index;585 return sym_index;
561}586}
562587