authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2024-01-31 17:21:32+01:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2024-02-29 15:23:04+01:00
log5a0f2af7e4aa01f861d86bfe9fb457ffde3d335e
tree4b6beeb03bc5ab32c3edb77cfeb7fdb98f023755
parentc153f94c892fc3b718d29ba4ae3234e99d4baba4
signaturelock-open Commit is signed but in an unrecognized format.

wasm: reimplement Zig errors in linker


2 files changed, 37 insertions(+), 73 deletions(-)

src/link/Wasm.zig+6-9
...@@ -1333,13 +1333,6 @@ fn resolveLazySymbols(wasm: *Wasm) !void {...@@ -1333,13 +1333,6 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
1333 }1333 }
1334 }1334 }
1335 }1335 }
1336 if (wasm.string_table.getOffset("__zig_errors_len")) |name_offset| {
1337 if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| {
1338 const loc = try wasm.createSyntheticSymbolOffset(name_offset, .data);
1339 try wasm.discarded.putNoClobber(gpa, kv.value, loc);
1340 _ = wasm.resolved_symbols.swapRemove(kv.value);
1341 }
1342 }
1343}1336}
13441337
1345// Tries to find a global symbol by its name. Returns null when not found,1338// Tries to find a global symbol by its name. Returns null when not found,
...@@ -2009,8 +2002,7 @@ fn mergeSections(wasm: *Wasm) !void {...@@ -2009,8 +2002,7 @@ fn mergeSections(wasm: *Wasm) !void {
20092002
2010 for (wasm.resolved_symbols.keys()) |sym_loc| {2003 for (wasm.resolved_symbols.keys()) |sym_loc| {
2011 const obj_file = wasm.file(sym_loc.file) orelse {2004 const obj_file = wasm.file(sym_loc.file) orelse {
2012 // Zig code-generated symbols are already within the sections and do not2005 // Synthetic symbols already live in the corresponding sections.
2013 // require to be merged
2014 continue;2006 continue;
2015 };2007 };
20162008
...@@ -2056,6 +2048,7 @@ fn mergeSections(wasm: *Wasm) !void {...@@ -2056,6 +2048,7 @@ fn mergeSections(wasm: *Wasm) !void {
2056 symbol.index = @as(u32, @intCast(wasm.tables.items.len)) + wasm.imported_tables_count;2048 symbol.index = @as(u32, @intCast(wasm.tables.items.len)) + wasm.imported_tables_count;
2057 try wasm.tables.append(gpa, original_table);2049 try wasm.tables.append(gpa, original_table);
2058 },2050 },
2051 .dead, .undefined => unreachable,
2059 else => {},2052 else => {},
2060 }2053 }
2061 }2054 }
...@@ -2719,6 +2712,10 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node)...@@ -2719,6 +2712,10 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node)
2719 sub_prog_node.activate();2712 sub_prog_node.activate();
2720 defer sub_prog_node.end();2713 defer sub_prog_node.end();
27212714
2715 if (wasm.zigObjectPtr()) |zig_object| {
2716 try zig_object.flushModule(wasm);
2717 }
2718
2722 // ensure the error names table is populated when an error name is referenced2719 // ensure the error names table is populated when an error name is referenced
2723 // try wasm.populateErrorNameTable();2720 // try wasm.populateErrorNameTable();
27242721
src/link/Wasm/ZigObject.zig+31-64
...@@ -551,16 +551,15 @@ pub fn getErrorTableSymbol(zig_object: *ZigObject, wasm_file: *Wasm) !u32 {...@@ -551,16 +551,15 @@ pub fn getErrorTableSymbol(zig_object: *ZigObject, wasm_file: *Wasm) !u32 {
551 atom.alignment = slice_ty.abiAlignment(mod);551 atom.alignment = slice_ty.abiAlignment(mod);
552552
553 const sym_name = try zig_object.string_table.insert(gpa, "__zig_err_name_table");553 const sym_name = try zig_object.string_table.insert(gpa, "__zig_err_name_table");
554 const segment_name = try gpa.dupe(u8, ".rodata.__zig_err_name_table");
554 const sym = zig_object.symbol(sym_index);555 const sym = zig_object.symbol(sym_index);
555 sym.* = .{556 sym.* = .{
556 .name = sym_name,557 .name = sym_name,
557 .tag = .data,558 .tag = .data,
558 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),559 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
559 .index = 0,560 .index = try zig_object.createDataSegment(gpa, segment_name, atom.alignment),
560 .virtual_address = undefined,561 .virtual_address = undefined,
561 };562 };
562 // TODO: can we remove this?
563 // sym.mark();
564563
565 log.debug("Error name table was created with symbol index: ({d})", .{sym_index});564 log.debug("Error name table was created with symbol index: ({d})", .{sym_index});
566 zig_object.error_table_symbol = sym_index;565 zig_object.error_table_symbol = sym_index;
...@@ -584,15 +583,15 @@ fn populateErrorNameTable(zig_object: *ZigObject, wasm_file: *Wasm) !void {...@@ -584,15 +583,15 @@ fn populateErrorNameTable(zig_object: *ZigObject, wasm_file: *Wasm) !void {
584 const names_atom = wasm_file.getAtomPtr(names_atom_index);583 const names_atom = wasm_file.getAtomPtr(names_atom_index);
585 names_atom.alignment = .@"1";584 names_atom.alignment = .@"1";
586 const sym_name = try zig_object.string_table.insert(gpa, "__zig_err_names");585 const sym_name = try zig_object.string_table.insert(gpa, "__zig_err_names");
586 const segment_name = try gpa.dupe(u8, ".rodata.__zig_err_names");
587 const names_symbol = &zig_object.symbols.items[names_sym_index];587 const names_symbol = &zig_object.symbols.items[names_sym_index];
588 names_symbol.* = .{588 names_symbol.* = .{
589 .name = sym_name,589 .name = sym_name,
590 .tag = .data,590 .tag = .data,
591 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),591 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
592 .index = 0,592 .index = try zig_object.createDataSegment(gpa, segment_name, names_atom.alignment),
593 .virtual_address = undefined,593 .virtual_address = undefined,
594 };594 };
595 names_symbol.mark();
596595
597 log.debug("Populating error names", .{});596 log.debug("Populating error names", .{});
598597
...@@ -628,11 +627,6 @@ fn populateErrorNameTable(zig_object: *ZigObject, wasm_file: *Wasm) !void {...@@ -628,11 +627,6 @@ fn populateErrorNameTable(zig_object: *ZigObject, wasm_file: *Wasm) !void {
628 log.debug("Populated error name: '{s}'", .{error_name});627 log.debug("Populated error name: '{s}'", .{error_name});
629 }628 }
630 names_atom.size = addend;629 names_atom.size = addend;
631
632 // link the atoms with the rest of the binary so they can be allocated
633 // and relocations will be performed.
634 try wasm_file.parseAtom(atom_index, .{ .data = .read_only });
635 try wasm_file.parseAtom(names_atom_index, .{ .data = .read_only });
636}630}
637631
638/// Either creates a new import, or updates one if existing.632/// Either creates a new import, or updates one if existing.
...@@ -995,76 +989,44 @@ pub fn putOrGetFuncType(zig_object: *ZigObject, gpa: std.mem.Allocator, func_typ...@@ -995,76 +989,44 @@ pub fn putOrGetFuncType(zig_object: *ZigObject, gpa: std.mem.Allocator, func_typ
995 return index;989 return index;
996}990}
997991
998/// Kind represents the type of an Atom, which is only
999/// used to parse a decl into an Atom to define in which section
1000/// or segment it should be placed.
1001const Kind = union(enum) {
1002 /// Represents the segment the data symbol should
1003 /// be inserted into.
1004 /// TODO: Add TLS segments
1005 data: enum {
1006 read_only,
1007 uninitialized,
1008 initialized,
1009 },
1010 function: void,
1011
1012 /// Returns the segment name the data kind represents.
1013 /// Asserts `kind` has its active tag set to `data`.
1014 fn segmentName(kind: Kind) []const u8 {
1015 switch (kind.data) {
1016 .read_only => return ".rodata.",
1017 .uninitialized => return ".bss.",
1018 .initialized => return ".data.",
1019 }
1020 }
1021};
1022
1023/// Parses an Atom and inserts its metadata into the corresponding sections.
1024pub fn parseAtom(zig_object: *ZigObject, wasm_file: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
1025 // TODO: Revisit
1026 _ = zig_object;
1027 _ = wasm_file;
1028 _ = atom_index;
1029 _ = kind;
1030}
1031
1032/// Generates an atom containing the global error set' size.992/// Generates an atom containing the global error set' size.
1033/// This will only be generated if the symbol exists.993/// This will only be generated if the symbol exists.
1034fn setupErrorsLen(zig_object: *ZigObject, wasm_file: *Wasm) !void {994fn setupErrorsLen(zig_object: *ZigObject, wasm_file: *Wasm) !void {
1035 const gpa = wasm_file.base.comp.gpa;995 const gpa = wasm_file.base.comp.gpa;
1036 const loc = zig_object.findGlobalSymbol("__zig_errors_len") orelse return;996 const sym_index = zig_object.findGlobalSymbol("__zig_errors_len") orelse return;
1037997
1038 const errors_len = wasm_file.base.comp.module.?.global_error_set.count();998 const errors_len = wasm_file.base.comp.module.?.global_error_set.count();
1039 // overwrite existing atom if it already exists (maybe the error set has increased)999 // overwrite existing atom if it already exists (maybe the error set has increased)
1040 // if not, allcoate a new atom.1000 // if not, allcoate a new atom.
1041 const atom_index = if (wasm_file.symbol_atom.get(loc)) |index| blk: {1001 const atom_index = if (wasm_file.symbol_atom.get(.{ .file = zig_object.index, .index = sym_index })) |index| blk: {
1042 const atom = wasm_file.getAtomPtr(index);1002 const atom = wasm_file.getAtomPtr(index);
1043 if (atom.next) |next_atom_index| {1003 atom.prev = null;
1044 const next_atom = wasm_file.getAtomPtr(next_atom_index);
1045 next_atom.prev = atom.prev;
1046 atom.next = null;
1047 }
1048 if (atom.prev) |prev_index| {
1049 const prev_atom = wasm_file.getAtomPtr(prev_index);
1050 prev_atom.next = atom.next;
1051 atom.prev = null;
1052 }
1053 atom.deinit(gpa);1004 atom.deinit(gpa);
1054 break :blk index;1005 break :blk index;
1055 } else new_atom: {1006 } else idx: {
1056 const atom_index: Atom.Index = @intCast(wasm_file.managed_atoms.items.len);1007 // We found a call to __zig_errors_len so make the symbol a local symbol
1057 try wasm_file.symbol_atom.put(gpa, loc, atom_index);1008 // and define it, so the final binary or resulting object file will not attempt
1058 try wasm_file.managed_atoms.append(gpa, undefined);1009 // to resolve it.
1059 break :new_atom atom_index;1010 const sym = zig_object.symbol(sym_index);
1011 sym.setGlobal(false);
1012 sym.setUndefined(false);
1013 sym.tag = .data;
1014 const segment_name = try gpa.dupe(u8, ".rodata.__zig_errors_len");
1015 sym.index = try zig_object.createDataSegment(gpa, segment_name, .@"2");
1016 break :idx try wasm_file.createAtom(sym_index, zig_object.index);
1060 };1017 };
1018
1061 const atom = wasm_file.getAtomPtr(atom_index);1019 const atom = wasm_file.getAtomPtr(atom_index);
1062 atom.* = Atom.empty;1020 atom.code.clearRetainingCapacity();
1063 atom.sym_index = loc.index;1021 atom.sym_index = sym_index;
1064 atom.size = 2;1022 atom.size = 2;
1023 atom.alignment = .@"2";
1065 try atom.code.writer(gpa).writeInt(u16, @intCast(errors_len), .little);1024 try atom.code.writer(gpa).writeInt(u16, @intCast(errors_len), .little);
1025}
10661026
1067 // try wasm.parseAtom(atom_index, .{ .data = .read_only });1027fn findGlobalSymbol(zig_object: *ZigObject, name: []const u8) ?u32 {
1028 const offset = zig_object.string_table.getOffset(name) orelse return null;
1029 return zig_object.global_syms.get(offset);
1068}1030}
10691031
1070/// Initializes symbols and atoms for the debug sections1032/// Initializes symbols and atoms for the debug sections
...@@ -1232,6 +1194,11 @@ fn appendFunction(zig_object: *ZigObject, gpa: std.mem.Allocator, func: std.wasm...@@ -1232,6 +1194,11 @@ fn appendFunction(zig_object: *ZigObject, gpa: std.mem.Allocator, func: std.wasm
1232 return index;1194 return index;
1233}1195}
12341196
1197pub fn flushModule(zig_object: *ZigObject, wasm_file: *Wasm) !void {
1198 try zig_object.populateErrorNameTable(wasm_file);
1199 try zig_object.setupErrorsLen(wasm_file);
1200}
1201
1235const build_options = @import("build_options");1202const build_options = @import("build_options");
1236const builtin = @import("builtin");1203const builtin = @import("builtin");
1237const codegen = @import("../../codegen.zig");1204const codegen = @import("../../codegen.zig");