authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-12-28 15:44:35-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-15 15:11:36-08:00
loga72e7384aae81d012f017c837df8c16048bdea4e
treece3daf169efab9f124fa86c2870be5eda5b6b50b
parenteb943890d975a50618db8ca7593563fcf8b107da

wasm linker: fix global imports in objects

they need to reference a local index until the object parsing is complete and also need to check mutability and type matching

1 files changed, 85 insertions(+), 16 deletions(-)

src/link/Wasm/Object.zig+85-16
......@@ -75,6 +75,13 @@ pub const FunctionImport = struct {
7575 function_index: ScratchSpace.FuncTypeIndex,
7676};
7777
78pub const GlobalImport = struct {
79 module_name: Wasm.String,
80 name: Wasm.String,
81 valtype: std.wasm.Valtype,
82 mutable: bool,
83};
84
7885pub const DataSegmentFlags = enum(u32) { active, passive, active_memidx };
7986
8087pub const SubsectionType = enum(u8) {
......@@ -105,7 +112,7 @@ pub const Symbol = struct {
105112 data: Wasm.ObjectData.Index,
106113 data_import: void,
107114 global: Wasm.ObjectGlobalIndex,
108 global_import: Wasm.GlobalImport.Index,
115 global_import: ScratchSpace.GlobalImportIndex,
109116 section: Wasm.ObjectSectionIndex,
110117 table: Wasm.ObjectTableIndex,
111118 table_import: Wasm.TableImport.Index,
......@@ -116,6 +123,7 @@ pub const ScratchSpace = struct {
116123 func_types: std.ArrayListUnmanaged(Wasm.FunctionType.Index) = .empty,
117124 func_type_indexes: std.ArrayListUnmanaged(FuncTypeIndex) = .empty,
118125 func_imports: std.ArrayListUnmanaged(FunctionImport) = .empty,
126 global_imports: std.ArrayListUnmanaged(GlobalImport) = .empty,
119127 symbol_table: std.ArrayListUnmanaged(Symbol) = .empty,
120128 segment_info: std.ArrayListUnmanaged(SegmentInfo) = .empty,
121129 exports: std.ArrayListUnmanaged(Export) = .empty,
......@@ -141,6 +149,15 @@ pub const ScratchSpace = struct {
141149 }
142150 };
143151
152 /// Index into `global_imports`.
153 const GlobalImportIndex = enum(u32) {
154 _,
155
156 fn ptr(index: GlobalImportIndex, ss: *const ScratchSpace) *GlobalImport {
157 return &ss.global_imports.items[@intFromEnum(index)];
158 }
159 };
160
144161 /// Index into `func_types`.
145162 const FuncTypeIndex = enum(u32) {
146163 _,
......@@ -155,6 +172,7 @@ pub const ScratchSpace = struct {
155172 ss.func_types.deinit(gpa);
156173 ss.func_type_indexes.deinit(gpa);
157174 ss.func_imports.deinit(gpa);
175 ss.global_imports.deinit(gpa);
158176 ss.symbol_table.deinit(gpa);
159177 ss.segment_info.deinit(gpa);
160178 ss.* = undefined;
......@@ -165,6 +183,7 @@ pub const ScratchSpace = struct {
165183 ss.func_types.clearRetainingCapacity();
166184 ss.func_type_indexes.clearRetainingCapacity();
167185 ss.func_imports.clearRetainingCapacity();
186 ss.global_imports.clearRetainingCapacity();
168187 ss.symbol_table.clearRetainingCapacity();
169188 ss.segment_info.clearRetainingCapacity();
170189 }
......@@ -361,7 +380,7 @@ pub fn parse(
361380 symbol.name = function_import.ptr(ss).name.toOptional();
362381 }
363382 } else {
364 symbol.pointee = .{ .function = @enumFromInt(functions_start + local_index) };
383 symbol.pointee = .{ .function = @enumFromInt(functions_start + (local_index - ss.func_imports.items.len)) };
365384 const name, pos = readBytes(bytes, pos);
366385 symbol.name = (try wasm.internString(name)).toOptional();
367386 }
......@@ -369,16 +388,16 @@ pub fn parse(
369388 .global => {
370389 const local_index, pos = readLeb(u32, bytes, pos);
371390 if (symbol.flags.undefined) {
372 const global_import: Wasm.GlobalImport.Index = @enumFromInt(global_imports_start + local_index);
391 const global_import: ScratchSpace.GlobalImportIndex = @enumFromInt(local_index);
373392 symbol.pointee = .{ .global_import = global_import };
374393 if (symbol.flags.explicit_name) {
375394 const name, pos = readBytes(bytes, pos);
376395 symbol.name = (try wasm.internString(name)).toOptional();
377396 } else {
378 symbol.name = global_import.key(wasm).toOptional();
397 symbol.name = global_import.ptr(ss).name.toOptional();
379398 }
380399 } else {
381 symbol.pointee = .{ .global = @enumFromInt(globals_start + local_index) };
400 symbol.pointee = .{ .global = @enumFromInt(globals_start + (local_index - ss.global_imports.items.len)) };
382401 const name, pos = readBytes(bytes, pos);
383402 symbol.name = (try wasm.internString(name)).toOptional();
384403 }
......@@ -579,16 +598,11 @@ pub fn parse(
579598 const valtype, pos = readEnum(std.wasm.Valtype, bytes, pos);
580599 const mutable = bytes[pos] == 0x01;
581600 pos += 1;
582 try wasm.object_global_imports.put(gpa, interned_name, .{
583 .flags = .{
584 .global_type = .{
585 .valtype = .from(valtype),
586 .mutable = mutable,
587 },
588 },
589 .module_name = interned_module_name.toOptional(),
590 .source_location = source_location,
591 .resolution = .unresolved,
601 try ss.global_imports.append(gpa, .{
602 .name = interned_name,
603 .valtype = valtype,
604 .mutable = mutable,
605 .module_name = interned_module_name,
592606 });
593607 },
594608 .table => {
......@@ -840,6 +854,61 @@ pub fn parse(
840854 };
841855 }
842856 },
857 .global_import => |index| {
858 const ptr = index.ptr(ss);
859 const name = symbol.name.unwrap().?;
860 if (symbol.flags.binding == .local) {
861 diags.addParseError(path, "local symbol '{s}' references import", .{name.slice(wasm)});
862 continue;
863 }
864 const gop = try wasm.object_global_imports.getOrPut(gpa, name);
865 if (gop.found_existing) {
866 const existing_ty = gop.value_ptr.flags.global_type.to();
867 if (ptr.valtype != existing_ty.valtype) {
868 var err = try diags.addErrorWithNotes(2);
869 try err.addMsg("symbol '{s}' mismatching global types", .{name.slice(wasm)});
870 gop.value_ptr.source_location.addNote(wasm, &err, "type {s} here", .{@tagName(existing_ty.valtype)});
871 source_location.addNote(wasm, &err, "type {s} here", .{@tagName(ptr.valtype)});
872 continue;
873 }
874 if (ptr.mutable != existing_ty.mutable) {
875 var err = try diags.addErrorWithNotes(2);
876 try err.addMsg("symbol '{s}' mismatching global mutability", .{name.slice(wasm)});
877 gop.value_ptr.source_location.addNote(wasm, &err, "{s} here", .{
878 if (existing_ty.mutable) "mutable" else "not mutable",
879 });
880 source_location.addNote(wasm, &err, "{s} here", .{
881 if (ptr.mutable) "mutable" else "not mutable",
882 });
883 continue;
884 }
885 if (gop.value_ptr.module_name != ptr.module_name.toOptional()) {
886 var err = try diags.addErrorWithNotes(2);
887 try err.addMsg("function symbol '{s}' mismatching module names", .{name.slice(wasm)});
888 if (gop.value_ptr.module_name.slice(wasm)) |module_name| {
889 gop.value_ptr.source_location.addNote(wasm, &err, "module '{s}' here", .{module_name});
890 } else {
891 gop.value_ptr.source_location.addNote(wasm, &err, "no module here", .{});
892 }
893 source_location.addNote(wasm, &err, "module '{s}' here", .{ptr.module_name.slice(wasm)});
894 continue;
895 }
896 if (symbol.flags.binding == .strong) gop.value_ptr.flags.binding = .strong;
897 if (!symbol.flags.visibility_hidden) gop.value_ptr.flags.visibility_hidden = false;
898 if (symbol.flags.no_strip) gop.value_ptr.flags.no_strip = true;
899 } else {
900 gop.value_ptr.* = .{
901 .flags = symbol.flags,
902 .module_name = ptr.module_name.toOptional(),
903 .source_location = source_location,
904 .resolution = .unresolved,
905 };
906 gop.value_ptr.flags.global_type = .{
907 .valtype = .from(ptr.valtype),
908 .mutable = ptr.mutable,
909 };
910 }
911 },
843912 .function => |index| {
844913 assert(!symbol.flags.undefined);
845914 const ptr = index.ptr(wasm);
......@@ -882,7 +951,7 @@ pub fn parse(
882951 }
883952 },
884953
885 inline .global_import, .table_import => |i| {
954 .table_import => |i| {
886955 const ptr = i.value(wasm);
887956 assert(i.key(wasm).toOptional() == symbol.name); // TODO
888957 ptr.flags = symbol.flags;