authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-12-23 18:18:54-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-15 15:11:36-08:00
log1a4c5837fedcad57f6c81301672e6246e0f0a8c1
tree97b7b1b10d130d96cb93d7b28c88ad00971e0e1d
parent4b9dc2922ff0c5d873971f6f6f25db709df21cc0

wasm linker: fix crashes when parsing compiler_rt


10 files changed, 514 insertions(+), 369 deletions(-)

src/link.zig+3-6
...@@ -97,15 +97,12 @@ pub const Diags = struct {...@@ -97,15 +97,12 @@ pub const Diags = struct {
97 err_msg.msg = try std.fmt.allocPrint(gpa, format, args);97 err_msg.msg = try std.fmt.allocPrint(gpa, format, args);
98 }98 }
9999
100 pub fn addNote(100 pub fn addNote(err: *ErrorWithNotes, comptime format: []const u8, args: anytype) void {
101 err: *ErrorWithNotes,
102 comptime format: []const u8,
103 args: anytype,
104 ) error{OutOfMemory}!void {
105 const gpa = err.diags.gpa;101 const gpa = err.diags.gpa;
102 const msg = std.fmt.allocPrint(gpa, format, args) catch return err.diags.setAllocFailure();
106 const err_msg = &err.diags.msgs.items[err.index];103 const err_msg = &err.diags.msgs.items[err.index];
107 assert(err.note_slot < err_msg.notes.len);104 assert(err.note_slot < err_msg.notes.len);
108 err_msg.notes[err.note_slot] = .{ .msg = try std.fmt.allocPrint(gpa, format, args) };105 err_msg.notes[err.note_slot] = .{ .msg = msg };
109 err.note_slot += 1;106 err.note_slot += 1;
110 }107 }
111 };108 };
src/link/Elf.zig+7-7
...@@ -3394,7 +3394,7 @@ fn allocatePhdrTable(self: *Elf) error{OutOfMemory}!void {...@@ -3394,7 +3394,7 @@ fn allocatePhdrTable(self: *Elf) error{OutOfMemory}!void {
3394 // TODO verify `getMaxNumberOfPhdrs()` is accurate and convert this into no-op3394 // TODO verify `getMaxNumberOfPhdrs()` is accurate and convert this into no-op
3395 var err = try diags.addErrorWithNotes(1);3395 var err = try diags.addErrorWithNotes(1);
3396 try err.addMsg("fatal linker error: not enough space reserved for EHDR and PHDR table", .{});3396 try err.addMsg("fatal linker error: not enough space reserved for EHDR and PHDR table", .{});
3397 try err.addNote("required 0x{x}, available 0x{x}", .{ needed_size, available_space });3397 err.addNote("required 0x{x}, available 0x{x}", .{ needed_size, available_space });
3398 }3398 }
33993399
3400 phdr_table_load.p_filesz = needed_size + ehsize;3400 phdr_table_load.p_filesz = needed_size + ehsize;
...@@ -4545,12 +4545,12 @@ fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void {...@@ -4545,12 +4545,12 @@ fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void {
4545 for (refs.items[0..nrefs]) |ref| {4545 for (refs.items[0..nrefs]) |ref| {
4546 const atom_ptr = self.atom(ref).?;4546 const atom_ptr = self.atom(ref).?;
4547 const file_ptr = atom_ptr.file(self).?;4547 const file_ptr = atom_ptr.file(self).?;
4548 try err.addNote("referenced by {s}:{s}", .{ file_ptr.fmtPath(), atom_ptr.name(self) });4548 err.addNote("referenced by {s}:{s}", .{ file_ptr.fmtPath(), atom_ptr.name(self) });
4549 }4549 }
45504550
4551 if (refs.items.len > max_notes) {4551 if (refs.items.len > max_notes) {
4552 const remaining = refs.items.len - max_notes;4552 const remaining = refs.items.len - max_notes;
4553 try err.addNote("referenced {d} more times", .{remaining});4553 err.addNote("referenced {d} more times", .{remaining});
4554 }4554 }
4555 }4555 }
4556}4556}
...@@ -4567,17 +4567,17 @@ fn reportDuplicates(self: *Elf, dupes: anytype) error{ HasDuplicates, OutOfMemor...@@ -4567,17 +4567,17 @@ fn reportDuplicates(self: *Elf, dupes: anytype) error{ HasDuplicates, OutOfMemor
45674567
4568 var err = try diags.addErrorWithNotes(nnotes + 1);4568 var err = try diags.addErrorWithNotes(nnotes + 1);
4569 try err.addMsg("duplicate symbol definition: {s}", .{sym.name(self)});4569 try err.addMsg("duplicate symbol definition: {s}", .{sym.name(self)});
4570 try err.addNote("defined by {}", .{sym.file(self).?.fmtPath()});4570 err.addNote("defined by {}", .{sym.file(self).?.fmtPath()});
45714571
4572 var inote: usize = 0;4572 var inote: usize = 0;
4573 while (inote < @min(notes.items.len, max_notes)) : (inote += 1) {4573 while (inote < @min(notes.items.len, max_notes)) : (inote += 1) {
4574 const file_ptr = self.file(notes.items[inote]).?;4574 const file_ptr = self.file(notes.items[inote]).?;
4575 try err.addNote("defined by {}", .{file_ptr.fmtPath()});4575 err.addNote("defined by {}", .{file_ptr.fmtPath()});
4576 }4576 }
45774577
4578 if (notes.items.len > max_notes) {4578 if (notes.items.len > max_notes) {
4579 const remaining = notes.items.len - max_notes;4579 const remaining = notes.items.len - max_notes;
4580 try err.addNote("defined {d} more times", .{remaining});4580 err.addNote("defined {d} more times", .{remaining});
4581 }4581 }
4582 }4582 }
45834583
...@@ -4601,7 +4601,7 @@ pub fn addFileError(...@@ -4601,7 +4601,7 @@ pub fn addFileError(
4601 const diags = &self.base.comp.link_diags;4601 const diags = &self.base.comp.link_diags;
4602 var err = try diags.addErrorWithNotes(1);4602 var err = try diags.addErrorWithNotes(1);
4603 try err.addMsg(format, args);4603 try err.addMsg(format, args);
4604 try err.addNote("while parsing {}", .{self.file(file_index).?.fmtPath()});4604 err.addNote("while parsing {}", .{self.file(file_index).?.fmtPath()});
4605}4605}
46064606
4607pub fn failFile(4607pub fn failFile(
src/link/Elf/Atom.zig+12-12
...@@ -523,7 +523,7 @@ fn reportUnhandledRelocError(self: Atom, rel: elf.Elf64_Rela, elf_file: *Elf) Re...@@ -523,7 +523,7 @@ fn reportUnhandledRelocError(self: Atom, rel: elf.Elf64_Rela, elf_file: *Elf) Re
523 relocation.fmtRelocType(rel.r_type(), elf_file.getTarget().cpu.arch),523 relocation.fmtRelocType(rel.r_type(), elf_file.getTarget().cpu.arch),
524 rel.r_offset,524 rel.r_offset,
525 });525 });
526 try err.addNote("in {}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) });526 err.addNote("in {}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) });
527 return error.RelocFailure;527 return error.RelocFailure;
528}528}
529529
...@@ -539,7 +539,7 @@ fn reportTextRelocError(...@@ -539,7 +539,7 @@ fn reportTextRelocError(
539 rel.r_offset,539 rel.r_offset,
540 symbol.name(elf_file),540 symbol.name(elf_file),
541 });541 });
542 try err.addNote("in {}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) });542 err.addNote("in {}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) });
543 return error.RelocFailure;543 return error.RelocFailure;
544}544}
545545
...@@ -555,8 +555,8 @@ fn reportPicError(...@@ -555,8 +555,8 @@ fn reportPicError(
555 rel.r_offset,555 rel.r_offset,
556 symbol.name(elf_file),556 symbol.name(elf_file),
557 });557 });
558 try err.addNote("in {}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) });558 err.addNote("in {}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) });
559 try err.addNote("recompile with -fPIC", .{});559 err.addNote("recompile with -fPIC", .{});
560 return error.RelocFailure;560 return error.RelocFailure;
561}561}
562562
...@@ -572,8 +572,8 @@ fn reportNoPicError(...@@ -572,8 +572,8 @@ fn reportNoPicError(
572 rel.r_offset,572 rel.r_offset,
573 symbol.name(elf_file),573 symbol.name(elf_file),
574 });574 });
575 try err.addNote("in {}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) });575 err.addNote("in {}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) });
576 try err.addNote("recompile with -fno-PIC", .{});576 err.addNote("recompile with -fno-PIC", .{});
577 return error.RelocFailure;577 return error.RelocFailure;
578}578}
579579
...@@ -1187,7 +1187,7 @@ const x86_64 = struct {...@@ -1187,7 +1187,7 @@ const x86_64 = struct {
1187 x86_64.relaxGotPcTlsDesc(code[r_offset - 3 ..]) catch {1187 x86_64.relaxGotPcTlsDesc(code[r_offset - 3 ..]) catch {
1188 var err = try diags.addErrorWithNotes(1);1188 var err = try diags.addErrorWithNotes(1);
1189 try err.addMsg("could not relax {s}", .{@tagName(r_type)});1189 try err.addMsg("could not relax {s}", .{@tagName(r_type)});
1190 try err.addNote("in {}:{s} at offset 0x{x}", .{1190 err.addNote("in {}:{s} at offset 0x{x}", .{
1191 atom.file(elf_file).?.fmtPath(),1191 atom.file(elf_file).?.fmtPath(),
1192 atom.name(elf_file),1192 atom.name(elf_file),
1193 rel.r_offset,1193 rel.r_offset,
...@@ -1332,7 +1332,7 @@ const x86_64 = struct {...@@ -1332,7 +1332,7 @@ const x86_64 = struct {
1332 relocation.fmtRelocType(rels[0].r_type(), .x86_64),1332 relocation.fmtRelocType(rels[0].r_type(), .x86_64),
1333 relocation.fmtRelocType(rels[1].r_type(), .x86_64),1333 relocation.fmtRelocType(rels[1].r_type(), .x86_64),
1334 });1334 });
1335 try err.addNote("in {}:{s} at offset 0x{x}", .{1335 err.addNote("in {}:{s} at offset 0x{x}", .{
1336 self.file(elf_file).?.fmtPath(),1336 self.file(elf_file).?.fmtPath(),
1337 self.name(elf_file),1337 self.name(elf_file),
1338 rels[0].r_offset,1338 rels[0].r_offset,
...@@ -1388,7 +1388,7 @@ const x86_64 = struct {...@@ -1388,7 +1388,7 @@ const x86_64 = struct {
1388 relocation.fmtRelocType(rels[0].r_type(), .x86_64),1388 relocation.fmtRelocType(rels[0].r_type(), .x86_64),
1389 relocation.fmtRelocType(rels[1].r_type(), .x86_64),1389 relocation.fmtRelocType(rels[1].r_type(), .x86_64),
1390 });1390 });
1391 try err.addNote("in {}:{s} at offset 0x{x}", .{1391 err.addNote("in {}:{s} at offset 0x{x}", .{
1392 self.file(elf_file).?.fmtPath(),1392 self.file(elf_file).?.fmtPath(),
1393 self.name(elf_file),1393 self.name(elf_file),
1394 rels[0].r_offset,1394 rels[0].r_offset,
...@@ -1485,7 +1485,7 @@ const x86_64 = struct {...@@ -1485,7 +1485,7 @@ const x86_64 = struct {
1485 relocation.fmtRelocType(rels[0].r_type(), .x86_64),1485 relocation.fmtRelocType(rels[0].r_type(), .x86_64),
1486 relocation.fmtRelocType(rels[1].r_type(), .x86_64),1486 relocation.fmtRelocType(rels[1].r_type(), .x86_64),
1487 });1487 });
1488 try err.addNote("in {}:{s} at offset 0x{x}", .{1488 err.addNote("in {}:{s} at offset 0x{x}", .{
1489 self.file(elf_file).?.fmtPath(),1489 self.file(elf_file).?.fmtPath(),
1490 self.name(elf_file),1490 self.name(elf_file),
1491 rels[0].r_offset,1491 rels[0].r_offset,
...@@ -1672,7 +1672,7 @@ const aarch64 = struct {...@@ -1672,7 +1672,7 @@ const aarch64 = struct {
1672 // TODO: relax1672 // TODO: relax
1673 var err = try diags.addErrorWithNotes(1);1673 var err = try diags.addErrorWithNotes(1);
1674 try err.addMsg("TODO: relax ADR_GOT_PAGE", .{});1674 try err.addMsg("TODO: relax ADR_GOT_PAGE", .{});
1675 try err.addNote("in {}:{s} at offset 0x{x}", .{1675 err.addNote("in {}:{s} at offset 0x{x}", .{
1676 atom.file(elf_file).?.fmtPath(),1676 atom.file(elf_file).?.fmtPath(),
1677 atom.name(elf_file),1677 atom.name(elf_file),
1678 r_offset,1678 r_offset,
...@@ -1959,7 +1959,7 @@ const riscv = struct {...@@ -1959,7 +1959,7 @@ const riscv = struct {
1959 // TODO: implement searching forward1959 // TODO: implement searching forward
1960 var err = try diags.addErrorWithNotes(1);1960 var err = try diags.addErrorWithNotes(1);
1961 try err.addMsg("TODO: find HI20 paired reloc scanning forward", .{});1961 try err.addMsg("TODO: find HI20 paired reloc scanning forward", .{});
1962 try err.addNote("in {}:{s} at offset 0x{x}", .{1962 err.addNote("in {}:{s} at offset 0x{x}", .{
1963 atom.file(elf_file).?.fmtPath(),1963 atom.file(elf_file).?.fmtPath(),
1964 atom.name(elf_file),1964 atom.name(elf_file),
1965 rel.r_offset,1965 rel.r_offset,
src/link/Elf/Object.zig+5-5
...@@ -797,7 +797,7 @@ pub fn initInputMergeSections(self: *Object, elf_file: *Elf) !void {...@@ -797,7 +797,7 @@ pub fn initInputMergeSections(self: *Object, elf_file: *Elf) !void {
797 if (!isNull(data[end .. end + sh_entsize])) {797 if (!isNull(data[end .. end + sh_entsize])) {
798 var err = try diags.addErrorWithNotes(1);798 var err = try diags.addErrorWithNotes(1);
799 try err.addMsg("string not null terminated", .{});799 try err.addMsg("string not null terminated", .{});
800 try err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });800 err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });
801 return error.LinkFailure;801 return error.LinkFailure;
802 }802 }
803 end += sh_entsize;803 end += sh_entsize;
...@@ -812,7 +812,7 @@ pub fn initInputMergeSections(self: *Object, elf_file: *Elf) !void {...@@ -812,7 +812,7 @@ pub fn initInputMergeSections(self: *Object, elf_file: *Elf) !void {
812 if (shdr.sh_size % sh_entsize != 0) {812 if (shdr.sh_size % sh_entsize != 0) {
813 var err = try diags.addErrorWithNotes(1);813 var err = try diags.addErrorWithNotes(1);
814 try err.addMsg("size not a multiple of sh_entsize", .{});814 try err.addMsg("size not a multiple of sh_entsize", .{});
815 try err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });815 err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });
816 return error.LinkFailure;816 return error.LinkFailure;
817 }817 }
818818
...@@ -889,8 +889,8 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) error{...@@ -889,8 +889,8 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) error{
889 const res = imsec.findSubsection(@intCast(esym.st_value)) orelse {889 const res = imsec.findSubsection(@intCast(esym.st_value)) orelse {
890 var err = try diags.addErrorWithNotes(2);890 var err = try diags.addErrorWithNotes(2);
891 try err.addMsg("invalid symbol value: {x}", .{esym.st_value});891 try err.addMsg("invalid symbol value: {x}", .{esym.st_value});
892 try err.addNote("for symbol {s}", .{sym.name(elf_file)});892 err.addNote("for symbol {s}", .{sym.name(elf_file)});
893 try err.addNote("in {}", .{self.fmtPath()});893 err.addNote("in {}", .{self.fmtPath()});
894 return error.LinkFailure;894 return error.LinkFailure;
895 };895 };
896896
...@@ -915,7 +915,7 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) error{...@@ -915,7 +915,7 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) error{
915 const res = imsec.findSubsection(@intCast(@as(i64, @intCast(esym.st_value)) + rel.r_addend)) orelse {915 const res = imsec.findSubsection(@intCast(@as(i64, @intCast(esym.st_value)) + rel.r_addend)) orelse {
916 var err = try diags.addErrorWithNotes(1);916 var err = try diags.addErrorWithNotes(1);
917 try err.addMsg("invalid relocation at offset 0x{x}", .{rel.r_offset});917 try err.addMsg("invalid relocation at offset 0x{x}", .{rel.r_offset});
918 try err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });918 err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });
919 return error.LinkFailure;919 return error.LinkFailure;
920 };920 };
921921
src/link/Elf/eh_frame.zig+1-1
...@@ -611,7 +611,7 @@ fn reportInvalidReloc(rec: anytype, elf_file: *Elf, rel: elf.Elf64_Rela) !void {...@@ -611,7 +611,7 @@ fn reportInvalidReloc(rec: anytype, elf_file: *Elf, rel: elf.Elf64_Rela) !void {
611 relocation.fmtRelocType(rel.r_type(), elf_file.getTarget().cpu.arch),611 relocation.fmtRelocType(rel.r_type(), elf_file.getTarget().cpu.arch),
612 rel.r_offset,612 rel.r_offset,
613 });613 });
614 try err.addNote("in {}:.eh_frame", .{elf_file.file(rec.file_index).?.fmtPath()});614 err.addNote("in {}:.eh_frame", .{elf_file.file(rec.file_index).?.fmtPath()});
615 return error.RelocFailure;615 return error.RelocFailure;
616}616}
617617
src/link/MachO.zig+16-16
...@@ -1572,21 +1572,21 @@ fn reportUndefs(self: *MachO) !void {...@@ -1572,21 +1572,21 @@ fn reportUndefs(self: *MachO) !void {
1572 try err.addMsg("undefined symbol: {s}", .{undef_sym.getName(self)});1572 try err.addMsg("undefined symbol: {s}", .{undef_sym.getName(self)});
15731573
1574 switch (notes) {1574 switch (notes) {
1575 .force_undefined => try err.addNote("referenced with linker flag -u", .{}),1575 .force_undefined => err.addNote("referenced with linker flag -u", .{}),
1576 .entry => try err.addNote("referenced with linker flag -e", .{}),1576 .entry => err.addNote("referenced with linker flag -e", .{}),
1577 .dyld_stub_binder, .objc_msgsend => try err.addNote("referenced implicitly", .{}),1577 .dyld_stub_binder, .objc_msgsend => err.addNote("referenced implicitly", .{}),
1578 .refs => |refs| {1578 .refs => |refs| {
1579 var inote: usize = 0;1579 var inote: usize = 0;
1580 while (inote < @min(refs.items.len, max_notes)) : (inote += 1) {1580 while (inote < @min(refs.items.len, max_notes)) : (inote += 1) {
1581 const ref = refs.items[inote];1581 const ref = refs.items[inote];
1582 const file = self.getFile(ref.file).?;1582 const file = self.getFile(ref.file).?;
1583 const atom = ref.getAtom(self).?;1583 const atom = ref.getAtom(self).?;
1584 try err.addNote("referenced by {}:{s}", .{ file.fmtPath(), atom.getName(self) });1584 err.addNote("referenced by {}:{s}", .{ file.fmtPath(), atom.getName(self) });
1585 }1585 }
15861586
1587 if (refs.items.len > max_notes) {1587 if (refs.items.len > max_notes) {
1588 const remaining = refs.items.len - max_notes;1588 const remaining = refs.items.len - max_notes;
1589 try err.addNote("referenced {d} more times", .{remaining});1589 err.addNote("referenced {d} more times", .{remaining});
1590 }1590 }
1591 },1591 },
1592 }1592 }
...@@ -3473,8 +3473,8 @@ fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !vo...@@ -3473,8 +3473,8 @@ fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !vo
3473 seg_id,3473 seg_id,
3474 seg.segName(),3474 seg.segName(),
3475 });3475 });
3476 try err.addNote("TODO: emit relocations to memory locations in self-hosted backends", .{});3476 err.addNote("TODO: emit relocations to memory locations in self-hosted backends", .{});
3477 try err.addNote("as a workaround, try increasing pre-allocated virtual memory of each segment", .{});3477 err.addNote("as a workaround, try increasing pre-allocated virtual memory of each segment", .{});
3478 }3478 }
34793479
3480 seg.vmsize = needed_size;3480 seg.vmsize = needed_size;
...@@ -3776,7 +3776,7 @@ pub fn reportParseError2(...@@ -3776,7 +3776,7 @@ pub fn reportParseError2(
3776 const diags = &self.base.comp.link_diags;3776 const diags = &self.base.comp.link_diags;
3777 var err = try diags.addErrorWithNotes(1);3777 var err = try diags.addErrorWithNotes(1);
3778 try err.addMsg(format, args);3778 try err.addMsg(format, args);
3779 try err.addNote("while parsing {}", .{self.getFile(file_index).?.fmtPath()});3779 err.addNote("while parsing {}", .{self.getFile(file_index).?.fmtPath()});
3780}3780}
37813781
3782fn reportMissingDependencyError(3782fn reportMissingDependencyError(
...@@ -3790,10 +3790,10 @@ fn reportMissingDependencyError(...@@ -3790,10 +3790,10 @@ fn reportMissingDependencyError(
3790 const diags = &self.base.comp.link_diags;3790 const diags = &self.base.comp.link_diags;
3791 var err = try diags.addErrorWithNotes(2 + checked_paths.len);3791 var err = try diags.addErrorWithNotes(2 + checked_paths.len);
3792 try err.addMsg(format, args);3792 try err.addMsg(format, args);
3793 try err.addNote("while resolving {s}", .{path});3793 err.addNote("while resolving {s}", .{path});
3794 try err.addNote("a dependency of {}", .{self.getFile(parent).?.fmtPath()});3794 err.addNote("a dependency of {}", .{self.getFile(parent).?.fmtPath()});
3795 for (checked_paths) |p| {3795 for (checked_paths) |p| {
3796 try err.addNote("tried {s}", .{p});3796 err.addNote("tried {s}", .{p});
3797 }3797 }
3798}3798}
37993799
...@@ -3807,8 +3807,8 @@ fn reportDependencyError(...@@ -3807,8 +3807,8 @@ fn reportDependencyError(
3807 const diags = &self.base.comp.link_diags;3807 const diags = &self.base.comp.link_diags;
3808 var err = try diags.addErrorWithNotes(2);3808 var err = try diags.addErrorWithNotes(2);
3809 try err.addMsg(format, args);3809 try err.addMsg(format, args);
3810 try err.addNote("while parsing {s}", .{path});3810 err.addNote("while parsing {s}", .{path});
3811 try err.addNote("a dependency of {}", .{self.getFile(parent).?.fmtPath()});3811 err.addNote("a dependency of {}", .{self.getFile(parent).?.fmtPath()});
3812}3812}
38133813
3814fn reportDuplicates(self: *MachO) error{ HasDuplicates, OutOfMemory }!void {3814fn reportDuplicates(self: *MachO) error{ HasDuplicates, OutOfMemory }!void {
...@@ -3838,17 +3838,17 @@ fn reportDuplicates(self: *MachO) error{ HasDuplicates, OutOfMemory }!void {...@@ -3838,17 +3838,17 @@ fn reportDuplicates(self: *MachO) error{ HasDuplicates, OutOfMemory }!void {
38383838
3839 var err = try diags.addErrorWithNotes(nnotes + 1);3839 var err = try diags.addErrorWithNotes(nnotes + 1);
3840 try err.addMsg("duplicate symbol definition: {s}", .{sym.getName(self)});3840 try err.addMsg("duplicate symbol definition: {s}", .{sym.getName(self)});
3841 try err.addNote("defined by {}", .{sym.getFile(self).?.fmtPath()});3841 err.addNote("defined by {}", .{sym.getFile(self).?.fmtPath()});
38423842
3843 var inote: usize = 0;3843 var inote: usize = 0;
3844 while (inote < @min(notes.items.len, max_notes)) : (inote += 1) {3844 while (inote < @min(notes.items.len, max_notes)) : (inote += 1) {
3845 const file = self.getFile(notes.items[inote]).?;3845 const file = self.getFile(notes.items[inote]).?;
3846 try err.addNote("defined by {}", .{file.fmtPath()});3846 err.addNote("defined by {}", .{file.fmtPath()});
3847 }3847 }
38483848
3849 if (notes.items.len > max_notes) {3849 if (notes.items.len > max_notes) {
3850 const remaining = notes.items.len - max_notes;3850 const remaining = notes.items.len - max_notes;
3851 try err.addNote("defined {d} more times", .{remaining});3851 err.addNote("defined {d} more times", .{remaining});
3852 }3852 }
3853 }3853 }
3854 return error.HasDuplicates;3854 return error.HasDuplicates;
src/link/MachO/Atom.zig+2-2
...@@ -909,8 +909,8 @@ const x86_64 = struct {...@@ -909,8 +909,8 @@ const x86_64 = struct {
909 rel.offset,909 rel.offset,
910 rel.fmtPretty(.x86_64),910 rel.fmtPretty(.x86_64),
911 });911 });
912 try err.addNote("expected .mov instruction but found .{s}", .{@tagName(x)});912 err.addNote("expected .mov instruction but found .{s}", .{@tagName(x)});
913 try err.addNote("while parsing {}", .{self.getFile(macho_file).fmtPath()});913 err.addNote("while parsing {}", .{self.getFile(macho_file).fmtPath()});
914 return error.RelaxFailUnexpectedInstruction;914 return error.RelaxFailUnexpectedInstruction;
915 },915 },
916 }916 }
src/link/Wasm.zig+351-229
...@@ -109,7 +109,7 @@ object_tables: std.ArrayListUnmanaged(Table) = .empty,...@@ -109,7 +109,7 @@ object_tables: std.ArrayListUnmanaged(Table) = .empty,
109/// All memory imports for all objects.109/// All memory imports for all objects.
110object_memory_imports: std.ArrayListUnmanaged(MemoryImport) = .empty,110object_memory_imports: std.ArrayListUnmanaged(MemoryImport) = .empty,
111/// All parsed memory sections for all objects.111/// All parsed memory sections for all objects.
112object_memories: std.ArrayListUnmanaged(std.wasm.Memory) = .empty,112object_memories: std.ArrayListUnmanaged(ObjectMemory) = .empty,
113113
114/// All relocations from all objects concatenated. `relocs_start` marks the end114/// All relocations from all objects concatenated. `relocs_start` marks the end
115/// point of object relocations and start point of Zcu relocations.115/// point of object relocations and start point of Zcu relocations.
...@@ -119,8 +119,13 @@ object_relocations: std.MultiArrayList(ObjectRelocation) = .empty,...@@ -119,8 +119,13 @@ object_relocations: std.MultiArrayList(ObjectRelocation) = .empty,
119/// by the (synthetic) __wasm_call_ctors function.119/// by the (synthetic) __wasm_call_ctors function.
120object_init_funcs: std.ArrayListUnmanaged(InitFunc) = .empty,120object_init_funcs: std.ArrayListUnmanaged(InitFunc) = .empty,
121121
122/// Non-synthetic section that can essentially be mem-cpy'd into place after performing relocations.122/// The data section of an object has many segments. Each segment corresponds
123object_data_segments: std.ArrayListUnmanaged(DataSegment) = .empty,123/// logically to an object file's .data section, or .rodata section. In
124/// the case of `-fdata-sections` there will be one segment per data symbol.
125object_data_segments: std.ArrayListUnmanaged(ObjectDataSegment) = .empty,
126/// Each segment has many data symbols. These correspond logically to global
127/// constants.
128object_datas: std.ArrayListUnmanaged(ObjectData) = .empty,
124/// Non-synthetic section that can essentially be mem-cpy'd into place after performing relocations.129/// Non-synthetic section that can essentially be mem-cpy'd into place after performing relocations.
125object_custom_segments: std.AutoArrayHashMapUnmanaged(ObjectSectionIndex, CustomSegment) = .empty,130object_custom_segments: std.AutoArrayHashMapUnmanaged(ObjectSectionIndex, CustomSegment) = .empty,
126131
...@@ -457,6 +462,21 @@ pub const SourceLocation = enum(u32) {...@@ -457,6 +462,21 @@ pub const SourceLocation = enum(u32) {
457 .source_location_index => @panic("TODO"),462 .source_location_index => @panic("TODO"),
458 }463 }
459 }464 }
465
466 pub fn addNote(
467 sl: SourceLocation,
468 wasm: *Wasm,
469 err: *link.Diags.ErrorWithNotes,
470 comptime f: []const u8,
471 args: anytype,
472 ) void {
473 switch (sl.unpack(wasm)) {
474 .none => err.addNote(f, args),
475 .zig_object_nofile => err.addNote("zig compilation unit: " ++ f, args),
476 .object_index => |i| err.addNote("{}: " ++ f, .{i.ptr(wasm).path} ++ args),
477 .source_location_index => @panic("TODO"),
478 }
479 }
460};480};
461481
462/// The lower bits of this ABI-match the flags here:482/// The lower bits of this ABI-match the flags here:
...@@ -687,13 +707,13 @@ pub const UavsExeIndex = enum(u32) {...@@ -687,13 +707,13 @@ pub const UavsExeIndex = enum(u32) {
687707
688/// Used when emitting a relocatable object.708/// Used when emitting a relocatable object.
689pub const ZcuDataObj = extern struct {709pub const ZcuDataObj = extern struct {
690 code: DataSegment.Payload,710 code: DataPayload,
691 relocs: OutReloc.Slice,711 relocs: OutReloc.Slice,
692};712};
693713
694/// Used when not emitting a relocatable object.714/// Used when not emitting a relocatable object.
695pub const ZcuDataExe = extern struct {715pub const ZcuDataExe = extern struct {
696 code: DataSegment.Payload,716 code: DataPayload,
697 /// Tracks how many references there are for the purposes of sorting data segments.717 /// Tracks how many references there are for the purposes of sorting data segments.
698 count: u32,718 count: u32,
699};719};
...@@ -917,6 +937,10 @@ pub const FunctionImport = extern struct {...@@ -917,6 +937,10 @@ pub const FunctionImport = extern struct {
917 return pack(wasm, .{ .zcu_func = @enumFromInt(wasm.zcu_funcs.getIndex(ip_index).?) });937 return pack(wasm, .{ .zcu_func = @enumFromInt(wasm.zcu_funcs.getIndex(ip_index).?) });
918 }938 }
919939
940 pub fn fromObjectFunction(wasm: *const Wasm, object_function: ObjectFunctionIndex) Resolution {
941 return pack(wasm, .{ .object_function = object_function });
942 }
943
920 pub fn isNavOrUnresolved(r: Resolution, wasm: *const Wasm) bool {944 pub fn isNavOrUnresolved(r: Resolution, wasm: *const Wasm) bool {
921 return switch (r.unpack(wasm)) {945 return switch (r.unpack(wasm)) {
922 .unresolved, .zcu_func => true,946 .unresolved, .zcu_func => true,
...@@ -988,7 +1012,7 @@ pub const Function = extern struct {...@@ -988,7 +1012,7 @@ pub const Function = extern struct {
988 section_index: ObjectSectionIndex,1012 section_index: ObjectSectionIndex,
989 source_location: SourceLocation,1013 source_location: SourceLocation,
9901014
991 pub const Code = DataSegment.Payload;1015 pub const Code = DataPayload;
992};1016};
9931017
994pub const GlobalImport = extern struct {1018pub const GlobalImport = extern struct {
...@@ -1283,12 +1307,30 @@ pub const ObjectGlobalIndex = enum(u32) {...@@ -1283,12 +1307,30 @@ pub const ObjectGlobalIndex = enum(u32) {
1283 }1307 }
1284};1308};
12851309
1286/// Index into `Wasm.object_memories`.1310pub const ObjectMemory = extern struct {
1287pub const ObjectMemoryIndex = enum(u32) {1311 flags: SymbolFlags,
1288 _,1312 name: OptionalString,
1313 limits_min: u32,
1314 limits_max: u32,
12891315
1290 pub fn ptr(index: ObjectMemoryIndex, wasm: *const Wasm) *std.wasm.Memory {1316 /// Index into `Wasm.object_memories`.
1291 return &wasm.object_memories.items[@intFromEnum(index)];1317 pub const Index = enum(u32) {
1318 _,
1319
1320 pub fn ptr(index: Index, wasm: *const Wasm) *ObjectMemory {
1321 return &wasm.object_memories.items[@intFromEnum(index)];
1322 }
1323 };
1324
1325 pub fn limits(om: *const ObjectMemory) std.wasm.Limits {
1326 return .{
1327 .flags = .{
1328 .has_max = om.limits_has_max,
1329 .is_shared = om.limits_is_shared,
1330 },
1331 .min = om.limits_min,
1332 .max = om.limits_max,
1333 };
1292 }1334 }
1293};1335};
12941336
...@@ -1318,14 +1360,74 @@ pub const OptionalObjectFunctionIndex = enum(u32) {...@@ -1318,14 +1360,74 @@ pub const OptionalObjectFunctionIndex = enum(u32) {
1318 }1360 }
1319};1361};
13201362
1321pub const DataSegment = extern struct {1363pub const ObjectDataSegment = extern struct {
1364 /// `none` if segment info custom subsection is missing.
1365 name: OptionalString,
1366 flags: SymbolFlags,
1367 payload: DataPayload,
1368
1369 /// Index into `Wasm.object_data_segments`.
1370 pub const Index = enum(u32) {
1371 _,
1372
1373 pub fn ptr(i: Index, wasm: *const Wasm) *ObjectDataSegment {
1374 return &wasm.object_data_segments.items[@intFromEnum(i)];
1375 }
1376 };
1377};
1378
1379/// A local or exported global const from an object file.
1380pub const ObjectData = extern struct {
1381 segment: ObjectDataSegment.Index,
1382 /// Index into the object segment payload. Must be <= the segment's size.
1383 offset: u32,
1384 /// May be zero. `offset + size` must be <= the segment's size.
1385 size: u32,
1322 /// `none` if no symbol describes it.1386 /// `none` if no symbol describes it.
1323 name: OptionalString,1387 name: OptionalString,
1324 flags: SymbolFlags,1388 flags: SymbolFlags,
1325 payload: Payload,1389
1326 /// From the data segment start to the first byte of payload.1390 /// Index into `Wasm.object_datas`.
1327 segment_offset: u32,1391 pub const Index = enum(u32) {
1328 section_index: ObjectSectionIndex,1392 _,
1393
1394 pub fn ptr(i: Index, wasm: *const Wasm) *ObjectData {
1395 return &wasm.object_datas.items[@intFromEnum(i)];
1396 }
1397 };
1398};
1399
1400pub const DataPayload = extern struct {
1401 off: Off,
1402 /// The size in bytes of the data representing the segment within the section.
1403 len: u32,
1404
1405 pub const Off = enum(u32) {
1406 /// The payload is all zeroes (bss section).
1407 none = std.math.maxInt(u32),
1408 /// Points into string_bytes. No corresponding string_table entry.
1409 _,
1410
1411 pub fn unwrap(off: Off) ?u32 {
1412 return if (off == .none) null else @intFromEnum(off);
1413 }
1414 };
1415
1416 pub fn slice(p: DataPayload, wasm: *const Wasm) []const u8 {
1417 return wasm.string_bytes.items[p.off.unwrap().?..][0..p.len];
1418 }
1419};
1420
1421/// A reference to a local or exported global const.
1422pub const DataId = enum(u32) {
1423 __zig_error_names,
1424 __zig_error_name_table,
1425 /// First, an `ObjectDataSegment.Index`.
1426 /// Next, index into `uavs_obj` or `uavs_exe` depending on whether emitting an object.
1427 /// Next, index into `navs_obj` or `navs_exe` depending on whether emitting an object.
1428 _,
1429
1430 const first_object = @intFromEnum(DataId.__zig_error_name_table) + 1;
13291431
1330 pub const Category = enum {1432 pub const Category = enum {
1331 /// Thread-local variables.1433 /// Thread-local variables.
...@@ -1337,221 +1439,180 @@ pub const DataSegment = extern struct {...@@ -1337,221 +1439,180 @@ pub const DataSegment = extern struct {
1337 zero,1439 zero,
1338 };1440 };
13391441
1340 pub const Payload = extern struct {1442 pub const Unpacked = union(enum) {
1341 off: Off,
1342 /// The size in bytes of the data representing the segment within the section.
1343 len: u32,
1344
1345 pub const Off = enum(u32) {
1346 /// The payload is all zeroes (bss section).
1347 none = std.math.maxInt(u32),
1348 /// Points into string_bytes. No corresponding string_table entry.
1349 _,
1350
1351 pub fn unwrap(off: Off) ?u32 {
1352 return if (off == .none) null else @intFromEnum(off);
1353 }
1354 };
1355
1356 pub fn slice(p: DataSegment.Payload, wasm: *const Wasm) []const u8 {
1357 return wasm.string_bytes.items[p.off.unwrap().?..][0..p.len];
1358 }
1359 };
1360
1361 pub const Id = enum(u32) {
1362 __zig_error_names,1443 __zig_error_names,
1363 __zig_error_name_table,1444 __zig_error_name_table,
1364 /// First, an `ObjectDataSegmentIndex`.1445 object: ObjectDataSegment.Index,
1365 /// Next, index into `uavs_obj` or `uavs_exe` depending on whether emitting an object.1446 uav_exe: UavsExeIndex,
1366 /// Next, index into `navs_obj` or `navs_exe` depending on whether emitting an object.1447 uav_obj: UavsObjIndex,
1367 _,1448 nav_exe: NavsExeIndex,
13681449 nav_obj: NavsObjIndex,
1369 const first_object = @intFromEnum(Id.__zig_error_name_table) + 1;1450 };
13701451
1371 pub const Unpacked = union(enum) {1452 pub fn pack(wasm: *const Wasm, unpacked: Unpacked) DataId {
1372 __zig_error_names,1453 return switch (unpacked) {
1373 __zig_error_name_table,1454 .__zig_error_names => .__zig_error_names,
1374 object: ObjectDataSegmentIndex,1455 .__zig_error_name_table => .__zig_error_name_table,
1375 uav_exe: UavsExeIndex,1456 .object => |i| @enumFromInt(first_object + @intFromEnum(i)),
1376 uav_obj: UavsObjIndex,1457 inline .uav_exe, .uav_obj => |i| @enumFromInt(first_object + wasm.object_data_segments.items.len + @intFromEnum(i)),
1377 nav_exe: NavsExeIndex,1458 .nav_exe => |i| @enumFromInt(first_object + wasm.object_data_segments.items.len + wasm.uavs_exe.entries.len + @intFromEnum(i)),
1378 nav_obj: NavsObjIndex,1459 .nav_obj => |i| @enumFromInt(first_object + wasm.object_data_segments.items.len + wasm.uavs_obj.entries.len + @intFromEnum(i)),
1379 };1460 };
1461 }
13801462
1381 pub fn pack(wasm: *const Wasm, unpacked: Unpacked) Id {1463 pub fn unpack(id: DataId, wasm: *const Wasm) Unpacked {
1382 return switch (unpacked) {1464 return switch (id) {
1383 .__zig_error_names => .__zig_error_names,1465 .__zig_error_names => .__zig_error_names,
1384 .__zig_error_name_table => .__zig_error_name_table,1466 .__zig_error_name_table => .__zig_error_name_table,
1385 .object => |i| @enumFromInt(first_object + @intFromEnum(i)),1467 _ => {
1386 inline .uav_exe, .uav_obj => |i| @enumFromInt(first_object + wasm.object_data_segments.items.len + @intFromEnum(i)),1468 const object_index = @intFromEnum(id) - first_object;
1387 .nav_exe => |i| @enumFromInt(first_object + wasm.object_data_segments.items.len + wasm.uavs_exe.entries.len + @intFromEnum(i)),1469
1388 .nav_obj => |i| @enumFromInt(first_object + wasm.object_data_segments.items.len + wasm.uavs_obj.entries.len + @intFromEnum(i)),1470 const uav_index = if (object_index < wasm.object_data_segments.items.len)
1389 };1471 return .{ .object = @enumFromInt(object_index) }
1390 }1472 else
13911473 object_index - wasm.object_data_segments.items.len;
1392 pub fn unpack(id: Id, wasm: *const Wasm) Unpacked {1474
1393 return switch (id) {1475 const comp = wasm.base.comp;
1394 .__zig_error_names => .__zig_error_names,1476 const is_obj = comp.config.output_mode == .Obj;
1395 .__zig_error_name_table => .__zig_error_name_table,1477 if (is_obj) {
1396 _ => {1478 const nav_index = if (uav_index < wasm.uavs_obj.entries.len)
1397 const object_index = @intFromEnum(id) - first_object;1479 return .{ .uav_obj = @enumFromInt(uav_index) }
1398
1399 const uav_index = if (object_index < wasm.object_data_segments.items.len)
1400 return .{ .object = @enumFromInt(object_index) }
1401 else1480 else
1402 object_index - wasm.object_data_segments.items.len;1481 uav_index - wasm.uavs_obj.entries.len;
1403
1404 const comp = wasm.base.comp;
1405 const is_obj = comp.config.output_mode == .Obj;
1406 if (is_obj) {
1407 const nav_index = if (uav_index < wasm.uavs_obj.entries.len)
1408 return .{ .uav_obj = @enumFromInt(uav_index) }
1409 else
1410 uav_index - wasm.uavs_obj.entries.len;
1411
1412 return .{ .nav_obj = @enumFromInt(nav_index) };
1413 } else {
1414 const nav_index = if (uav_index < wasm.uavs_exe.entries.len)
1415 return .{ .uav_exe = @enumFromInt(uav_index) }
1416 else
1417 uav_index - wasm.uavs_exe.entries.len;
1418
1419 return .{ .nav_exe = @enumFromInt(nav_index) };
1420 }
1421 },
1422 };
1423 }
14241482
1425 pub fn category(id: Id, wasm: *const Wasm) Category {1483 return .{ .nav_obj = @enumFromInt(nav_index) };
1426 return switch (unpack(id, wasm)) {1484 } else {
1427 .__zig_error_names, .__zig_error_name_table => .data,1485 const nav_index = if (uav_index < wasm.uavs_exe.entries.len)
1428 .object => |i| {1486 return .{ .uav_exe = @enumFromInt(uav_index) }
1429 const ptr = i.ptr(wasm);1487 else
1430 if (ptr.flags.tls) return .tls;1488 uav_index - wasm.uavs_exe.entries.len;
1431 if (wasm.isBss(ptr.name)) return .zero;
1432 return .data;
1433 },
1434 inline .uav_exe, .uav_obj => |i| if (i.value(wasm).code.off == .none) .zero else .data,
1435 inline .nav_exe, .nav_obj => |i| {
1436 const zcu = wasm.base.comp.zcu.?;
1437 const ip = &zcu.intern_pool;
1438 const nav = ip.getNav(i.key(wasm).*);
1439 if (nav.isThreadLocal(ip)) return .tls;
1440 const code = i.value(wasm).code;
1441 return if (code.off == .none) .zero else .data;
1442 },
1443 };
1444 }
14451489
1446 pub fn isTls(id: Id, wasm: *const Wasm) bool {1490 return .{ .nav_exe = @enumFromInt(nav_index) };
1447 return switch (unpack(id, wasm)) {1491 }
1448 .__zig_error_names, .__zig_error_name_table => false,1492 },
1449 .object => |i| i.ptr(wasm).flags.tls,1493 };
1450 .uav_exe, .uav_obj => false,1494 }
1451 inline .nav_exe, .nav_obj => |i| {
1452 const zcu = wasm.base.comp.zcu.?;
1453 const ip = &zcu.intern_pool;
1454 const nav = ip.getNav(i.key(wasm).*);
1455 return nav.isThreadLocal(ip);
1456 },
1457 };
1458 }
14591495
1460 pub fn isBss(id: Id, wasm: *const Wasm) bool {1496 pub fn category(id: DataId, wasm: *const Wasm) Category {
1461 return id.category(wasm) == .zero;1497 return switch (unpack(id, wasm)) {
1462 }1498 .__zig_error_names, .__zig_error_name_table => .data,
1499 .object => |i| {
1500 const ptr = i.ptr(wasm);
1501 if (ptr.flags.tls) return .tls;
1502 if (wasm.isBss(ptr.name)) return .zero;
1503 return .data;
1504 },
1505 inline .uav_exe, .uav_obj => |i| if (i.value(wasm).code.off == .none) .zero else .data,
1506 inline .nav_exe, .nav_obj => |i| {
1507 const zcu = wasm.base.comp.zcu.?;
1508 const ip = &zcu.intern_pool;
1509 const nav = ip.getNav(i.key(wasm).*);
1510 if (nav.isThreadLocal(ip)) return .tls;
1511 const code = i.value(wasm).code;
1512 return if (code.off == .none) .zero else .data;
1513 },
1514 };
1515 }
14631516
1464 pub fn name(id: Id, wasm: *const Wasm) []const u8 {1517 pub fn isTls(id: DataId, wasm: *const Wasm) bool {
1465 return switch (unpack(id, wasm)) {1518 return switch (unpack(id, wasm)) {
1466 .__zig_error_names, .__zig_error_name_table, .uav_exe, .uav_obj => ".data",1519 .__zig_error_names, .__zig_error_name_table => false,
1467 .object => |i| i.ptr(wasm).name.unwrap().?.slice(wasm),1520 .object => |i| i.ptr(wasm).flags.tls,
1468 inline .nav_exe, .nav_obj => |i| {1521 .uav_exe, .uav_obj => false,
1469 const zcu = wasm.base.comp.zcu.?;1522 inline .nav_exe, .nav_obj => |i| {
1470 const ip = &zcu.intern_pool;1523 const zcu = wasm.base.comp.zcu.?;
1471 const nav = ip.getNav(i.key(wasm).*);1524 const ip = &zcu.intern_pool;
1472 return nav.status.resolved.@"linksection".toSlice(ip) orelse ".data";1525 const nav = ip.getNav(i.key(wasm).*);
1473 },1526 return nav.isThreadLocal(ip);
1474 };1527 },
1475 }1528 };
1529 }
14761530
1477 pub fn alignment(id: Id, wasm: *const Wasm) Alignment {1531 pub fn isBss(id: DataId, wasm: *const Wasm) bool {
1478 return switch (unpack(id, wasm)) {1532 return id.category(wasm) == .zero;
1479 .__zig_error_names => .@"1",1533 }
1480 .__zig_error_name_table => wasm.pointerAlignment(),
1481 .object => |i| i.ptr(wasm).flags.alignment,
1482 inline .uav_exe, .uav_obj => |i| {
1483 const zcu = wasm.base.comp.zcu.?;
1484 const ip = &zcu.intern_pool;
1485 const ip_index = i.key(wasm).*;
1486 const ty: ZcuType = .fromInterned(ip.typeOf(ip_index));
1487 const result = ty.abiAlignment(zcu);
1488 assert(result != .none);
1489 return result;
1490 },
1491 inline .nav_exe, .nav_obj => |i| {
1492 const zcu = wasm.base.comp.zcu.?;
1493 const ip = &zcu.intern_pool;
1494 const nav = ip.getNav(i.key(wasm).*);
1495 const explicit = nav.status.resolved.alignment;
1496 if (explicit != .none) return explicit;
1497 const ty: ZcuType = .fromInterned(nav.typeOf(ip));
1498 const result = ty.abiAlignment(zcu);
1499 assert(result != .none);
1500 return result;
1501 },
1502 };
1503 }
15041534
1505 pub fn refCount(id: Id, wasm: *const Wasm) u32 {1535 pub fn name(id: DataId, wasm: *const Wasm) []const u8 {
1506 return switch (unpack(id, wasm)) {1536 return switch (unpack(id, wasm)) {
1507 .__zig_error_names => @intCast(wasm.error_name_offs.items.len),1537 .__zig_error_names, .__zig_error_name_table, .uav_exe, .uav_obj => ".data",
1508 .__zig_error_name_table => wasm.error_name_table_ref_count,1538 .object => |i| i.ptr(wasm).name.unwrap().?.slice(wasm),
1509 .object, .uav_obj, .nav_obj => 0,1539 inline .nav_exe, .nav_obj => |i| {
1510 inline .uav_exe, .nav_exe => |i| i.value(wasm).count,1540 const zcu = wasm.base.comp.zcu.?;
1511 };1541 const ip = &zcu.intern_pool;
1512 }1542 const nav = ip.getNav(i.key(wasm).*);
1543 return nav.status.resolved.@"linksection".toSlice(ip) orelse ".data";
1544 },
1545 };
1546 }
15131547
1514 pub fn isPassive(id: Id, wasm: *const Wasm) bool {1548 pub fn alignment(id: DataId, wasm: *const Wasm) Alignment {
1515 const comp = wasm.base.comp;1549 return switch (unpack(id, wasm)) {
1516 if (comp.config.import_memory and !id.isBss(wasm)) return true;1550 .__zig_error_names => .@"1",
1517 return switch (unpack(id, wasm)) {1551 .__zig_error_name_table => wasm.pointerAlignment(),
1518 .__zig_error_names, .__zig_error_name_table => false,1552 .object => |i| i.ptr(wasm).flags.alignment,
1519 .object => |i| i.ptr(wasm).flags.is_passive,1553 inline .uav_exe, .uav_obj => |i| {
1520 .uav_exe, .uav_obj, .nav_exe, .nav_obj => false,1554 const zcu = wasm.base.comp.zcu.?;
1521 };1555 const ip = &zcu.intern_pool;
1522 }1556 const ip_index = i.key(wasm).*;
1557 const ty: ZcuType = .fromInterned(ip.typeOf(ip_index));
1558 const result = ty.abiAlignment(zcu);
1559 assert(result != .none);
1560 return result;
1561 },
1562 inline .nav_exe, .nav_obj => |i| {
1563 const zcu = wasm.base.comp.zcu.?;
1564 const ip = &zcu.intern_pool;
1565 const nav = ip.getNav(i.key(wasm).*);
1566 const explicit = nav.status.resolved.alignment;
1567 if (explicit != .none) return explicit;
1568 const ty: ZcuType = .fromInterned(nav.typeOf(ip));
1569 const result = ty.abiAlignment(zcu);
1570 assert(result != .none);
1571 return result;
1572 },
1573 };
1574 }
15231575
1524 pub fn isEmpty(id: Id, wasm: *const Wasm) bool {1576 pub fn refCount(id: DataId, wasm: *const Wasm) u32 {
1525 return switch (unpack(id, wasm)) {1577 return switch (unpack(id, wasm)) {
1526 .__zig_error_names, .__zig_error_name_table => false,1578 .__zig_error_names => @intCast(wasm.error_name_offs.items.len),
1527 .object => |i| i.ptr(wasm).payload.off == .none,1579 .__zig_error_name_table => wasm.error_name_table_ref_count,
1528 inline .uav_exe, .uav_obj, .nav_exe, .nav_obj => |i| i.value(wasm).code.off == .none,1580 .object, .uav_obj, .nav_obj => 0,
1529 };1581 inline .uav_exe, .nav_exe => |i| i.value(wasm).count,
1530 }1582 };
1583 }
15311584
1532 pub fn size(id: Id, wasm: *const Wasm) u32 {1585 pub fn isPassive(id: DataId, wasm: *const Wasm) bool {
1533 return switch (unpack(id, wasm)) {1586 const comp = wasm.base.comp;
1534 .__zig_error_names => @intCast(wasm.error_name_bytes.items.len),1587 if (comp.config.import_memory and !id.isBss(wasm)) return true;
1535 .__zig_error_name_table => {1588 return switch (unpack(id, wasm)) {
1536 const comp = wasm.base.comp;1589 .__zig_error_names, .__zig_error_name_table => false,
1537 const zcu = comp.zcu.?;1590 .object => |i| i.ptr(wasm).flags.is_passive,
1538 const errors_len = wasm.error_name_offs.items.len;1591 .uav_exe, .uav_obj, .nav_exe, .nav_obj => false,
1539 const elem_size = ZcuType.slice_const_u8_sentinel_0.abiSize(zcu);1592 };
1540 return @intCast(errors_len * elem_size);1593 }
1541 },
1542 .object => |i| i.ptr(wasm).payload.len,
1543 inline .uav_exe, .uav_obj, .nav_exe, .nav_obj => |i| i.value(wasm).code.len,
1544 };
1545 }
1546 };
1547};
15481594
1549/// Index into `Wasm.object_data_segments`.1595 pub fn isEmpty(id: DataId, wasm: *const Wasm) bool {
1550pub const ObjectDataSegmentIndex = enum(u32) {1596 return switch (unpack(id, wasm)) {
1551 _,1597 .__zig_error_names, .__zig_error_name_table => false,
1598 .object => |i| i.ptr(wasm).payload.off == .none,
1599 inline .uav_exe, .uav_obj, .nav_exe, .nav_obj => |i| i.value(wasm).code.off == .none,
1600 };
1601 }
15521602
1553 pub fn ptr(i: ObjectDataSegmentIndex, wasm: *const Wasm) *DataSegment {1603 pub fn size(id: DataId, wasm: *const Wasm) u32 {
1554 return &wasm.object_data_segments.items[@intFromEnum(i)];1604 return switch (unpack(id, wasm)) {
1605 .__zig_error_names => @intCast(wasm.error_name_bytes.items.len),
1606 .__zig_error_name_table => {
1607 const comp = wasm.base.comp;
1608 const zcu = comp.zcu.?;
1609 const errors_len = wasm.error_name_offs.items.len;
1610 const elem_size = ZcuType.slice_const_u8_sentinel_0.abiSize(zcu);
1611 return @intCast(errors_len * elem_size);
1612 },
1613 .object => |i| i.ptr(wasm).payload.len,
1614 inline .uav_exe, .uav_obj, .nav_exe, .nav_obj => |i| i.value(wasm).code.len,
1615 };
1555 }1616 }
1556};1617};
15571618
...@@ -1565,7 +1626,7 @@ pub const CustomSegment = extern struct {...@@ -1565,7 +1626,7 @@ pub const CustomSegment = extern struct {
1565 flags: SymbolFlags,1626 flags: SymbolFlags,
1566 section_name: String,1627 section_name: String,
15671628
1568 pub const Payload = DataSegment.Payload;1629 pub const Payload = DataPayload;
1569};1630};
15701631
1571/// An index into string_bytes where a wasm expression is found.1632/// An index into string_bytes where a wasm expression is found.
...@@ -1591,9 +1652,13 @@ pub const FunctionType = extern struct {...@@ -1591,9 +1652,13 @@ pub const FunctionType = extern struct {
1591 pub const Index = enum(u32) {1652 pub const Index = enum(u32) {
1592 _,1653 _,
15931654
1594 pub fn ptr(i: FunctionType.Index, wasm: *const Wasm) *FunctionType {1655 pub fn ptr(i: Index, wasm: *const Wasm) *FunctionType {
1595 return &wasm.func_types.keys()[@intFromEnum(i)];1656 return &wasm.func_types.keys()[@intFromEnum(i)];
1596 }1657 }
1658
1659 pub fn fmt(i: Index, wasm: *const Wasm) Formatter {
1660 return i.ptr(wasm).fmt(wasm);
1661 }
1597 };1662 };
15981663
1599 pub const format = @compileError("can't format without *Wasm reference");1664 pub const format = @compileError("can't format without *Wasm reference");
...@@ -1601,6 +1666,46 @@ pub const FunctionType = extern struct {...@@ -1601,6 +1666,46 @@ pub const FunctionType = extern struct {
1601 pub fn eql(a: FunctionType, b: FunctionType) bool {1666 pub fn eql(a: FunctionType, b: FunctionType) bool {
1602 return a.params == b.params and a.returns == b.returns;1667 return a.params == b.params and a.returns == b.returns;
1603 }1668 }
1669
1670 pub fn fmt(ft: FunctionType, wasm: *const Wasm) Formatter {
1671 return .{ .wasm = wasm, .ft = ft };
1672 }
1673
1674 const Formatter = struct {
1675 wasm: *const Wasm,
1676 ft: FunctionType,
1677
1678 pub fn format(
1679 self: Formatter,
1680 comptime format_string: []const u8,
1681 options: std.fmt.FormatOptions,
1682 writer: anytype,
1683 ) !void {
1684 if (format_string.len != 0) std.fmt.invalidFmtError(format_string, self);
1685 _ = options;
1686 const params = self.ft.params.slice(self.wasm);
1687 const returns = self.ft.returns.slice(self.wasm);
1688
1689 try writer.writeByte('(');
1690 for (params, 0..) |param, i| {
1691 try writer.print("{s}", .{@tagName(param)});
1692 if (i + 1 != params.len) {
1693 try writer.writeAll(", ");
1694 }
1695 }
1696 try writer.writeAll(") -> ");
1697 if (returns.len == 0) {
1698 try writer.writeAll("nil");
1699 } else {
1700 for (returns, 0..) |return_ty, i| {
1701 try writer.print("{s}", .{@tagName(return_ty)});
1702 if (i + 1 != returns.len) {
1703 try writer.writeAll(", ");
1704 }
1705 }
1706 }
1707 }
1708 };
1604};1709};
16051710
1606/// Represents a function entry, holding the index to its type1711/// Represents a function entry, holding the index to its type
...@@ -1955,7 +2060,7 @@ pub const ObjectRelocation = struct {...@@ -1955,7 +2060,7 @@ pub const ObjectRelocation = struct {
1955 symbol_name: String,2060 symbol_name: String,
1956 type_index: FunctionType.Index,2061 type_index: FunctionType.Index,
1957 section: ObjectSectionIndex,2062 section: ObjectSectionIndex,
1958 data_segment: ObjectDataSegmentIndex,2063 data: ObjectData.Index,
1959 function: Wasm.ObjectFunctionIndex,2064 function: Wasm.ObjectFunctionIndex,
1960 };2065 };
19612066
...@@ -2096,6 +2201,8 @@ pub const Feature = packed struct(u8) {...@@ -2096,6 +2201,8 @@ pub const Feature = packed struct(u8) {
2096 /// Type of the feature, must be unique in the sequence of features.2201 /// Type of the feature, must be unique in the sequence of features.
2097 tag: Tag,2202 tag: Tag,
20982203
2204 pub const sentinel: Feature = @bitCast(@as(u8, 0));
2205
2099 /// Stored identically to `String`. The bytes are reinterpreted as `Feature`2206 /// Stored identically to `String`. The bytes are reinterpreted as `Feature`
2100 /// elements. Elements must be sorted before string-interning.2207 /// elements. Elements must be sorted before string-interning.
2101 pub const Set = enum(u32) {2208 pub const Set = enum(u32) {
...@@ -2104,6 +2211,14 @@ pub const Feature = packed struct(u8) {...@@ -2104,6 +2211,14 @@ pub const Feature = packed struct(u8) {
2104 pub fn fromString(s: String) Set {2211 pub fn fromString(s: String) Set {
2105 return @enumFromInt(@intFromEnum(s));2212 return @enumFromInt(@intFromEnum(s));
2106 }2213 }
2214
2215 pub fn string(s: Set) String {
2216 return @enumFromInt(@intFromEnum(s));
2217 }
2218
2219 pub fn slice(s: Set, wasm: *const Wasm) [:sentinel]const Feature {
2220 return @ptrCast(string(s).slice(wasm));
2221 }
2107 };2222 };
21082223
2109 /// Unlike `std.Target.wasm.Feature` this also contains linker-features such as shared-mem.2224 /// Unlike `std.Target.wasm.Feature` this also contains linker-features such as shared-mem.
...@@ -2129,6 +2244,13 @@ pub const Feature = packed struct(u8) {...@@ -2129,6 +2244,13 @@ pub const Feature = packed struct(u8) {
2129 return @enumFromInt(@intFromEnum(feature));2244 return @enumFromInt(@intFromEnum(feature));
2130 }2245 }
21312246
2247 pub fn toCpuFeature(tag: Tag) ?std.Target.wasm.Feature {
2248 return if (@intFromEnum(tag) < @typeInfo(std.Target.wasm.Feature).@"enum".fields.len)
2249 @enumFromInt(@intFromEnum(tag))
2250 else
2251 null;
2252 }
2253
2132 pub const format = @compileError("use @tagName instead");2254 pub const format = @compileError("use @tagName instead");
2133 };2255 };
21342256
...@@ -2136,15 +2258,14 @@ pub const Feature = packed struct(u8) {...@@ -2136,15 +2258,14 @@ pub const Feature = packed struct(u8) {
2136 pub const Prefix = enum(u2) {2258 pub const Prefix = enum(u2) {
2137 /// Reserved so that a 0-byte Feature is invalid and therefore can be a sentinel.2259 /// Reserved so that a 0-byte Feature is invalid and therefore can be a sentinel.
2138 invalid,2260 invalid,
2139 /// '0x2b': Object uses this feature, and the link fails if feature is2261 /// Object uses this feature, and the link fails if feature is not in
2140 /// not in the allowed set.2262 /// the allowed set.
2141 @"+",2263 @"+",
2142 /// '0x2d': Object does not use this feature, and the link fails if2264 /// Object does not use this feature, and the link fails if this
2143 /// this feature is in the allowed set.2265 /// feature is in the allowed set.
2144 @"-",2266 @"-",
2145 /// '0x3d': Object uses this feature, and the link fails if this2267 /// Object uses this feature, and the link fails if this feature is not
2146 /// feature is not in the allowed set, or if any object does not use2268 /// in the allowed set, or if any object does not use this feature.
2147 /// this feature.
2148 @"=",2269 @"=",
2149 };2270 };
21502271
...@@ -2390,6 +2511,7 @@ pub fn deinit(wasm: *Wasm) void {...@@ -2390,6 +2511,7 @@ pub fn deinit(wasm: *Wasm) void {
2390 wasm.object_memories.deinit(gpa);2511 wasm.object_memories.deinit(gpa);
2391 wasm.object_relocations.deinit(gpa);2512 wasm.object_relocations.deinit(gpa);
2392 wasm.object_data_segments.deinit(gpa);2513 wasm.object_data_segments.deinit(gpa);
2514 wasm.object_datas.deinit(gpa);
2393 wasm.object_custom_segments.deinit(gpa);2515 wasm.object_custom_segments.deinit(gpa);
2394 wasm.object_init_funcs.deinit(gpa);2516 wasm.object_init_funcs.deinit(gpa);
2395 wasm.object_comdats.deinit(gpa);2517 wasm.object_comdats.deinit(gpa);
...@@ -3412,7 +3534,7 @@ pub fn addExpr(wasm: *Wasm, bytes: []const u8) Allocator.Error!Expr {...@@ -3412,7 +3534,7 @@ pub fn addExpr(wasm: *Wasm, bytes: []const u8) Allocator.Error!Expr {
3412 return @enumFromInt(wasm.string_bytes.items.len - bytes.len);3534 return @enumFromInt(wasm.string_bytes.items.len - bytes.len);
3413}3535}
34143536
3415pub fn addRelocatableDataPayload(wasm: *Wasm, bytes: []const u8) Allocator.Error!DataSegment.Payload {3537pub fn addRelocatableDataPayload(wasm: *Wasm, bytes: []const u8) Allocator.Error!DataPayload {
3416 const gpa = wasm.base.comp.gpa;3538 const gpa = wasm.base.comp.gpa;
3417 try wasm.string_bytes.appendSlice(gpa, bytes);3539 try wasm.string_bytes.appendSlice(gpa, bytes);
3418 return .{3540 return .{
...@@ -3546,7 +3668,7 @@ pub fn uavAddr(wasm: *Wasm, uav_index: UavsExeIndex) u32 {...@@ -3546,7 +3668,7 @@ pub fn uavAddr(wasm: *Wasm, uav_index: UavsExeIndex) u32 {
3546 assert(wasm.flush_buffer.memory_layout_finished);3668 assert(wasm.flush_buffer.memory_layout_finished);
3547 const comp = wasm.base.comp;3669 const comp = wasm.base.comp;
3548 assert(comp.config.output_mode != .Obj);3670 assert(comp.config.output_mode != .Obj);
3549 const ds_id: DataSegment.Id = .pack(wasm, .{ .uav_exe = uav_index });3671 const ds_id: DataId = .pack(wasm, .{ .uav_exe = uav_index });
3550 return wasm.flush_buffer.data_segments.get(ds_id).?;3672 return wasm.flush_buffer.data_segments.get(ds_id).?;
3551}3673}
35523674
...@@ -3557,7 +3679,7 @@ pub fn navAddr(wasm: *Wasm, nav_index: InternPool.Nav.Index) u32 {...@@ -3557,7 +3679,7 @@ pub fn navAddr(wasm: *Wasm, nav_index: InternPool.Nav.Index) u32 {
3557 assert(comp.config.output_mode != .Obj);3679 assert(comp.config.output_mode != .Obj);
3558 const navs_exe_index: NavsExeIndex = @enumFromInt(wasm.navs_exe.getIndex(nav_index).?);3680 const navs_exe_index: NavsExeIndex = @enumFromInt(wasm.navs_exe.getIndex(nav_index).?);
3559 log.debug("navAddr {s} {}", .{ navs_exe_index.name(wasm), nav_index });3681 log.debug("navAddr {s} {}", .{ navs_exe_index.name(wasm), nav_index });
3560 const ds_id: DataSegment.Id = .pack(wasm, .{ .nav_exe = navs_exe_index });3682 const ds_id: DataId = .pack(wasm, .{ .nav_exe = navs_exe_index });
3561 return wasm.flush_buffer.data_segments.get(ds_id).?;3683 return wasm.flush_buffer.data_segments.get(ds_id).?;
3562}3684}
35633685
...@@ -3646,14 +3768,14 @@ fn lowerZcuData(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !Zcu...@@ -3646,14 +3768,14 @@ fn lowerZcuData(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !Zcu
3646 const relocs_len: u32 = @intCast(wasm.out_relocs.len - relocs_start);3768 const relocs_len: u32 = @intCast(wasm.out_relocs.len - relocs_start);
3647 wasm.string_bytes_lock.unlock();3769 wasm.string_bytes_lock.unlock();
36483770
3649 const naive_code: DataSegment.Payload = .{3771 const naive_code: DataPayload = .{
3650 .off = @enumFromInt(code_start),3772 .off = @enumFromInt(code_start),
3651 .len = code_len,3773 .len = code_len,
3652 };3774 };
36533775
3654 // Only nonzero init values need to take up space in the output.3776 // Only nonzero init values need to take up space in the output.
3655 const all_zeroes = std.mem.allEqual(u8, naive_code.slice(wasm), 0);3777 const all_zeroes = std.mem.allEqual(u8, naive_code.slice(wasm), 0);
3656 const code: DataSegment.Payload = if (!all_zeroes) naive_code else c: {3778 const code: DataPayload = if (!all_zeroes) naive_code else c: {
3657 wasm.string_bytes.shrinkRetainingCapacity(code_start);3779 wasm.string_bytes.shrinkRetainingCapacity(code_start);
3658 // Indicate empty by making off and len the same value, however, still3780 // Indicate empty by making off and len the same value, however, still
3659 // transmit the data size by using the size as that value.3781 // transmit the data size by using the size as that value.
src/link/Wasm/Flush.zig+12-12
...@@ -22,7 +22,7 @@ const assert = std.debug.assert;...@@ -22,7 +22,7 @@ const assert = std.debug.assert;
22/// Ordered list of data segments that will appear in the final binary.22/// Ordered list of data segments that will appear in the final binary.
23/// When sorted, to-be-merged segments will be made adjacent.23/// When sorted, to-be-merged segments will be made adjacent.
24/// Values are virtual address.24/// Values are virtual address.
25data_segments: std.AutoArrayHashMapUnmanaged(Wasm.DataSegment.Id, u32) = .empty,25data_segments: std.AutoArrayHashMapUnmanaged(Wasm.DataId, u32) = .empty,
26/// Each time a `data_segment` offset equals zero it indicates a new group, and26/// Each time a `data_segment` offset equals zero it indicates a new group, and
27/// the next element in this array will contain the total merged segment size.27/// the next element in this array will contain the total merged segment size.
28/// Value is the virtual memory address of the end of the segment.28/// Value is the virtual memory address of the end of the segment.
...@@ -120,7 +120,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -120,7 +120,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
120 if (wasm.entry_resolution == .unresolved) {120 if (wasm.entry_resolution == .unresolved) {
121 var err = try diags.addErrorWithNotes(1);121 var err = try diags.addErrorWithNotes(1);
122 try err.addMsg("entry symbol '{s}' missing", .{name.slice(wasm)});122 try err.addMsg("entry symbol '{s}' missing", .{name.slice(wasm)});
123 try err.addNote("'-fno-entry' suppresses this error", .{});123 err.addNote("'-fno-entry' suppresses this error", .{});
124 }124 }
125 }125 }
126 }126 }
...@@ -176,10 +176,10 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -176,10 +176,10 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
176 }), @as(u32, undefined));176 }), @as(u32, undefined));
177 for (wasm.object_data_segments.items, 0..) |*ds, i| {177 for (wasm.object_data_segments.items, 0..) |*ds, i| {
178 if (!ds.flags.alive) continue;178 if (!ds.flags.alive) continue;
179 const data_segment_index: Wasm.ObjectDataSegmentIndex = @enumFromInt(i);179 const obj_seg_index: Wasm.ObjectDataSegment.Index = @enumFromInt(i);
180 any_passive_inits = any_passive_inits or ds.flags.is_passive or (import_memory and !wasm.isBss(ds.name));180 any_passive_inits = any_passive_inits or ds.flags.is_passive or (import_memory and !wasm.isBss(ds.name));
181 _ = f.data_segments.putAssumeCapacityNoClobber(.pack(wasm, .{181 _ = f.data_segments.putAssumeCapacityNoClobber(.pack(wasm, .{
182 .object = data_segment_index,182 .object = obj_seg_index,
183 }), @as(u32, undefined));183 }), @as(u32, undefined));
184 }184 }
185 if (wasm.error_name_table_ref_count > 0) {185 if (wasm.error_name_table_ref_count > 0) {
...@@ -229,7 +229,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -229,7 +229,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
229 // For the purposes of sorting, they are implicitly all named ".data".229 // For the purposes of sorting, they are implicitly all named ".data".
230 const Sort = struct {230 const Sort = struct {
231 wasm: *const Wasm,231 wasm: *const Wasm,
232 segments: []const Wasm.DataSegment.Id,232 segments: []const Wasm.DataId,
233 pub fn lessThan(ctx: @This(), lhs: usize, rhs: usize) bool {233 pub fn lessThan(ctx: @This(), lhs: usize, rhs: usize) bool {
234 const lhs_segment = ctx.segments[lhs];234 const lhs_segment = ctx.segments[lhs];
235 const rhs_segment = ctx.segments[rhs];235 const rhs_segment = ctx.segments[rhs];
...@@ -312,7 +312,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -312,7 +312,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
312 const data_vaddr: u32 = @intCast(memory_ptr);312 const data_vaddr: u32 = @intCast(memory_ptr);
313 {313 {
314 var seen_tls: enum { before, during, after } = .before;314 var seen_tls: enum { before, during, after } = .before;
315 var category: Wasm.DataSegment.Category = undefined;315 var category: Wasm.DataId.Category = undefined;
316 for (segment_ids, segment_vaddrs, 0..) |segment_id, *segment_vaddr, i| {316 for (segment_ids, segment_vaddrs, 0..) |segment_id, *segment_vaddr, i| {
317 const alignment = segment_id.alignment(wasm);317 const alignment = segment_id.alignment(wasm);
318 category = segment_id.category(wasm);318 category = segment_id.category(wasm);
...@@ -707,7 +707,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -707,7 +707,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
707707
708 if (!is_obj) {708 if (!is_obj) {
709 for (wasm.uav_fixups.items) |uav_fixup| {709 for (wasm.uav_fixups.items) |uav_fixup| {
710 const ds_id: Wasm.DataSegment.Id = .pack(wasm, .{ .uav_exe = uav_fixup.uavs_exe_index });710 const ds_id: Wasm.DataId = .pack(wasm, .{ .uav_exe = uav_fixup.uavs_exe_index });
711 const vaddr = f.data_segments.get(ds_id).?;711 const vaddr = f.data_segments.get(ds_id).?;
712 if (!is64) {712 if (!is64) {
713 mem.writeInt(u32, wasm.string_bytes.items[uav_fixup.offset..][0..4], vaddr, .little);713 mem.writeInt(u32, wasm.string_bytes.items[uav_fixup.offset..][0..4], vaddr, .little);
...@@ -716,7 +716,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -716,7 +716,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
716 }716 }
717 }717 }
718 for (wasm.nav_fixups.items) |nav_fixup| {718 for (wasm.nav_fixups.items) |nav_fixup| {
719 const ds_id: Wasm.DataSegment.Id = .pack(wasm, .{ .nav_exe = nav_fixup.navs_exe_index });719 const ds_id: Wasm.DataId = .pack(wasm, .{ .nav_exe = nav_fixup.navs_exe_index });
720 const vaddr = f.data_segments.get(ds_id).?;720 const vaddr = f.data_segments.get(ds_id).?;
721 if (!is64) {721 if (!is64) {
722 mem.writeInt(u32, wasm.string_bytes.items[nav_fixup.offset..][0..4], vaddr, .little);722 mem.writeInt(u32, wasm.string_bytes.items[nav_fixup.offset..][0..4], vaddr, .little);
...@@ -862,7 +862,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -862,7 +862,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
862862
863fn emitNameSection(863fn emitNameSection(
864 wasm: *Wasm,864 wasm: *Wasm,
865 data_segments: *const std.AutoArrayHashMapUnmanaged(Wasm.DataSegment.Id, u32),865 data_segments: *const std.AutoArrayHashMapUnmanaged(Wasm.DataId, u32),
866 binary_bytes: *std.ArrayListUnmanaged(u8),866 binary_bytes: *std.ArrayListUnmanaged(u8),
867) !void {867) !void {
868 const f = &wasm.flush_buffer;868 const f = &wasm.flush_buffer;
...@@ -1137,9 +1137,9 @@ fn splitSegmentName(name: []const u8) struct { []const u8, []const u8 } {...@@ -1137,9 +1137,9 @@ fn splitSegmentName(name: []const u8) struct { []const u8, []const u8 } {
11371137
1138fn wantSegmentMerge(1138fn wantSegmentMerge(
1139 wasm: *const Wasm,1139 wasm: *const Wasm,
1140 a_id: Wasm.DataSegment.Id,1140 a_id: Wasm.DataId,
1141 b_id: Wasm.DataSegment.Id,1141 b_id: Wasm.DataId,
1142 b_category: Wasm.DataSegment.Category,1142 b_category: Wasm.DataId.Category,
1143) bool {1143) bool {
1144 const a_category = a_id.category(wasm);1144 const a_category = a_id.category(wasm);
1145 if (a_category != b_category) return false;1145 if (a_category != b_category) return false;
src/link/Wasm/Object.zig+105-79
...@@ -102,11 +102,7 @@ pub const Symbol = struct {...@@ -102,11 +102,7 @@ pub const Symbol = struct {
102 const Pointee = union(enum) {102 const Pointee = union(enum) {
103 function: Wasm.ObjectFunctionIndex,103 function: Wasm.ObjectFunctionIndex,
104 function_import: ScratchSpace.FuncImportIndex,104 function_import: ScratchSpace.FuncImportIndex,
105 data: struct {105 data: Wasm.ObjectData.Index,
106 segment_index: Wasm.ObjectDataSegmentIndex,
107 segment_offset: u32,
108 size: u32,
109 },
110 data_import: void,106 data_import: void,
111 global: Wasm.ObjectGlobalIndex,107 global: Wasm.ObjectGlobalIndex,
112 global_import: Wasm.GlobalImport.Index,108 global_import: Wasm.GlobalImport.Index,
...@@ -131,7 +127,7 @@ pub const ScratchSpace = struct {...@@ -131,7 +127,7 @@ pub const ScratchSpace = struct {
131 const Pointee = union(std.wasm.ExternalKind) {127 const Pointee = union(std.wasm.ExternalKind) {
132 function: Wasm.ObjectFunctionIndex,128 function: Wasm.ObjectFunctionIndex,
133 table: Wasm.ObjectTableIndex,129 table: Wasm.ObjectTableIndex,
134 memory: Wasm.ObjectMemoryIndex,130 memory: Wasm.ObjectMemory.Index,
135 global: Wasm.ObjectGlobalIndex,131 global: Wasm.ObjectGlobalIndex,
136 };132 };
137 };133 };
...@@ -184,8 +180,9 @@ pub fn parse(...@@ -184,8 +180,9 @@ pub fn parse(
184 must_link: bool,180 must_link: bool,
185 gc_sections: bool,181 gc_sections: bool,
186) anyerror!Object {182) anyerror!Object {
187 const gpa = wasm.base.comp.gpa;183 const comp = wasm.base.comp;
188 const diags = &wasm.base.comp.link_diags;184 const gpa = comp.gpa;
185 const diags = &comp.link_diags;
189186
190 var pos: usize = 0;187 var pos: usize = 0;
191188
...@@ -334,12 +331,16 @@ pub fn parse(...@@ -334,12 +331,16 @@ pub fn parse(
334 const segment_index, pos = readLeb(u32, bytes, pos);331 const segment_index, pos = readLeb(u32, bytes, pos);
335 const segment_offset, pos = readLeb(u32, bytes, pos);332 const segment_offset, pos = readLeb(u32, bytes, pos);
336 const size, pos = readLeb(u32, bytes, pos);333 const size, pos = readLeb(u32, bytes, pos);
337334 try wasm.object_datas.append(gpa, .{
338 symbol.pointee = .{ .data = .{335 .segment = @enumFromInt(data_segment_start + segment_index),
339 .segment_index = @enumFromInt(data_segment_start + segment_index),336 .offset = segment_offset,
340 .segment_offset = segment_offset,
341 .size = size,337 .size = size,
342 } };338 .name = symbol.name,
339 .flags = symbol.flags,
340 });
341 symbol.pointee = .{
342 .data = @enumFromInt(wasm.object_datas.items.len - 1),
343 };
343 }344 }
344 },345 },
345 .section => {346 .section => {
...@@ -405,7 +406,6 @@ pub fn parse(...@@ -405,7 +406,6 @@ pub fn parse(
405 return error.UnrecognizedSymbolType;406 return error.UnrecognizedSymbolType;
406 },407 },
407 }408 }
408 log.debug("found symbol: {}", .{symbol});
409 }409 }
410 },410 },
411 }411 }
...@@ -450,22 +450,10 @@ pub fn parse(...@@ -450,22 +450,10 @@ pub fn parse(
450 .MEMORY_ADDR_TLS_SLEB64,450 .MEMORY_ADDR_TLS_SLEB64,
451 => {451 => {
452 const addend: i32, pos = readLeb(i32, bytes, pos);452 const addend: i32, pos = readLeb(i32, bytes, pos);
453 const sym_section = ss.symbol_table.items[index].pointee.data;
454 if (sym_section.segment_offset != 0) {
455 return diags.failParse(path, "data symbol {d} has nonzero offset {d}", .{
456 index, sym_section.segment_offset,
457 });
458 }
459 const seg_size = sym_section.segment_index.ptr(wasm).payload.len;
460 if (sym_section.size != seg_size) {
461 return diags.failParse(path, "data symbol {d} has size {d}, inequal to corresponding data segment {d} size {d}", .{
462 index, sym_section.size, @intFromEnum(sym_section.segment_index), seg_size,
463 });
464 }
465 wasm.object_relocations.appendAssumeCapacity(.{453 wasm.object_relocations.appendAssumeCapacity(.{
466 .tag = tag,454 .tag = tag,
467 .offset = offset,455 .offset = offset,
468 .pointee = .{ .data_segment = sym_section.segment_index },456 .pointee = .{ .data = ss.symbol_table.items[index].pointee.data },
469 .addend = addend,457 .addend = addend,
470 });458 });
471 },459 },
...@@ -651,7 +639,15 @@ pub fn parse(...@@ -651,7 +639,15 @@ pub fn parse(
651 const memories_len, pos = readLeb(u32, bytes, pos);639 const memories_len, pos = readLeb(u32, bytes, pos);
652 for (try wasm.object_memories.addManyAsSlice(gpa, memories_len)) |*memory| {640 for (try wasm.object_memories.addManyAsSlice(gpa, memories_len)) |*memory| {
653 const limits, pos = readLimits(bytes, pos);641 const limits, pos = readLimits(bytes, pos);
654 memory.* = .{ .limits = limits };642 memory.* = .{
643 .name = .none,
644 .flags = .{
645 .limits_has_max = limits.flags.has_max,
646 .limits_is_shared = limits.flags.is_shared,
647 },
648 .limits_min = limits.min,
649 .limits_max = limits.max,
650 };
655 }651 }
656 },652 },
657 .global => {653 .global => {
...@@ -722,7 +718,6 @@ pub fn parse(...@@ -722,7 +718,6 @@ pub fn parse(
722 }718 }
723 },719 },
724 .data => {720 .data => {
725 const start = pos;
726 const count, pos = readLeb(u32, bytes, pos);721 const count, pos = readLeb(u32, bytes, pos);
727 for (try wasm.object_data_segments.addManyAsSlice(gpa, count)) |*elem| {722 for (try wasm.object_data_segments.addManyAsSlice(gpa, count)) |*elem| {
728 const flags, pos = readEnum(DataSegmentFlags, bytes, pos);723 const flags, pos = readEnum(DataSegmentFlags, bytes, pos);
...@@ -733,13 +728,10 @@ pub fn parse(...@@ -733,13 +728,10 @@ pub fn parse(
733 //const expr, pos = if (flags != .passive) try readInit(wasm, bytes, pos) else .{ .none, pos };728 //const expr, pos = if (flags != .passive) try readInit(wasm, bytes, pos) else .{ .none, pos };
734 if (flags != .passive) pos = try skipInit(bytes, pos);729 if (flags != .passive) pos = try skipInit(bytes, pos);
735 const data_len, pos = readLeb(u32, bytes, pos);730 const data_len, pos = readLeb(u32, bytes, pos);
736 const segment_offset: u32 = @intCast(pos - start);
737 const payload = try wasm.addRelocatableDataPayload(bytes[pos..][0..data_len]);731 const payload = try wasm.addRelocatableDataPayload(bytes[pos..][0..data_len]);
738 pos += data_len;732 pos += data_len;
739 elem.* = .{733 elem.* = .{
740 .payload = payload,734 .payload = payload,
741 .segment_offset = segment_offset,
742 .section_index = section_index,
743 .name = .none, // Populated from symbol table735 .name = .none, // Populated from symbol table
744 .flags = .{}, // Populated from symbol table and segment_info736 .flags = .{}, // Populated from symbol table and segment_info
745 };737 };
...@@ -751,20 +743,56 @@ pub fn parse(...@@ -751,20 +743,56 @@ pub fn parse(
751 }743 }
752 if (!saw_linking_section) return error.MissingLinkingSection;744 if (!saw_linking_section) return error.MissingLinkingSection;
753745
746 const target_features = comp.root_mod.resolved_target.result.cpu.features;
747
754 if (has_tls) {748 if (has_tls) {
755 const cpu_features = wasm.base.comp.root_mod.resolved_target.result.cpu.features;749 if (!std.Target.wasm.featureSetHas(target_features, .atomics))
756 if (!std.Target.wasm.featureSetHas(cpu_features, .atomics))
757 return diags.failParse(path, "object has TLS segment but target CPU feature atomics is disabled", .{});750 return diags.failParse(path, "object has TLS segment but target CPU feature atomics is disabled", .{});
758 if (!std.Target.wasm.featureSetHas(cpu_features, .bulk_memory))751 if (!std.Target.wasm.featureSetHas(target_features, .bulk_memory))
759 return diags.failParse(path, "object has TLS segment but target CPU feature bulk_memory is disabled", .{});752 return diags.failParse(path, "object has TLS segment but target CPU feature bulk_memory is disabled", .{});
760 }753 }
761754
762 const features = opt_features orelse return error.MissingFeatures;755 const features = opt_features orelse return error.MissingFeatures;
763 if (true) @panic("iterate features, match against target features");756 for (features.slice(wasm)) |feat| {
757 log.debug("feature: {s}{s}", .{ @tagName(feat.prefix), @tagName(feat.tag) });
758 switch (feat.prefix) {
759 .invalid => unreachable,
760 .@"-" => switch (feat.tag) {
761 .@"shared-mem" => if (comp.config.shared_memory) {
762 return diags.failParse(path, "object forbids shared-mem but compilation enables it", .{});
763 },
764 else => {
765 const f = feat.tag.toCpuFeature().?;
766 if (std.Target.wasm.featureSetHas(target_features, f)) {
767 return diags.failParse(
768 path,
769 "object forbids {s} but specified target features include {s}",
770 .{ @tagName(feat.tag), @tagName(f) },
771 );
772 }
773 },
774 },
775 .@"+", .@"=" => switch (feat.tag) {
776 .@"shared-mem" => if (!comp.config.shared_memory) {
777 return diags.failParse(path, "object requires shared-mem but compilation disables it", .{});
778 },
779 else => {
780 const f = feat.tag.toCpuFeature().?;
781 if (!std.Target.wasm.featureSetHas(target_features, f)) {
782 return diags.failParse(
783 path,
784 "object requires {s} but specified target features exclude {s}",
785 .{ @tagName(feat.tag), @tagName(f) },
786 );
787 }
788 },
789 },
790 }
791 }
764792
765 // Apply function type information.793 // Apply function type information.
766 for (ss.func_types.items, wasm.object_functions.items[functions_start..]) |func_type, *func| {794 for (ss.func_type_indexes.items, wasm.object_functions.items[functions_start..]) |func_type, *func| {
767 func.type_index = func_type;795 func.type_index = func_type.ptr(ss).*;
768 }796 }
769797
770 // Apply symbol table information.798 // Apply symbol table information.
...@@ -782,15 +810,21 @@ pub fn parse(...@@ -782,15 +810,21 @@ pub fn parse(
782 if (gop.value_ptr.type != fn_ty_index) {810 if (gop.value_ptr.type != fn_ty_index) {
783 var err = try diags.addErrorWithNotes(2);811 var err = try diags.addErrorWithNotes(2);
784 try err.addMsg("symbol '{s}' mismatching function signatures", .{name.slice(wasm)});812 try err.addMsg("symbol '{s}' mismatching function signatures", .{name.slice(wasm)});
785 try err.addSrcNote(gop.value_ptr.source_location, "imported as {} here", .{gop.value_ptr.type.fmt(wasm)});813 gop.value_ptr.source_location.addNote(wasm, &err, "imported as {} here", .{
786 try err.addSrcNote(source_location, "imported as {} here", .{fn_ty_index.fmt(wasm)});814 gop.value_ptr.type.fmt(wasm),
815 });
816 source_location.addNote(wasm, &err, "imported as {} here", .{fn_ty_index.fmt(wasm)});
787 continue;817 continue;
788 }818 }
789 if (gop.value_ptr.module_name != ptr.module_name) {819 if (gop.value_ptr.module_name != ptr.module_name.toOptional()) {
790 var err = try diags.addErrorWithNotes(2);820 var err = try diags.addErrorWithNotes(2);
791 try err.addMsg("symbol '{s}' mismatching module names", .{name.slice(wasm)});821 try err.addMsg("symbol '{s}' mismatching module names", .{name.slice(wasm)});
792 try err.addSrcNote(gop.value_ptr.source_location, "module '{s}' here", .{gop.value_ptr.module_name.slice(wasm)});822 if (gop.value_ptr.module_name.slice(wasm)) |module_name| {
793 try err.addSrcNote(source_location, "module '{s}' here", .{ptr.module_name.slice(wasm)});823 gop.value_ptr.source_location.addNote(wasm, &err, "module '{s}' here", .{module_name});
824 } else {
825 gop.value_ptr.source_location.addNote(wasm, &err, "no module here", .{});
826 }
827 source_location.addNote(wasm, &err, "module '{s}' here", .{ptr.module_name.slice(wasm)});
794 continue;828 continue;
795 }829 }
796 if (symbol.flags.binding == .strong) gop.value_ptr.flags.binding = .strong;830 if (symbol.flags.binding == .strong) gop.value_ptr.flags.binding = .strong;
...@@ -799,7 +833,7 @@ pub fn parse(...@@ -799,7 +833,7 @@ pub fn parse(
799 } else {833 } else {
800 gop.value_ptr.* = .{834 gop.value_ptr.* = .{
801 .flags = symbol.flags,835 .flags = symbol.flags,
802 .module_name = ptr.module_name,836 .module_name = ptr.module_name.toOptional(),
803 .source_location = source_location,837 .source_location = source_location,
804 .resolution = .unresolved,838 .resolution = .unresolved,
805 .type = fn_ty_index,839 .type = fn_ty_index,
...@@ -808,7 +842,7 @@ pub fn parse(...@@ -808,7 +842,7 @@ pub fn parse(
808 },842 },
809 .function => |index| {843 .function => |index| {
810 assert(!symbol.flags.undefined);844 assert(!symbol.flags.undefined);
811 const ptr = index.ptr();845 const ptr = index.ptr(wasm);
812 ptr.name = symbol.name;846 ptr.name = symbol.name;
813 ptr.flags = symbol.flags;847 ptr.flags = symbol.flags;
814 if (symbol.flags.binding == .local) continue; // No participation in symbol resolution.848 if (symbol.flags.binding == .local) continue; // No participation in symbol resolution.
...@@ -818,35 +852,46 @@ pub fn parse(...@@ -818,35 +852,46 @@ pub fn parse(
818 if (gop.value_ptr.type != ptr.type_index) {852 if (gop.value_ptr.type != ptr.type_index) {
819 var err = try diags.addErrorWithNotes(2);853 var err = try diags.addErrorWithNotes(2);
820 try err.addMsg("function signature mismatch: {s}", .{name.slice(wasm)});854 try err.addMsg("function signature mismatch: {s}", .{name.slice(wasm)});
821 try err.addSrcNote(gop.value_ptr.source_location, "exported as {} here", .{ptr.type_index.fmt(wasm)});855 gop.value_ptr.source_location.addNote(wasm, &err, "exported as {} here", .{
822 const word = if (gop.value_ptr.resolution == .none) "imported" else "exported";856 ptr.type_index.fmt(wasm),
823 try err.addSrcNote(source_location, "{s} as {} here", .{ word, gop.value_ptr.type.fmt(wasm) });857 });
858 const word = if (gop.value_ptr.resolution == .unresolved) "imported" else "exported";
859 source_location.addNote(wasm, &err, "{s} as {} here", .{ word, gop.value_ptr.type.fmt(wasm) });
824 continue;860 continue;
825 }861 }
826 if (gop.value_ptr.resolution == .none or gop.value_ptr.flags.binding == .weak) {862 if (gop.value_ptr.resolution == .unresolved or gop.value_ptr.flags.binding == .weak) {
827 // Intentional: if they're both weak, take the last one.863 // Intentional: if they're both weak, take the last one.
828 gop.value_ptr.source_location = source_location;864 gop.value_ptr.source_location = source_location;
829 gop.value_ptr.module_name = host_name;865 gop.value_ptr.module_name = host_name;
830 gop.value_ptr.resolution = .fromObjectFunction(index);866 gop.value_ptr.resolution = .fromObjectFunction(wasm, index);
831 continue;867 continue;
832 }868 }
833 var err = try diags.addErrorWithNotes(2);869 var err = try diags.addErrorWithNotes(2);
834 try err.addMsg("symbol collision: {s}", .{name.slice(wasm)});870 try err.addMsg("symbol collision: {s}", .{name.slice(wasm)});
835 try err.addSrcNote(gop.value_ptr.source_location, "exported as {} here", .{ptr.type_index.fmt(wasm)});871 gop.value_ptr.source_location.addNote(wasm, &err, "exported as {} here", .{ptr.type_index.fmt(wasm)});
836 try err.addSrcNote(source_location, "exported as {} here", .{gop.value_ptr.type.fmt(wasm)});872 source_location.addNote(wasm, &err, "exported as {} here", .{gop.value_ptr.type.fmt(wasm)});
837 continue;873 continue;
838 } else {874 } else {
839 gop.value_ptr.* = .{875 gop.value_ptr.* = .{
840 .flags = symbol.flags,876 .flags = symbol.flags,
841 .module_name = host_name,877 .module_name = host_name,
842 .source_location = source_location,878 .source_location = source_location,
843 .resolution = .fromObjectFunction(index),879 .resolution = .fromObjectFunction(wasm, index),
844 .type = ptr.type_index,880 .type = ptr.type_index,
845 };881 };
846 }882 }
847 },883 },
848884
849 inline .global, .global_import, .table, .table_import => |i| {885 inline .global_import, .table_import => |i| {
886 const ptr = i.value(wasm);
887 assert(i.key(wasm).toOptional() == symbol.name); // TODO
888 ptr.flags = symbol.flags;
889 if (symbol.flags.undefined and symbol.flags.binding == .local) {
890 const name = i.key(wasm).slice(wasm);
891 diags.addParseError(path, "local symbol '{s}' references import", .{name});
892 }
893 },
894 inline .global, .table => |i| {
850 const ptr = i.ptr(wasm);895 const ptr = i.ptr(wasm);
851 ptr.name = symbol.name;896 ptr.name = symbol.name;
852 ptr.flags = symbol.flags;897 ptr.flags = symbol.flags;
...@@ -857,10 +902,11 @@ pub fn parse(...@@ -857,10 +902,11 @@ pub fn parse(
857 },902 },
858 .section => |i| {903 .section => |i| {
859 // Name is provided by the section directly; symbol table does not have it.904 // Name is provided by the section directly; symbol table does not have it.
860 const ptr = i.ptr(wasm);905 //const ptr = i.ptr(wasm);
861 ptr.flags = symbol.flags;906 //ptr.flags = symbol.flags;
907 _ = i;
862 if (symbol.flags.undefined and symbol.flags.binding == .local) {908 if (symbol.flags.undefined and symbol.flags.binding == .local) {
863 const name = ptr.name.slice(wasm);909 const name = symbol.name.slice(wasm).?;
864 diags.addParseError(path, "local symbol '{s}' references import", .{name});910 diags.addParseError(path, "local symbol '{s}' references import", .{name});
865 }911 }
866 },912 },
...@@ -868,15 +914,7 @@ pub fn parse(...@@ -868,15 +914,7 @@ pub fn parse(
868 const name = symbol.name.unwrap().?;914 const name = symbol.name.unwrap().?;
869 log.warn("TODO data import '{s}'", .{name.slice(wasm)});915 log.warn("TODO data import '{s}'", .{name.slice(wasm)});
870 },916 },
871 .data => |data| {917 .data => continue, // `wasm.object_datas` has already been populated.
872 const ptr = data.ptr(wasm);
873 const is_passive = ptr.flags.is_passive;
874 ptr.name = symbol.name;
875 ptr.flags = symbol.flags;
876 ptr.flags.is_passive = is_passive;
877 ptr.offset = data.segment_offset;
878 ptr.size = data.size;
879 },
880 };918 };
881919
882 // Apply export section info. This is done after the symbol table above so920 // Apply export section info. This is done after the symbol table above so
...@@ -957,18 +995,6 @@ pub fn parse(...@@ -957,18 +995,6 @@ pub fn parse(
957 .off = functions_start,995 .off = functions_start,
958 .len = @intCast(wasm.object_functions.items.len - functions_start),996 .len = @intCast(wasm.object_functions.items.len - functions_start),
959 },997 },
960 .globals = .{
961 .off = globals_start,
962 .len = @intCast(wasm.object_globals.items.len - globals_start),
963 },
964 .tables = .{
965 .off = tables_start,
966 .len = @intCast(wasm.object_tables.items.len - tables_start),
967 },
968 .memories = .{
969 .off = memories_start,
970 .len = @intCast(wasm.object_memories.items.len - memories_start),
971 },
972 .function_imports = .{998 .function_imports = .{
973 .off = function_imports_start,999 .off = function_imports_start,
974 .len = @intCast(wasm.object_function_imports.entries.len - function_imports_start),1000 .len = @intCast(wasm.object_function_imports.entries.len - function_imports_start),
...@@ -979,7 +1005,7 @@ pub fn parse(...@@ -979,7 +1005,7 @@ pub fn parse(
979 },1005 },
980 .table_imports = .{1006 .table_imports = .{
981 .off = table_imports_start,1007 .off = table_imports_start,
982 .len = @intCast(wasm.object_table_imports.items.len - table_imports_start),1008 .len = @intCast(wasm.object_table_imports.entries.len - table_imports_start),
983 },1009 },
984 .init_funcs = .{1010 .init_funcs = .{
985 .off = init_funcs_start,1011 .off = init_funcs_start,