| author | |
| committer | |
| log | 1a4c5837fedcad57f6c81301672e6246e0f0a8c1 |
| tree | 97b7b1b10d130d96cb93d7b28c88ad00971e0e1d |
| parent | 4b9dc2922ff0c5d873971f6f6f25db709df21cc0 |
10 files changed, 514 insertions(+), 369 deletions(-)
src/link.zig+3-6| ... | ... | @@ -97,15 +97,12 @@ pub const Diags = struct { |
| 97 | 97 | err_msg.msg = try std.fmt.allocPrint(gpa, format, args); |
| 98 | 98 | } |
| 99 | 99 | |
| 100 | pub fn addNote( | |
| 101 | err: *ErrorWithNotes, | |
| 102 | comptime format: []const u8, | |
| 103 | args: anytype, | |
| 104 | ) error{OutOfMemory}!void { | |
| 100 | pub fn addNote(err: *ErrorWithNotes, comptime format: []const u8, args: anytype) void { | |
| 105 | 101 | const gpa = err.diags.gpa; |
| 102 | const msg = std.fmt.allocPrint(gpa, format, args) catch return err.diags.setAllocFailure(); | |
| 106 | 103 | const err_msg = &err.diags.msgs.items[err.index]; |
| 107 | 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 | 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 | 3394 | // TODO verify `getMaxNumberOfPhdrs()` is accurate and convert this into no-op |
| 3395 | 3395 | var err = try diags.addErrorWithNotes(1); |
| 3396 | 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 | } |
| 3399 | 3399 | |
| 3400 | 3400 | phdr_table_load.p_filesz = needed_size + ehsize; |
| ... | ... | @@ -4545,12 +4545,12 @@ fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void { |
| 4545 | 4545 | for (refs.items[0..nrefs]) |ref| { |
| 4546 | 4546 | const atom_ptr = self.atom(ref).?; |
| 4547 | 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 | } |
| 4550 | 4550 | |
| 4551 | 4551 | if (refs.items.len > max_notes) { |
| 4552 | 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 | 4567 | |
| 4568 | 4568 | var err = try diags.addErrorWithNotes(nnotes + 1); |
| 4569 | 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()}); | |
| 4571 | 4571 | |
| 4572 | 4572 | var inote: usize = 0; |
| 4573 | 4573 | while (inote < @min(notes.items.len, max_notes)) : (inote += 1) { |
| 4574 | 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 | } |
| 4577 | 4577 | |
| 4578 | 4578 | if (notes.items.len > max_notes) { |
| 4579 | 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 | } |
| 4583 | 4583 | |
| ... | ... | @@ -4601,7 +4601,7 @@ pub fn addFileError( |
| 4601 | 4601 | const diags = &self.base.comp.link_diags; |
| 4602 | 4602 | var err = try diags.addErrorWithNotes(1); |
| 4603 | 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 | } |
| 4606 | 4606 | |
| 4607 | 4607 | pub 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 | 523 | relocation.fmtRelocType(rel.r_type(), elf_file.getTarget().cpu.arch), |
| 524 | 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 | 527 | return error.RelocFailure; |
| 528 | 528 | } |
| 529 | 529 | |
| ... | ... | @@ -539,7 +539,7 @@ fn reportTextRelocError( |
| 539 | 539 | rel.r_offset, |
| 540 | 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 | 543 | return error.RelocFailure; |
| 544 | 544 | } |
| 545 | 545 | |
| ... | ... | @@ -555,8 +555,8 @@ fn reportPicError( |
| 555 | 555 | rel.r_offset, |
| 556 | 556 | symbol.name(elf_file), |
| 557 | 557 | }); |
| 558 | try err.addNote("in {}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) }); | |
| 559 | try err.addNote("recompile with -fPIC", .{}); | |
| 558 | err.addNote("in {}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) }); | |
| 559 | err.addNote("recompile with -fPIC", .{}); | |
| 560 | 560 | return error.RelocFailure; |
| 561 | 561 | } |
| 562 | 562 | |
| ... | ... | @@ -572,8 +572,8 @@ fn reportNoPicError( |
| 572 | 572 | rel.r_offset, |
| 573 | 573 | symbol.name(elf_file), |
| 574 | 574 | }); |
| 575 | try err.addNote("in {}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) }); | |
| 576 | try err.addNote("recompile with -fno-PIC", .{}); | |
| 575 | err.addNote("in {}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) }); | |
| 576 | err.addNote("recompile with -fno-PIC", .{}); | |
| 577 | 577 | return error.RelocFailure; |
| 578 | 578 | } |
| 579 | 579 | |
| ... | ... | @@ -1187,7 +1187,7 @@ const x86_64 = struct { |
| 1187 | 1187 | x86_64.relaxGotPcTlsDesc(code[r_offset - 3 ..]) catch { |
| 1188 | 1188 | var err = try diags.addErrorWithNotes(1); |
| 1189 | 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 | 1191 | atom.file(elf_file).?.fmtPath(), |
| 1192 | 1192 | atom.name(elf_file), |
| 1193 | 1193 | rel.r_offset, |
| ... | ... | @@ -1332,7 +1332,7 @@ const x86_64 = struct { |
| 1332 | 1332 | relocation.fmtRelocType(rels[0].r_type(), .x86_64), |
| 1333 | 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 | 1336 | self.file(elf_file).?.fmtPath(), |
| 1337 | 1337 | self.name(elf_file), |
| 1338 | 1338 | rels[0].r_offset, |
| ... | ... | @@ -1388,7 +1388,7 @@ const x86_64 = struct { |
| 1388 | 1388 | relocation.fmtRelocType(rels[0].r_type(), .x86_64), |
| 1389 | 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 | 1392 | self.file(elf_file).?.fmtPath(), |
| 1393 | 1393 | self.name(elf_file), |
| 1394 | 1394 | rels[0].r_offset, |
| ... | ... | @@ -1485,7 +1485,7 @@ const x86_64 = struct { |
| 1485 | 1485 | relocation.fmtRelocType(rels[0].r_type(), .x86_64), |
| 1486 | 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 | 1489 | self.file(elf_file).?.fmtPath(), |
| 1490 | 1490 | self.name(elf_file), |
| 1491 | 1491 | rels[0].r_offset, |
| ... | ... | @@ -1672,7 +1672,7 @@ const aarch64 = struct { |
| 1672 | 1672 | // TODO: relax |
| 1673 | 1673 | var err = try diags.addErrorWithNotes(1); |
| 1674 | 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 | 1676 | atom.file(elf_file).?.fmtPath(), |
| 1677 | 1677 | atom.name(elf_file), |
| 1678 | 1678 | r_offset, |
| ... | ... | @@ -1959,7 +1959,7 @@ const riscv = struct { |
| 1959 | 1959 | // TODO: implement searching forward |
| 1960 | 1960 | var err = try diags.addErrorWithNotes(1); |
| 1961 | 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 | 1963 | atom.file(elf_file).?.fmtPath(), |
| 1964 | 1964 | atom.name(elf_file), |
| 1965 | 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 | 797 | if (!isNull(data[end .. end + sh_entsize])) { |
| 798 | 798 | var err = try diags.addErrorWithNotes(1); |
| 799 | 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 | 801 | return error.LinkFailure; |
| 802 | 802 | } |
| 803 | 803 | end += sh_entsize; |
| ... | ... | @@ -812,7 +812,7 @@ pub fn initInputMergeSections(self: *Object, elf_file: *Elf) !void { |
| 812 | 812 | if (shdr.sh_size % sh_entsize != 0) { |
| 813 | 813 | var err = try diags.addErrorWithNotes(1); |
| 814 | 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 | 816 | return error.LinkFailure; |
| 817 | 817 | } |
| 818 | 818 | |
| ... | ... | @@ -889,8 +889,8 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) error{ |
| 889 | 889 | const res = imsec.findSubsection(@intCast(esym.st_value)) orelse { |
| 890 | 890 | var err = try diags.addErrorWithNotes(2); |
| 891 | 891 | try err.addMsg("invalid symbol value: {x}", .{esym.st_value}); |
| 892 | try err.addNote("for symbol {s}", .{sym.name(elf_file)}); | |
| 893 | try err.addNote("in {}", .{self.fmtPath()}); | |
| 892 | err.addNote("for symbol {s}", .{sym.name(elf_file)}); | |
| 893 | err.addNote("in {}", .{self.fmtPath()}); | |
| 894 | 894 | return error.LinkFailure; |
| 895 | 895 | }; |
| 896 | 896 | |
| ... | ... | @@ -915,7 +915,7 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) error{ |
| 915 | 915 | const res = imsec.findSubsection(@intCast(@as(i64, @intCast(esym.st_value)) + rel.r_addend)) orelse { |
| 916 | 916 | var err = try diags.addErrorWithNotes(1); |
| 917 | 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 | 919 | return error.LinkFailure; |
| 920 | 920 | }; |
| 921 | 921 |
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 | 611 | relocation.fmtRelocType(rel.r_type(), elf_file.getTarget().cpu.arch), |
| 612 | 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 | 615 | return error.RelocFailure; |
| 616 | 616 | } |
| 617 | 617 |
src/link/MachO.zig+16-16| ... | ... | @@ -1572,21 +1572,21 @@ fn reportUndefs(self: *MachO) !void { |
| 1572 | 1572 | try err.addMsg("undefined symbol: {s}", .{undef_sym.getName(self)}); |
| 1573 | 1573 | |
| 1574 | 1574 | switch (notes) { |
| 1575 | .force_undefined => try err.addNote("referenced with linker flag -u", .{}), | |
| 1576 | .entry => try err.addNote("referenced with linker flag -e", .{}), | |
| 1577 | .dyld_stub_binder, .objc_msgsend => try err.addNote("referenced implicitly", .{}), | |
| 1575 | .force_undefined => err.addNote("referenced with linker flag -u", .{}), | |
| 1576 | .entry => err.addNote("referenced with linker flag -e", .{}), | |
| 1577 | .dyld_stub_binder, .objc_msgsend => err.addNote("referenced implicitly", .{}), | |
| 1578 | 1578 | .refs => |refs| { |
| 1579 | 1579 | var inote: usize = 0; |
| 1580 | 1580 | while (inote < @min(refs.items.len, max_notes)) : (inote += 1) { |
| 1581 | 1581 | const ref = refs.items[inote]; |
| 1582 | 1582 | const file = self.getFile(ref.file).?; |
| 1583 | 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 | } |
| 1586 | 1586 | |
| 1587 | 1587 | if (refs.items.len > max_notes) { |
| 1588 | 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 | 3473 | seg_id, |
| 3474 | 3474 | seg.segName(), |
| 3475 | 3475 | }); |
| 3476 | try 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", .{}); | |
| 3476 | err.addNote("TODO: emit relocations to memory locations in self-hosted backends", .{}); | |
| 3477 | err.addNote("as a workaround, try increasing pre-allocated virtual memory of each segment", .{}); | |
| 3478 | 3478 | } |
| 3479 | 3479 | |
| 3480 | 3480 | seg.vmsize = needed_size; |
| ... | ... | @@ -3776,7 +3776,7 @@ pub fn reportParseError2( |
| 3776 | 3776 | const diags = &self.base.comp.link_diags; |
| 3777 | 3777 | var err = try diags.addErrorWithNotes(1); |
| 3778 | 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 | } |
| 3781 | 3781 | |
| 3782 | 3782 | fn reportMissingDependencyError( |
| ... | ... | @@ -3790,10 +3790,10 @@ fn reportMissingDependencyError( |
| 3790 | 3790 | const diags = &self.base.comp.link_diags; |
| 3791 | 3791 | var err = try diags.addErrorWithNotes(2 + checked_paths.len); |
| 3792 | 3792 | try err.addMsg(format, args); |
| 3793 | try err.addNote("while resolving {s}", .{path}); | |
| 3794 | try err.addNote("a dependency of {}", .{self.getFile(parent).?.fmtPath()}); | |
| 3793 | err.addNote("while resolving {s}", .{path}); | |
| 3794 | err.addNote("a dependency of {}", .{self.getFile(parent).?.fmtPath()}); | |
| 3795 | 3795 | for (checked_paths) |p| { |
| 3796 | try err.addNote("tried {s}", .{p}); | |
| 3796 | err.addNote("tried {s}", .{p}); | |
| 3797 | 3797 | } |
| 3798 | 3798 | } |
| 3799 | 3799 | |
| ... | ... | @@ -3807,8 +3807,8 @@ fn reportDependencyError( |
| 3807 | 3807 | const diags = &self.base.comp.link_diags; |
| 3808 | 3808 | var err = try diags.addErrorWithNotes(2); |
| 3809 | 3809 | try err.addMsg(format, args); |
| 3810 | try err.addNote("while parsing {s}", .{path}); | |
| 3811 | try err.addNote("a dependency of {}", .{self.getFile(parent).?.fmtPath()}); | |
| 3810 | err.addNote("while parsing {s}", .{path}); | |
| 3811 | err.addNote("a dependency of {}", .{self.getFile(parent).?.fmtPath()}); | |
| 3812 | 3812 | } |
| 3813 | 3813 | |
| 3814 | 3814 | fn reportDuplicates(self: *MachO) error{ HasDuplicates, OutOfMemory }!void { |
| ... | ... | @@ -3838,17 +3838,17 @@ fn reportDuplicates(self: *MachO) error{ HasDuplicates, OutOfMemory }!void { |
| 3838 | 3838 | |
| 3839 | 3839 | var err = try diags.addErrorWithNotes(nnotes + 1); |
| 3840 | 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()}); | |
| 3842 | 3842 | |
| 3843 | 3843 | var inote: usize = 0; |
| 3844 | 3844 | while (inote < @min(notes.items.len, max_notes)) : (inote += 1) { |
| 3845 | 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 | } |
| 3848 | 3848 | |
| 3849 | 3849 | if (notes.items.len > max_notes) { |
| 3850 | 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 | 3854 | return error.HasDuplicates; |
src/link/MachO/Atom.zig+2-2| ... | ... | @@ -909,8 +909,8 @@ const x86_64 = struct { |
| 909 | 909 | rel.offset, |
| 910 | 910 | rel.fmtPretty(.x86_64), |
| 911 | 911 | }); |
| 912 | try err.addNote("expected .mov instruction but found .{s}", .{@tagName(x)}); | |
| 913 | try err.addNote("while parsing {}", .{self.getFile(macho_file).fmtPath()}); | |
| 912 | err.addNote("expected .mov instruction but found .{s}", .{@tagName(x)}); | |
| 913 | err.addNote("while parsing {}", .{self.getFile(macho_file).fmtPath()}); | |
| 914 | 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 | 109 | /// All memory imports for all objects. |
| 110 | 110 | object_memory_imports: std.ArrayListUnmanaged(MemoryImport) = .empty, |
| 111 | 111 | /// All parsed memory sections for all objects. |
| 112 | object_memories: std.ArrayListUnmanaged(std.wasm.Memory) = .empty, | |
| 112 | object_memories: std.ArrayListUnmanaged(ObjectMemory) = .empty, | |
| 113 | 113 | |
| 114 | 114 | /// All relocations from all objects concatenated. `relocs_start` marks the end |
| 115 | 115 | /// point of object relocations and start point of Zcu relocations. |
| ... | ... | @@ -119,8 +119,13 @@ object_relocations: std.MultiArrayList(ObjectRelocation) = .empty, |
| 119 | 119 | /// by the (synthetic) __wasm_call_ctors function. |
| 120 | 120 | object_init_funcs: std.ArrayListUnmanaged(InitFunc) = .empty, |
| 121 | 121 | |
| 122 | /// Non-synthetic section that can essentially be mem-cpy'd into place after performing relocations. | |
| 123 | object_data_segments: std.ArrayListUnmanaged(DataSegment) = .empty, | |
| 122 | /// The data section of an object has many segments. Each segment corresponds | |
| 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. | |
| 125 | object_data_segments: std.ArrayListUnmanaged(ObjectDataSegment) = .empty, | |
| 126 | /// Each segment has many data symbols. These correspond logically to global | |
| 127 | /// constants. | |
| 128 | object_datas: std.ArrayListUnmanaged(ObjectData) = .empty, | |
| 124 | 129 | /// Non-synthetic section that can essentially be mem-cpy'd into place after performing relocations. |
| 125 | 130 | object_custom_segments: std.AutoArrayHashMapUnmanaged(ObjectSectionIndex, CustomSegment) = .empty, |
| 126 | 131 | |
| ... | ... | @@ -457,6 +462,21 @@ pub const SourceLocation = enum(u32) { |
| 457 | 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 | }; |
| 461 | 481 | |
| 462 | 482 | /// The lower bits of this ABI-match the flags here: |
| ... | ... | @@ -687,13 +707,13 @@ pub const UavsExeIndex = enum(u32) { |
| 687 | 707 | |
| 688 | 708 | /// Used when emitting a relocatable object. |
| 689 | 709 | pub const ZcuDataObj = extern struct { |
| 690 | code: DataSegment.Payload, | |
| 710 | code: DataPayload, | |
| 691 | 711 | relocs: OutReloc.Slice, |
| 692 | 712 | }; |
| 693 | 713 | |
| 694 | 714 | /// Used when not emitting a relocatable object. |
| 695 | 715 | pub const ZcuDataExe = extern struct { |
| 696 | code: DataSegment.Payload, | |
| 716 | code: DataPayload, | |
| 697 | 717 | /// Tracks how many references there are for the purposes of sorting data segments. |
| 698 | 718 | count: u32, |
| 699 | 719 | }; |
| ... | ... | @@ -917,6 +937,10 @@ pub const FunctionImport = extern struct { |
| 917 | 937 | return pack(wasm, .{ .zcu_func = @enumFromInt(wasm.zcu_funcs.getIndex(ip_index).?) }); |
| 918 | 938 | } |
| 919 | 939 | |
| 940 | pub fn fromObjectFunction(wasm: *const Wasm, object_function: ObjectFunctionIndex) Resolution { | |
| 941 | return pack(wasm, .{ .object_function = object_function }); | |
| 942 | } | |
| 943 | ||
| 920 | 944 | pub fn isNavOrUnresolved(r: Resolution, wasm: *const Wasm) bool { |
| 921 | 945 | return switch (r.unpack(wasm)) { |
| 922 | 946 | .unresolved, .zcu_func => true, |
| ... | ... | @@ -988,7 +1012,7 @@ pub const Function = extern struct { |
| 988 | 1012 | section_index: ObjectSectionIndex, |
| 989 | 1013 | source_location: SourceLocation, |
| 990 | 1014 | |
| 991 | pub const Code = DataSegment.Payload; | |
| 1015 | pub const Code = DataPayload; | |
| 992 | 1016 | }; |
| 993 | 1017 | |
| 994 | 1018 | pub const GlobalImport = extern struct { |
| ... | ... | @@ -1283,12 +1307,30 @@ pub const ObjectGlobalIndex = enum(u32) { |
| 1283 | 1307 | } |
| 1284 | 1308 | }; |
| 1285 | 1309 | |
| 1286 | /// Index into `Wasm.object_memories`. | |
| 1287 | pub const ObjectMemoryIndex = enum(u32) { | |
| 1288 | _, | |
| 1310 | pub const ObjectMemory = extern struct { | |
| 1311 | flags: SymbolFlags, | |
| 1312 | name: OptionalString, | |
| 1313 | limits_min: u32, | |
| 1314 | limits_max: u32, | |
| 1289 | 1315 | |
| 1290 | pub fn ptr(index: ObjectMemoryIndex, wasm: *const Wasm) *std.wasm.Memory { | |
| 1291 | return &wasm.object_memories.items[@intFromEnum(index)]; | |
| 1316 | /// Index into `Wasm.object_memories`. | |
| 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 | }; |
| 1294 | 1336 | |
| ... | ... | @@ -1318,14 +1360,74 @@ pub const OptionalObjectFunctionIndex = enum(u32) { |
| 1318 | 1360 | } |
| 1319 | 1361 | }; |
| 1320 | 1362 | |
| 1321 | pub const DataSegment = extern struct { | |
| 1363 | pub 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. | |
| 1380 | pub 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 | 1386 | /// `none` if no symbol describes it. |
| 1323 | 1387 | name: OptionalString, |
| 1324 | 1388 | flags: SymbolFlags, |
| 1325 | payload: Payload, | |
| 1326 | /// From the data segment start to the first byte of payload. | |
| 1327 | segment_offset: u32, | |
| 1328 | section_index: ObjectSectionIndex, | |
| 1389 | ||
| 1390 | /// Index into `Wasm.object_datas`. | |
| 1391 | pub const Index = enum(u32) { | |
| 1392 | _, | |
| 1393 | ||
| 1394 | pub fn ptr(i: Index, wasm: *const Wasm) *ObjectData { | |
| 1395 | return &wasm.object_datas.items[@intFromEnum(i)]; | |
| 1396 | } | |
| 1397 | }; | |
| 1398 | }; | |
| 1399 | ||
| 1400 | pub 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. | |
| 1422 | pub 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; | |
| 1329 | 1431 | |
| 1330 | 1432 | pub const Category = enum { |
| 1331 | 1433 | /// Thread-local variables. |
| ... | ... | @@ -1337,221 +1439,180 @@ pub const DataSegment = extern struct { |
| 1337 | 1439 | zero, |
| 1338 | 1440 | }; |
| 1339 | 1441 | |
| 1340 | pub const Payload = extern struct { | |
| 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) { | |
| 1442 | pub const Unpacked = union(enum) { | |
| 1362 | 1443 | __zig_error_names, |
| 1363 | 1444 | __zig_error_name_table, |
| 1364 | /// First, an `ObjectDataSegmentIndex`. | |
| 1365 | /// Next, index into `uavs_obj` or `uavs_exe` depending on whether emitting an object. | |
| 1366 | /// Next, index into `navs_obj` or `navs_exe` depending on whether emitting an object. | |
| 1367 | _, | |
| 1368 | ||
| 1369 | const first_object = @intFromEnum(Id.__zig_error_name_table) + 1; | |
| 1445 | object: ObjectDataSegment.Index, | |
| 1446 | uav_exe: UavsExeIndex, | |
| 1447 | uav_obj: UavsObjIndex, | |
| 1448 | nav_exe: NavsExeIndex, | |
| 1449 | nav_obj: NavsObjIndex, | |
| 1450 | }; | |
| 1370 | 1451 | |
| 1371 | pub const Unpacked = union(enum) { | |
| 1372 | __zig_error_names, | |
| 1373 | __zig_error_name_table, | |
| 1374 | object: ObjectDataSegmentIndex, | |
| 1375 | uav_exe: UavsExeIndex, | |
| 1376 | uav_obj: UavsObjIndex, | |
| 1377 | nav_exe: NavsExeIndex, | |
| 1378 | nav_obj: NavsObjIndex, | |
| 1452 | pub fn pack(wasm: *const Wasm, unpacked: Unpacked) DataId { | |
| 1453 | return switch (unpacked) { | |
| 1454 | .__zig_error_names => .__zig_error_names, | |
| 1455 | .__zig_error_name_table => .__zig_error_name_table, | |
| 1456 | .object => |i| @enumFromInt(first_object + @intFromEnum(i)), | |
| 1457 | inline .uav_exe, .uav_obj => |i| @enumFromInt(first_object + wasm.object_data_segments.items.len + @intFromEnum(i)), | |
| 1458 | .nav_exe => |i| @enumFromInt(first_object + wasm.object_data_segments.items.len + wasm.uavs_exe.entries.len + @intFromEnum(i)), | |
| 1459 | .nav_obj => |i| @enumFromInt(first_object + wasm.object_data_segments.items.len + wasm.uavs_obj.entries.len + @intFromEnum(i)), | |
| 1379 | 1460 | }; |
| 1461 | } | |
| 1380 | 1462 | |
| 1381 | pub fn pack(wasm: *const Wasm, unpacked: Unpacked) Id { | |
| 1382 | return switch (unpacked) { | |
| 1383 | .__zig_error_names => .__zig_error_names, | |
| 1384 | .__zig_error_name_table => .__zig_error_name_table, | |
| 1385 | .object => |i| @enumFromInt(first_object + @intFromEnum(i)), | |
| 1386 | inline .uav_exe, .uav_obj => |i| @enumFromInt(first_object + wasm.object_data_segments.items.len + @intFromEnum(i)), | |
| 1387 | .nav_exe => |i| @enumFromInt(first_object + wasm.object_data_segments.items.len + wasm.uavs_exe.entries.len + @intFromEnum(i)), | |
| 1388 | .nav_obj => |i| @enumFromInt(first_object + wasm.object_data_segments.items.len + wasm.uavs_obj.entries.len + @intFromEnum(i)), | |
| 1389 | }; | |
| 1390 | } | |
| 1391 | ||
| 1392 | pub fn unpack(id: Id, wasm: *const Wasm) Unpacked { | |
| 1393 | return switch (id) { | |
| 1394 | .__zig_error_names => .__zig_error_names, | |
| 1395 | .__zig_error_name_table => .__zig_error_name_table, | |
| 1396 | _ => { | |
| 1397 | const object_index = @intFromEnum(id) - first_object; | |
| 1398 | ||
| 1399 | const uav_index = if (object_index < wasm.object_data_segments.items.len) | |
| 1400 | return .{ .object = @enumFromInt(object_index) } | |
| 1463 | pub fn unpack(id: DataId, wasm: *const Wasm) Unpacked { | |
| 1464 | return switch (id) { | |
| 1465 | .__zig_error_names => .__zig_error_names, | |
| 1466 | .__zig_error_name_table => .__zig_error_name_table, | |
| 1467 | _ => { | |
| 1468 | const object_index = @intFromEnum(id) - first_object; | |
| 1469 | ||
| 1470 | const uav_index = if (object_index < wasm.object_data_segments.items.len) | |
| 1471 | return .{ .object = @enumFromInt(object_index) } | |
| 1472 | else | |
| 1473 | object_index - wasm.object_data_segments.items.len; | |
| 1474 | ||
| 1475 | const comp = wasm.base.comp; | |
| 1476 | const is_obj = comp.config.output_mode == .Obj; | |
| 1477 | if (is_obj) { | |
| 1478 | const nav_index = if (uav_index < wasm.uavs_obj.entries.len) | |
| 1479 | return .{ .uav_obj = @enumFromInt(uav_index) } | |
| 1401 | 1480 | else |
| 1402 | object_index - wasm.object_data_segments.items.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 | } | |
| 1481 | uav_index - wasm.uavs_obj.entries.len; | |
| 1424 | 1482 | |
| 1425 | pub fn category(id: Id, wasm: *const Wasm) Category { | |
| 1426 | return switch (unpack(id, wasm)) { | |
| 1427 | .__zig_error_names, .__zig_error_name_table => .data, | |
| 1428 | .object => |i| { | |
| 1429 | const ptr = i.ptr(wasm); | |
| 1430 | if (ptr.flags.tls) return .tls; | |
| 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 | } | |
| 1483 | return .{ .nav_obj = @enumFromInt(nav_index) }; | |
| 1484 | } else { | |
| 1485 | const nav_index = if (uav_index < wasm.uavs_exe.entries.len) | |
| 1486 | return .{ .uav_exe = @enumFromInt(uav_index) } | |
| 1487 | else | |
| 1488 | uav_index - wasm.uavs_exe.entries.len; | |
| 1445 | 1489 | |
| 1446 | pub fn isTls(id: Id, wasm: *const Wasm) bool { | |
| 1447 | return switch (unpack(id, wasm)) { | |
| 1448 | .__zig_error_names, .__zig_error_name_table => false, | |
| 1449 | .object => |i| i.ptr(wasm).flags.tls, | |
| 1450 | .uav_exe, .uav_obj => false, | |
| 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 | } | |
| 1490 | return .{ .nav_exe = @enumFromInt(nav_index) }; | |
| 1491 | } | |
| 1492 | }, | |
| 1493 | }; | |
| 1494 | } | |
| 1459 | 1495 | |
| 1460 | pub fn isBss(id: Id, wasm: *const Wasm) bool { | |
| 1461 | return id.category(wasm) == .zero; | |
| 1462 | } | |
| 1496 | pub fn category(id: DataId, wasm: *const Wasm) Category { | |
| 1497 | return switch (unpack(id, wasm)) { | |
| 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 | } | |
| 1463 | 1516 | |
| 1464 | pub fn name(id: Id, wasm: *const Wasm) []const u8 { | |
| 1465 | return switch (unpack(id, wasm)) { | |
| 1466 | .__zig_error_names, .__zig_error_name_table, .uav_exe, .uav_obj => ".data", | |
| 1467 | .object => |i| i.ptr(wasm).name.unwrap().?.slice(wasm), | |
| 1468 | inline .nav_exe, .nav_obj => |i| { | |
| 1469 | const zcu = wasm.base.comp.zcu.?; | |
| 1470 | const ip = &zcu.intern_pool; | |
| 1471 | const nav = ip.getNav(i.key(wasm).*); | |
| 1472 | return nav.status.resolved.@"linksection".toSlice(ip) orelse ".data"; | |
| 1473 | }, | |
| 1474 | }; | |
| 1475 | } | |
| 1517 | pub fn isTls(id: DataId, wasm: *const Wasm) bool { | |
| 1518 | return switch (unpack(id, wasm)) { | |
| 1519 | .__zig_error_names, .__zig_error_name_table => false, | |
| 1520 | .object => |i| i.ptr(wasm).flags.tls, | |
| 1521 | .uav_exe, .uav_obj => false, | |
| 1522 | inline .nav_exe, .nav_obj => |i| { | |
| 1523 | const zcu = wasm.base.comp.zcu.?; | |
| 1524 | const ip = &zcu.intern_pool; | |
| 1525 | const nav = ip.getNav(i.key(wasm).*); | |
| 1526 | return nav.isThreadLocal(ip); | |
| 1527 | }, | |
| 1528 | }; | |
| 1529 | } | |
| 1476 | 1530 | |
| 1477 | pub fn alignment(id: Id, wasm: *const Wasm) Alignment { | |
| 1478 | return switch (unpack(id, wasm)) { | |
| 1479 | .__zig_error_names => .@"1", | |
| 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 | } | |
| 1531 | pub fn isBss(id: DataId, wasm: *const Wasm) bool { | |
| 1532 | return id.category(wasm) == .zero; | |
| 1533 | } | |
| 1504 | 1534 | |
| 1505 | pub fn refCount(id: Id, wasm: *const Wasm) u32 { | |
| 1506 | return switch (unpack(id, wasm)) { | |
| 1507 | .__zig_error_names => @intCast(wasm.error_name_offs.items.len), | |
| 1508 | .__zig_error_name_table => wasm.error_name_table_ref_count, | |
| 1509 | .object, .uav_obj, .nav_obj => 0, | |
| 1510 | inline .uav_exe, .nav_exe => |i| i.value(wasm).count, | |
| 1511 | }; | |
| 1512 | } | |
| 1535 | pub fn name(id: DataId, wasm: *const Wasm) []const u8 { | |
| 1536 | return switch (unpack(id, wasm)) { | |
| 1537 | .__zig_error_names, .__zig_error_name_table, .uav_exe, .uav_obj => ".data", | |
| 1538 | .object => |i| i.ptr(wasm).name.unwrap().?.slice(wasm), | |
| 1539 | inline .nav_exe, .nav_obj => |i| { | |
| 1540 | const zcu = wasm.base.comp.zcu.?; | |
| 1541 | const ip = &zcu.intern_pool; | |
| 1542 | const nav = ip.getNav(i.key(wasm).*); | |
| 1543 | return nav.status.resolved.@"linksection".toSlice(ip) orelse ".data"; | |
| 1544 | }, | |
| 1545 | }; | |
| 1546 | } | |
| 1513 | 1547 | |
| 1514 | pub fn isPassive(id: Id, wasm: *const Wasm) bool { | |
| 1515 | const comp = wasm.base.comp; | |
| 1516 | if (comp.config.import_memory and !id.isBss(wasm)) return true; | |
| 1517 | return switch (unpack(id, wasm)) { | |
| 1518 | .__zig_error_names, .__zig_error_name_table => false, | |
| 1519 | .object => |i| i.ptr(wasm).flags.is_passive, | |
| 1520 | .uav_exe, .uav_obj, .nav_exe, .nav_obj => false, | |
| 1521 | }; | |
| 1522 | } | |
| 1548 | pub fn alignment(id: DataId, wasm: *const Wasm) Alignment { | |
| 1549 | return switch (unpack(id, wasm)) { | |
| 1550 | .__zig_error_names => .@"1", | |
| 1551 | .__zig_error_name_table => wasm.pointerAlignment(), | |
| 1552 | .object => |i| i.ptr(wasm).flags.alignment, | |
| 1553 | inline .uav_exe, .uav_obj => |i| { | |
| 1554 | const zcu = wasm.base.comp.zcu.?; | |
| 1555 | const ip = &zcu.intern_pool; | |
| 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 | } | |
| 1523 | 1575 | |
| 1524 | pub fn isEmpty(id: Id, wasm: *const Wasm) bool { | |
| 1525 | return switch (unpack(id, wasm)) { | |
| 1526 | .__zig_error_names, .__zig_error_name_table => false, | |
| 1527 | .object => |i| i.ptr(wasm).payload.off == .none, | |
| 1528 | inline .uav_exe, .uav_obj, .nav_exe, .nav_obj => |i| i.value(wasm).code.off == .none, | |
| 1529 | }; | |
| 1530 | } | |
| 1576 | pub fn refCount(id: DataId, wasm: *const Wasm) u32 { | |
| 1577 | return switch (unpack(id, wasm)) { | |
| 1578 | .__zig_error_names => @intCast(wasm.error_name_offs.items.len), | |
| 1579 | .__zig_error_name_table => wasm.error_name_table_ref_count, | |
| 1580 | .object, .uav_obj, .nav_obj => 0, | |
| 1581 | inline .uav_exe, .nav_exe => |i| i.value(wasm).count, | |
| 1582 | }; | |
| 1583 | } | |
| 1531 | 1584 | |
| 1532 | pub fn size(id: Id, wasm: *const Wasm) u32 { | |
| 1533 | return switch (unpack(id, wasm)) { | |
| 1534 | .__zig_error_names => @intCast(wasm.error_name_bytes.items.len), | |
| 1535 | .__zig_error_name_table => { | |
| 1536 | const comp = wasm.base.comp; | |
| 1537 | const zcu = comp.zcu.?; | |
| 1538 | const errors_len = wasm.error_name_offs.items.len; | |
| 1539 | const elem_size = ZcuType.slice_const_u8_sentinel_0.abiSize(zcu); | |
| 1540 | return @intCast(errors_len * elem_size); | |
| 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 | }; | |
| 1585 | pub fn isPassive(id: DataId, wasm: *const Wasm) bool { | |
| 1586 | const comp = wasm.base.comp; | |
| 1587 | if (comp.config.import_memory and !id.isBss(wasm)) return true; | |
| 1588 | return switch (unpack(id, wasm)) { | |
| 1589 | .__zig_error_names, .__zig_error_name_table => false, | |
| 1590 | .object => |i| i.ptr(wasm).flags.is_passive, | |
| 1591 | .uav_exe, .uav_obj, .nav_exe, .nav_obj => false, | |
| 1592 | }; | |
| 1593 | } | |
| 1548 | 1594 | |
| 1549 | /// Index into `Wasm.object_data_segments`. | |
| 1550 | pub const ObjectDataSegmentIndex = enum(u32) { | |
| 1551 | _, | |
| 1595 | pub fn isEmpty(id: DataId, wasm: *const Wasm) bool { | |
| 1596 | return switch (unpack(id, wasm)) { | |
| 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 | } | |
| 1552 | 1602 | |
| 1553 | pub fn ptr(i: ObjectDataSegmentIndex, wasm: *const Wasm) *DataSegment { | |
| 1554 | return &wasm.object_data_segments.items[@intFromEnum(i)]; | |
| 1603 | pub fn size(id: DataId, wasm: *const Wasm) u32 { | |
| 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 | }; |
| 1557 | 1618 | |
| ... | ... | @@ -1565,7 +1626,7 @@ pub const CustomSegment = extern struct { |
| 1565 | 1626 | flags: SymbolFlags, |
| 1566 | 1627 | section_name: String, |
| 1567 | 1628 | |
| 1568 | pub const Payload = DataSegment.Payload; | |
| 1629 | pub const Payload = DataPayload; | |
| 1569 | 1630 | }; |
| 1570 | 1631 | |
| 1571 | 1632 | /// An index into string_bytes where a wasm expression is found. |
| ... | ... | @@ -1591,9 +1652,13 @@ pub const FunctionType = extern struct { |
| 1591 | 1652 | pub const Index = enum(u32) { |
| 1592 | 1653 | _, |
| 1593 | 1654 | |
| 1594 | pub fn ptr(i: FunctionType.Index, wasm: *const Wasm) *FunctionType { | |
| 1655 | pub fn ptr(i: Index, wasm: *const Wasm) *FunctionType { | |
| 1595 | 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 | }; |
| 1598 | 1663 | |
| 1599 | 1664 | pub const format = @compileError("can't format without *Wasm reference"); |
| ... | ... | @@ -1601,6 +1666,46 @@ pub const FunctionType = extern struct { |
| 1601 | 1666 | pub fn eql(a: FunctionType, b: FunctionType) bool { |
| 1602 | 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 | }; |
| 1605 | 1710 | |
| 1606 | 1711 | /// Represents a function entry, holding the index to its type |
| ... | ... | @@ -1955,7 +2060,7 @@ pub const ObjectRelocation = struct { |
| 1955 | 2060 | symbol_name: String, |
| 1956 | 2061 | type_index: FunctionType.Index, |
| 1957 | 2062 | section: ObjectSectionIndex, |
| 1958 | data_segment: ObjectDataSegmentIndex, | |
| 2063 | data: ObjectData.Index, | |
| 1959 | 2064 | function: Wasm.ObjectFunctionIndex, |
| 1960 | 2065 | }; |
| 1961 | 2066 | |
| ... | ... | @@ -2096,6 +2201,8 @@ pub const Feature = packed struct(u8) { |
| 2096 | 2201 | /// Type of the feature, must be unique in the sequence of features. |
| 2097 | 2202 | tag: Tag, |
| 2098 | 2203 | |
| 2204 | pub const sentinel: Feature = @bitCast(@as(u8, 0)); | |
| 2205 | ||
| 2099 | 2206 | /// Stored identically to `String`. The bytes are reinterpreted as `Feature` |
| 2100 | 2207 | /// elements. Elements must be sorted before string-interning. |
| 2101 | 2208 | pub const Set = enum(u32) { |
| ... | ... | @@ -2104,6 +2211,14 @@ pub const Feature = packed struct(u8) { |
| 2104 | 2211 | pub fn fromString(s: String) Set { |
| 2105 | 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 | }; |
| 2108 | 2223 | |
| 2109 | 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 | 2244 | return @enumFromInt(@intFromEnum(feature)); |
| 2130 | 2245 | } |
| 2131 | 2246 | |
| 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 | 2254 | pub const format = @compileError("use @tagName instead"); |
| 2133 | 2255 | }; |
| 2134 | 2256 | |
| ... | ... | @@ -2136,15 +2258,14 @@ pub const Feature = packed struct(u8) { |
| 2136 | 2258 | pub const Prefix = enum(u2) { |
| 2137 | 2259 | /// Reserved so that a 0-byte Feature is invalid and therefore can be a sentinel. |
| 2138 | 2260 | invalid, |
| 2139 | /// '0x2b': Object uses this feature, and the link fails if feature is | |
| 2140 | /// not in the allowed set. | |
| 2261 | /// Object uses this feature, and the link fails if feature is not in | |
| 2262 | /// the allowed set. | |
| 2141 | 2263 | @"+", |
| 2142 | /// '0x2d': Object does not use this feature, and the link fails if | |
| 2143 | /// this feature is in the allowed set. | |
| 2264 | /// Object does not use this feature, and the link fails if this | |
| 2265 | /// feature is in the allowed set. | |
| 2144 | 2266 | @"-", |
| 2145 | /// '0x3d': Object uses this feature, and the link fails if this | |
| 2146 | /// feature is not in the allowed set, or if any object does not use | |
| 2147 | /// this feature. | |
| 2267 | /// Object uses this feature, and the link fails if this feature is not | |
| 2268 | /// in the allowed set, or if any object does not use this feature. | |
| 2148 | 2269 | @"=", |
| 2149 | 2270 | }; |
| 2150 | 2271 | |
| ... | ... | @@ -2390,6 +2511,7 @@ pub fn deinit(wasm: *Wasm) void { |
| 2390 | 2511 | wasm.object_memories.deinit(gpa); |
| 2391 | 2512 | wasm.object_relocations.deinit(gpa); |
| 2392 | 2513 | wasm.object_data_segments.deinit(gpa); |
| 2514 | wasm.object_datas.deinit(gpa); | |
| 2393 | 2515 | wasm.object_custom_segments.deinit(gpa); |
| 2394 | 2516 | wasm.object_init_funcs.deinit(gpa); |
| 2395 | 2517 | wasm.object_comdats.deinit(gpa); |
| ... | ... | @@ -3412,7 +3534,7 @@ pub fn addExpr(wasm: *Wasm, bytes: []const u8) Allocator.Error!Expr { |
| 3412 | 3534 | return @enumFromInt(wasm.string_bytes.items.len - bytes.len); |
| 3413 | 3535 | } |
| 3414 | 3536 | |
| 3415 | pub fn addRelocatableDataPayload(wasm: *Wasm, bytes: []const u8) Allocator.Error!DataSegment.Payload { | |
| 3537 | pub fn addRelocatableDataPayload(wasm: *Wasm, bytes: []const u8) Allocator.Error!DataPayload { | |
| 3416 | 3538 | const gpa = wasm.base.comp.gpa; |
| 3417 | 3539 | try wasm.string_bytes.appendSlice(gpa, bytes); |
| 3418 | 3540 | return .{ |
| ... | ... | @@ -3546,7 +3668,7 @@ pub fn uavAddr(wasm: *Wasm, uav_index: UavsExeIndex) u32 { |
| 3546 | 3668 | assert(wasm.flush_buffer.memory_layout_finished); |
| 3547 | 3669 | const comp = wasm.base.comp; |
| 3548 | 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 | 3672 | return wasm.flush_buffer.data_segments.get(ds_id).?; |
| 3551 | 3673 | } |
| 3552 | 3674 | |
| ... | ... | @@ -3557,7 +3679,7 @@ pub fn navAddr(wasm: *Wasm, nav_index: InternPool.Nav.Index) u32 { |
| 3557 | 3679 | assert(comp.config.output_mode != .Obj); |
| 3558 | 3680 | const navs_exe_index: NavsExeIndex = @enumFromInt(wasm.navs_exe.getIndex(nav_index).?); |
| 3559 | 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 | 3683 | return wasm.flush_buffer.data_segments.get(ds_id).?; |
| 3562 | 3684 | } |
| 3563 | 3685 | |
| ... | ... | @@ -3646,14 +3768,14 @@ fn lowerZcuData(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !Zcu |
| 3646 | 3768 | const relocs_len: u32 = @intCast(wasm.out_relocs.len - relocs_start); |
| 3647 | 3769 | wasm.string_bytes_lock.unlock(); |
| 3648 | 3770 | |
| 3649 | const naive_code: DataSegment.Payload = .{ | |
| 3771 | const naive_code: DataPayload = .{ | |
| 3650 | 3772 | .off = @enumFromInt(code_start), |
| 3651 | 3773 | .len = code_len, |
| 3652 | 3774 | }; |
| 3653 | 3775 | |
| 3654 | 3776 | // Only nonzero init values need to take up space in the output. |
| 3655 | 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 | 3779 | wasm.string_bytes.shrinkRetainingCapacity(code_start); |
| 3658 | 3780 | // Indicate empty by making off and len the same value, however, still |
| 3659 | 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 | 22 | /// Ordered list of data segments that will appear in the final binary. |
| 23 | 23 | /// When sorted, to-be-merged segments will be made adjacent. |
| 24 | 24 | /// Values are virtual address. |
| 25 | data_segments: std.AutoArrayHashMapUnmanaged(Wasm.DataSegment.Id, u32) = .empty, | |
| 25 | data_segments: std.AutoArrayHashMapUnmanaged(Wasm.DataId, u32) = .empty, | |
| 26 | 26 | /// Each time a `data_segment` offset equals zero it indicates a new group, and |
| 27 | 27 | /// the next element in this array will contain the total merged segment size. |
| 28 | 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 | 120 | if (wasm.entry_resolution == .unresolved) { |
| 121 | 121 | var err = try diags.addErrorWithNotes(1); |
| 122 | 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 | 176 | }), @as(u32, undefined)); |
| 177 | 177 | for (wasm.object_data_segments.items, 0..) |*ds, i| { |
| 178 | 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 | 180 | any_passive_inits = any_passive_inits or ds.flags.is_passive or (import_memory and !wasm.isBss(ds.name)); |
| 181 | 181 | _ = f.data_segments.putAssumeCapacityNoClobber(.pack(wasm, .{ |
| 182 | .object = data_segment_index, | |
| 182 | .object = obj_seg_index, | |
| 183 | 183 | }), @as(u32, undefined)); |
| 184 | 184 | } |
| 185 | 185 | if (wasm.error_name_table_ref_count > 0) { |
| ... | ... | @@ -229,7 +229,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { |
| 229 | 229 | // For the purposes of sorting, they are implicitly all named ".data". |
| 230 | 230 | const Sort = struct { |
| 231 | 231 | wasm: *const Wasm, |
| 232 | segments: []const Wasm.DataSegment.Id, | |
| 232 | segments: []const Wasm.DataId, | |
| 233 | 233 | pub fn lessThan(ctx: @This(), lhs: usize, rhs: usize) bool { |
| 234 | 234 | const lhs_segment = ctx.segments[lhs]; |
| 235 | 235 | const rhs_segment = ctx.segments[rhs]; |
| ... | ... | @@ -312,7 +312,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { |
| 312 | 312 | const data_vaddr: u32 = @intCast(memory_ptr); |
| 313 | 313 | { |
| 314 | 314 | var seen_tls: enum { before, during, after } = .before; |
| 315 | var category: Wasm.DataSegment.Category = undefined; | |
| 315 | var category: Wasm.DataId.Category = undefined; | |
| 316 | 316 | for (segment_ids, segment_vaddrs, 0..) |segment_id, *segment_vaddr, i| { |
| 317 | 317 | const alignment = segment_id.alignment(wasm); |
| 318 | 318 | category = segment_id.category(wasm); |
| ... | ... | @@ -707,7 +707,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { |
| 707 | 707 | |
| 708 | 708 | if (!is_obj) { |
| 709 | 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 | 711 | const vaddr = f.data_segments.get(ds_id).?; |
| 712 | 712 | if (!is64) { |
| 713 | 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 | 716 | } |
| 717 | 717 | } |
| 718 | 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 | 720 | const vaddr = f.data_segments.get(ds_id).?; |
| 721 | 721 | if (!is64) { |
| 722 | 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 | 862 | |
| 863 | 863 | fn emitNameSection( |
| 864 | 864 | wasm: *Wasm, |
| 865 | data_segments: *const std.AutoArrayHashMapUnmanaged(Wasm.DataSegment.Id, u32), | |
| 865 | data_segments: *const std.AutoArrayHashMapUnmanaged(Wasm.DataId, u32), | |
| 866 | 866 | binary_bytes: *std.ArrayListUnmanaged(u8), |
| 867 | 867 | ) !void { |
| 868 | 868 | const f = &wasm.flush_buffer; |
| ... | ... | @@ -1137,9 +1137,9 @@ fn splitSegmentName(name: []const u8) struct { []const u8, []const u8 } { |
| 1137 | 1137 | |
| 1138 | 1138 | fn wantSegmentMerge( |
| 1139 | 1139 | wasm: *const Wasm, |
| 1140 | a_id: Wasm.DataSegment.Id, | |
| 1141 | b_id: Wasm.DataSegment.Id, | |
| 1142 | b_category: Wasm.DataSegment.Category, | |
| 1140 | a_id: Wasm.DataId, | |
| 1141 | b_id: Wasm.DataId, | |
| 1142 | b_category: Wasm.DataId.Category, | |
| 1143 | 1143 | ) bool { |
| 1144 | 1144 | const a_category = a_id.category(wasm); |
| 1145 | 1145 | if (a_category != b_category) return false; |
src/link/Wasm/Object.zig+105-79| ... | ... | @@ -102,11 +102,7 @@ pub const Symbol = struct { |
| 102 | 102 | const Pointee = union(enum) { |
| 103 | 103 | function: Wasm.ObjectFunctionIndex, |
| 104 | 104 | function_import: ScratchSpace.FuncImportIndex, |
| 105 | data: struct { | |
| 106 | segment_index: Wasm.ObjectDataSegmentIndex, | |
| 107 | segment_offset: u32, | |
| 108 | size: u32, | |
| 109 | }, | |
| 105 | data: Wasm.ObjectData.Index, | |
| 110 | 106 | data_import: void, |
| 111 | 107 | global: Wasm.ObjectGlobalIndex, |
| 112 | 108 | global_import: Wasm.GlobalImport.Index, |
| ... | ... | @@ -131,7 +127,7 @@ pub const ScratchSpace = struct { |
| 131 | 127 | const Pointee = union(std.wasm.ExternalKind) { |
| 132 | 128 | function: Wasm.ObjectFunctionIndex, |
| 133 | 129 | table: Wasm.ObjectTableIndex, |
| 134 | memory: Wasm.ObjectMemoryIndex, | |
| 130 | memory: Wasm.ObjectMemory.Index, | |
| 135 | 131 | global: Wasm.ObjectGlobalIndex, |
| 136 | 132 | }; |
| 137 | 133 | }; |
| ... | ... | @@ -184,8 +180,9 @@ pub fn parse( |
| 184 | 180 | must_link: bool, |
| 185 | 181 | gc_sections: bool, |
| 186 | 182 | ) anyerror!Object { |
| 187 | const gpa = wasm.base.comp.gpa; | |
| 188 | const diags = &wasm.base.comp.link_diags; | |
| 183 | const comp = wasm.base.comp; | |
| 184 | const gpa = comp.gpa; | |
| 185 | const diags = &comp.link_diags; | |
| 189 | 186 | |
| 190 | 187 | var pos: usize = 0; |
| 191 | 188 | |
| ... | ... | @@ -334,12 +331,16 @@ pub fn parse( |
| 334 | 331 | const segment_index, pos = readLeb(u32, bytes, pos); |
| 335 | 332 | const segment_offset, pos = readLeb(u32, bytes, pos); |
| 336 | 333 | const size, pos = readLeb(u32, bytes, pos); |
| 337 | ||
| 338 | symbol.pointee = .{ .data = .{ | |
| 339 | .segment_index = @enumFromInt(data_segment_start + segment_index), | |
| 340 | .segment_offset = segment_offset, | |
| 334 | try wasm.object_datas.append(gpa, .{ | |
| 335 | .segment = @enumFromInt(data_segment_start + segment_index), | |
| 336 | .offset = segment_offset, | |
| 341 | 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 | 346 | .section => { |
| ... | ... | @@ -405,7 +406,6 @@ pub fn parse( |
| 405 | 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 | 450 | .MEMORY_ADDR_TLS_SLEB64, |
| 451 | 451 | => { |
| 452 | 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 | 453 | wasm.object_relocations.appendAssumeCapacity(.{ |
| 466 | 454 | .tag = tag, |
| 467 | 455 | .offset = offset, |
| 468 | .pointee = .{ .data_segment = sym_section.segment_index }, | |
| 456 | .pointee = .{ .data = ss.symbol_table.items[index].pointee.data }, | |
| 469 | 457 | .addend = addend, |
| 470 | 458 | }); |
| 471 | 459 | }, |
| ... | ... | @@ -651,7 +639,15 @@ pub fn parse( |
| 651 | 639 | const memories_len, pos = readLeb(u32, bytes, pos); |
| 652 | 640 | for (try wasm.object_memories.addManyAsSlice(gpa, memories_len)) |*memory| { |
| 653 | 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 | 653 | .global => { |
| ... | ... | @@ -722,7 +718,6 @@ pub fn parse( |
| 722 | 718 | } |
| 723 | 719 | }, |
| 724 | 720 | .data => { |
| 725 | const start = pos; | |
| 726 | 721 | const count, pos = readLeb(u32, bytes, pos); |
| 727 | 722 | for (try wasm.object_data_segments.addManyAsSlice(gpa, count)) |*elem| { |
| 728 | 723 | const flags, pos = readEnum(DataSegmentFlags, bytes, pos); |
| ... | ... | @@ -733,13 +728,10 @@ pub fn parse( |
| 733 | 728 | //const expr, pos = if (flags != .passive) try readInit(wasm, bytes, pos) else .{ .none, pos }; |
| 734 | 729 | if (flags != .passive) pos = try skipInit(bytes, pos); |
| 735 | 730 | const data_len, pos = readLeb(u32, bytes, pos); |
| 736 | const segment_offset: u32 = @intCast(pos - start); | |
| 737 | 731 | const payload = try wasm.addRelocatableDataPayload(bytes[pos..][0..data_len]); |
| 738 | 732 | pos += data_len; |
| 739 | 733 | elem.* = .{ |
| 740 | 734 | .payload = payload, |
| 741 | .segment_offset = segment_offset, | |
| 742 | .section_index = section_index, | |
| 743 | 735 | .name = .none, // Populated from symbol table |
| 744 | 736 | .flags = .{}, // Populated from symbol table and segment_info |
| 745 | 737 | }; |
| ... | ... | @@ -751,20 +743,56 @@ pub fn parse( |
| 751 | 743 | } |
| 752 | 744 | if (!saw_linking_section) return error.MissingLinkingSection; |
| 753 | 745 | |
| 746 | const target_features = comp.root_mod.resolved_target.result.cpu.features; | |
| 747 | ||
| 754 | 748 | if (has_tls) { |
| 755 | const cpu_features = wasm.base.comp.root_mod.resolved_target.result.cpu.features; | |
| 756 | if (!std.Target.wasm.featureSetHas(cpu_features, .atomics)) | |
| 749 | if (!std.Target.wasm.featureSetHas(target_features, .atomics)) | |
| 757 | 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 | 752 | return diags.failParse(path, "object has TLS segment but target CPU feature bulk_memory is disabled", .{}); |
| 760 | 753 | } |
| 761 | 754 | |
| 762 | 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 | } | |
| 764 | 792 | |
| 765 | 793 | // Apply function type information. |
| 766 | for (ss.func_types.items, wasm.object_functions.items[functions_start..]) |func_type, *func| { | |
| 767 | func.type_index = func_type; | |
| 794 | for (ss.func_type_indexes.items, wasm.object_functions.items[functions_start..]) |func_type, *func| { | |
| 795 | func.type_index = func_type.ptr(ss).*; | |
| 768 | 796 | } |
| 769 | 797 | |
| 770 | 798 | // Apply symbol table information. |
| ... | ... | @@ -782,15 +810,21 @@ pub fn parse( |
| 782 | 810 | if (gop.value_ptr.type != fn_ty_index) { |
| 783 | 811 | var err = try diags.addErrorWithNotes(2); |
| 784 | 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)}); | |
| 786 | try err.addSrcNote(source_location, "imported as {} here", .{fn_ty_index.fmt(wasm)}); | |
| 813 | gop.value_ptr.source_location.addNote(wasm, &err, "imported as {} here", .{ | |
| 814 | gop.value_ptr.type.fmt(wasm), | |
| 815 | }); | |
| 816 | source_location.addNote(wasm, &err, "imported as {} here", .{fn_ty_index.fmt(wasm)}); | |
| 787 | 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 | 820 | var err = try diags.addErrorWithNotes(2); |
| 791 | 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)}); | |
| 793 | try err.addSrcNote(source_location, "module '{s}' here", .{ptr.module_name.slice(wasm)}); | |
| 822 | if (gop.value_ptr.module_name.slice(wasm)) |module_name| { | |
| 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 | 828 | continue; |
| 795 | 829 | } |
| 796 | 830 | if (symbol.flags.binding == .strong) gop.value_ptr.flags.binding = .strong; |
| ... | ... | @@ -799,7 +833,7 @@ pub fn parse( |
| 799 | 833 | } else { |
| 800 | 834 | gop.value_ptr.* = .{ |
| 801 | 835 | .flags = symbol.flags, |
| 802 | .module_name = ptr.module_name, | |
| 836 | .module_name = ptr.module_name.toOptional(), | |
| 803 | 837 | .source_location = source_location, |
| 804 | 838 | .resolution = .unresolved, |
| 805 | 839 | .type = fn_ty_index, |
| ... | ... | @@ -808,7 +842,7 @@ pub fn parse( |
| 808 | 842 | }, |
| 809 | 843 | .function => |index| { |
| 810 | 844 | assert(!symbol.flags.undefined); |
| 811 | const ptr = index.ptr(); | |
| 845 | const ptr = index.ptr(wasm); | |
| 812 | 846 | ptr.name = symbol.name; |
| 813 | 847 | ptr.flags = symbol.flags; |
| 814 | 848 | if (symbol.flags.binding == .local) continue; // No participation in symbol resolution. |
| ... | ... | @@ -818,35 +852,46 @@ pub fn parse( |
| 818 | 852 | if (gop.value_ptr.type != ptr.type_index) { |
| 819 | 853 | var err = try diags.addErrorWithNotes(2); |
| 820 | 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)}); | |
| 822 | const word = if (gop.value_ptr.resolution == .none) "imported" else "exported"; | |
| 823 | try err.addSrcNote(source_location, "{s} as {} here", .{ word, gop.value_ptr.type.fmt(wasm) }); | |
| 855 | gop.value_ptr.source_location.addNote(wasm, &err, "exported as {} here", .{ | |
| 856 | ptr.type_index.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 | 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 | 863 | // Intentional: if they're both weak, take the last one. |
| 828 | 864 | gop.value_ptr.source_location = source_location; |
| 829 | 865 | gop.value_ptr.module_name = host_name; |
| 830 | gop.value_ptr.resolution = .fromObjectFunction(index); | |
| 866 | gop.value_ptr.resolution = .fromObjectFunction(wasm, index); | |
| 831 | 867 | continue; |
| 832 | 868 | } |
| 833 | 869 | var err = try diags.addErrorWithNotes(2); |
| 834 | 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)}); | |
| 836 | try err.addSrcNote(source_location, "exported as {} here", .{gop.value_ptr.type.fmt(wasm)}); | |
| 871 | gop.value_ptr.source_location.addNote(wasm, &err, "exported as {} here", .{ptr.type_index.fmt(wasm)}); | |
| 872 | source_location.addNote(wasm, &err, "exported as {} here", .{gop.value_ptr.type.fmt(wasm)}); | |
| 837 | 873 | continue; |
| 838 | 874 | } else { |
| 839 | 875 | gop.value_ptr.* = .{ |
| 840 | 876 | .flags = symbol.flags, |
| 841 | 877 | .module_name = host_name, |
| 842 | 878 | .source_location = source_location, |
| 843 | .resolution = .fromObjectFunction(index), | |
| 879 | .resolution = .fromObjectFunction(wasm, index), | |
| 844 | 880 | .type = ptr.type_index, |
| 845 | 881 | }; |
| 846 | 882 | } |
| 847 | 883 | }, |
| 848 | 884 | |
| 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 | 895 | const ptr = i.ptr(wasm); |
| 851 | 896 | ptr.name = symbol.name; |
| 852 | 897 | ptr.flags = symbol.flags; |
| ... | ... | @@ -857,10 +902,11 @@ pub fn parse( |
| 857 | 902 | }, |
| 858 | 903 | .section => |i| { |
| 859 | 904 | // Name is provided by the section directly; symbol table does not have it. |
| 860 | const ptr = i.ptr(wasm); | |
| 861 | ptr.flags = symbol.flags; | |
| 905 | //const ptr = i.ptr(wasm); | |
| 906 | //ptr.flags = symbol.flags; | |
| 907 | _ = i; | |
| 862 | 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 | 910 | diags.addParseError(path, "local symbol '{s}' references import", .{name}); |
| 865 | 911 | } |
| 866 | 912 | }, |
| ... | ... | @@ -868,15 +914,7 @@ pub fn parse( |
| 868 | 914 | const name = symbol.name.unwrap().?; |
| 869 | 915 | log.warn("TODO data import '{s}'", .{name.slice(wasm)}); |
| 870 | 916 | }, |
| 871 | .data => |data| { | |
| 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 | }, | |
| 917 | .data => continue, // `wasm.object_datas` has already been populated. | |
| 880 | 918 | }; |
| 881 | 919 | |
| 882 | 920 | // Apply export section info. This is done after the symbol table above so |
| ... | ... | @@ -957,18 +995,6 @@ pub fn parse( |
| 957 | 995 | .off = functions_start, |
| 958 | 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 | 998 | .function_imports = .{ |
| 973 | 999 | .off = function_imports_start, |
| 974 | 1000 | .len = @intCast(wasm.object_function_imports.entries.len - function_imports_start), |
| ... | ... | @@ -979,7 +1005,7 @@ pub fn parse( |
| 979 | 1005 | }, |
| 980 | 1006 | .table_imports = .{ |
| 981 | 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 | 1010 | .init_funcs = .{ |
| 985 | 1011 | .off = init_funcs_start, |