authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-03 18:08:56-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-15 15:11:36-08:00
logabdbc38574b9f0fb3a1130285cbf84c2dbd4552c
treee25acd4a4311b87f817e615897ab915d0498ecbb
parenta4bee3009a45557f788472bd3b396b5528bf0a96

wasm linker: implement data symbols


3 files changed, 277 insertions(+), 61 deletions(-)

src/link/Wasm.zig+203-32
...@@ -123,9 +123,10 @@ object_init_funcs: std.ArrayListUnmanaged(InitFunc) = .empty,...@@ -123,9 +123,10 @@ object_init_funcs: std.ArrayListUnmanaged(InitFunc) = .empty,
123/// logically to an object file's .data section, or .rodata section. In123/// 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.124/// the case of `-fdata-sections` there will be one segment per data symbol.
125object_data_segments: std.ArrayListUnmanaged(ObjectDataSegment) = .empty,125object_data_segments: std.ArrayListUnmanaged(ObjectDataSegment) = .empty,
126/// Each segment has many data symbols. These correspond logically to global126/// Each segment has many data symbols, which correspond logically to global
127/// constants.127/// constants.
128object_datas: std.ArrayListUnmanaged(ObjectData) = .empty,128object_datas: std.ArrayListUnmanaged(ObjectData) = .empty,
129object_data_imports: std.AutoArrayHashMapUnmanaged(String, ObjectDataImport) = .empty,
129/// Non-synthetic section that can essentially be mem-cpy'd into place after performing relocations.130/// Non-synthetic section that can essentially be mem-cpy'd into place after performing relocations.
130object_custom_segments: std.AutoArrayHashMapUnmanaged(ObjectSectionIndex, CustomSegment) = .empty,131object_custom_segments: std.AutoArrayHashMapUnmanaged(ObjectSectionIndex, CustomSegment) = .empty,
131132
...@@ -227,6 +228,22 @@ functions_end_prelink: u32 = 0,...@@ -227,6 +228,22 @@ functions_end_prelink: u32 = 0,
227/// symbol errors, or import section entries depending on the output mode.228/// symbol errors, or import section entries depending on the output mode.
228function_imports: std.AutoArrayHashMapUnmanaged(String, FunctionImportId) = .empty,229function_imports: std.AutoArrayHashMapUnmanaged(String, FunctionImportId) = .empty,
229230
231/// At the end of prelink, this is populated with data symbols needed by
232/// objects.
233///
234/// During the Zcu phase, entries are not deleted from this table
235/// because doing so would be irreversible when a `deleteExport` call is
236/// handled. However, entries are added during the Zcu phase when extern
237/// functions are passed to `updateNav`.
238///
239/// `flush` gets a copy of this table, and then Zcu exports are applied to
240/// remove elements from the table, and the remainder are either undefined
241/// symbol errors, or symbol table entries depending on the output mode.
242data_imports: std.AutoArrayHashMapUnmanaged(String, DataImportId) = .empty,
243/// Set of data symbols that will appear in the final binary. Used to populate
244/// `Flush.data_segments` before sorting.
245data_segments: std.AutoArrayHashMapUnmanaged(DataId, void) = .empty,
246
230/// Ordered list of non-import globals that will appear in the final binary.247/// Ordered list of non-import globals that will appear in the final binary.
231/// Empty until prelink.248/// Empty until prelink.
232globals: std.AutoArrayHashMapUnmanaged(GlobalImport.Resolution, void) = .empty,249globals: std.AutoArrayHashMapUnmanaged(GlobalImport.Resolution, void) = .empty,
...@@ -251,6 +268,7 @@ error_name_table_ref_count: u32 = 0,...@@ -251,6 +268,7 @@ error_name_table_ref_count: u32 = 0,
251/// value must be this OR'd with the same logic for zig functions268/// value must be this OR'd with the same logic for zig functions
252/// (set to true if any threadlocal global is used).269/// (set to true if any threadlocal global is used).
253any_tls_relocs: bool = false,270any_tls_relocs: bool = false,
271any_passive_inits: bool = false,
254272
255/// All MIR instructions for all Zcu functions.273/// All MIR instructions for all Zcu functions.
256mir_instructions: std.MultiArrayList(Mir.Inst) = .{},274mir_instructions: std.MultiArrayList(Mir.Inst) = .{},
...@@ -1499,6 +1517,50 @@ pub const ObjectData = extern struct {...@@ -1499,6 +1517,50 @@ pub const ObjectData = extern struct {
1499 };1517 };
1500};1518};
15011519
1520pub const ObjectDataImport = extern struct {
1521 resolution: Resolution,
1522 flags: SymbolFlags,
1523 source_location: SourceLocation,
1524
1525 pub const Resolution = enum(u32) {
1526 __zig_error_names,
1527 __zig_error_name_table,
1528 __heap_base,
1529 __heap_end,
1530 unresolved = std.math.maxInt(u32),
1531 _,
1532
1533 comptime {
1534 assert(@intFromEnum(Resolution.__zig_error_names) == @intFromEnum(DataId.__zig_error_names));
1535 assert(@intFromEnum(Resolution.__zig_error_name_table) == @intFromEnum(DataId.__zig_error_name_table));
1536 assert(@intFromEnum(Resolution.__heap_base) == @intFromEnum(DataId.__heap_base));
1537 assert(@intFromEnum(Resolution.__heap_end) == @intFromEnum(DataId.__heap_end));
1538 }
1539
1540 pub fn toDataId(r: Resolution) ?DataId {
1541 if (r == .unresolved) return null;
1542 return @enumFromInt(@intFromEnum(r));
1543 }
1544
1545 pub fn fromObjectDataIndex(wasm: *const Wasm, object_data_index: ObjectData.Index) Resolution {
1546 return @enumFromInt(@intFromEnum(DataId.pack(wasm, .{ .object = object_data_index.ptr(wasm).segment })));
1547 }
1548 };
1549
1550 /// Points into `Wasm.object_data_imports`.
1551 pub const Index = enum(u32) {
1552 _,
1553
1554 pub fn value(i: @This(), wasm: *const Wasm) *ObjectDataImport {
1555 return &wasm.object_data_imports.values()[@intFromEnum(i)];
1556 }
1557
1558 pub fn fromSymbolName(wasm: *const Wasm, name: String) ?Index {
1559 return @enumFromInt(wasm.object_data_imports.getIndex(name) orelse return null);
1560 }
1561 };
1562};
1563
1502pub const DataPayload = extern struct {1564pub const DataPayload = extern struct {
1503 off: Off,1565 off: Off,
1504 /// The size in bytes of the data representing the segment within the section.1566 /// The size in bytes of the data representing the segment within the section.
...@@ -1524,12 +1586,17 @@ pub const DataPayload = extern struct {...@@ -1524,12 +1586,17 @@ pub const DataPayload = extern struct {
1524pub const DataId = enum(u32) {1586pub const DataId = enum(u32) {
1525 __zig_error_names,1587 __zig_error_names,
1526 __zig_error_name_table,1588 __zig_error_name_table,
1589 /// This and `__heap_end` are better retrieved via a global, but there is
1590 /// some suboptimal code out there (wasi libc) that additionally needs them
1591 /// as data symbols.
1592 __heap_base,
1593 __heap_end,
1527 /// First, an `ObjectDataSegment.Index`.1594 /// First, an `ObjectDataSegment.Index`.
1528 /// Next, index into `uavs_obj` or `uavs_exe` depending on whether emitting an object.1595 /// Next, index into `uavs_obj` or `uavs_exe` depending on whether emitting an object.
1529 /// Next, index into `navs_obj` or `navs_exe` depending on whether emitting an object.1596 /// Next, index into `navs_obj` or `navs_exe` depending on whether emitting an object.
1530 _,1597 _,
15311598
1532 const first_object = @intFromEnum(DataId.__zig_error_name_table) + 1;1599 const first_object = @intFromEnum(DataId.__heap_end) + 1;
15331600
1534 pub const Category = enum {1601 pub const Category = enum {
1535 /// Thread-local variables.1602 /// Thread-local variables.
...@@ -1544,6 +1611,8 @@ pub const DataId = enum(u32) {...@@ -1544,6 +1611,8 @@ pub const DataId = enum(u32) {
1544 pub const Unpacked = union(enum) {1611 pub const Unpacked = union(enum) {
1545 __zig_error_names,1612 __zig_error_names,
1546 __zig_error_name_table,1613 __zig_error_name_table,
1614 __heap_base,
1615 __heap_end,
1547 object: ObjectDataSegment.Index,1616 object: ObjectDataSegment.Index,
1548 uav_exe: UavsExeIndex,1617 uav_exe: UavsExeIndex,
1549 uav_obj: UavsObjIndex,1618 uav_obj: UavsObjIndex,
...@@ -1555,6 +1624,8 @@ pub const DataId = enum(u32) {...@@ -1555,6 +1624,8 @@ pub const DataId = enum(u32) {
1555 return switch (unpacked) {1624 return switch (unpacked) {
1556 .__zig_error_names => .__zig_error_names,1625 .__zig_error_names => .__zig_error_names,
1557 .__zig_error_name_table => .__zig_error_name_table,1626 .__zig_error_name_table => .__zig_error_name_table,
1627 .__heap_base => .__heap_base,
1628 .__heap_end => .__heap_end,
1558 .object => |i| @enumFromInt(first_object + @intFromEnum(i)),1629 .object => |i| @enumFromInt(first_object + @intFromEnum(i)),
1559 inline .uav_exe, .uav_obj => |i| @enumFromInt(first_object + wasm.object_data_segments.items.len + @intFromEnum(i)),1630 inline .uav_exe, .uav_obj => |i| @enumFromInt(first_object + wasm.object_data_segments.items.len + @intFromEnum(i)),
1560 .nav_exe => |i| @enumFromInt(first_object + wasm.object_data_segments.items.len + wasm.uavs_exe.entries.len + @intFromEnum(i)),1631 .nav_exe => |i| @enumFromInt(first_object + wasm.object_data_segments.items.len + wasm.uavs_exe.entries.len + @intFromEnum(i)),
...@@ -1566,6 +1637,8 @@ pub const DataId = enum(u32) {...@@ -1566,6 +1637,8 @@ pub const DataId = enum(u32) {
1566 return switch (id) {1637 return switch (id) {
1567 .__zig_error_names => .__zig_error_names,1638 .__zig_error_names => .__zig_error_names,
1568 .__zig_error_name_table => .__zig_error_name_table,1639 .__zig_error_name_table => .__zig_error_name_table,
1640 .__heap_base => .__heap_base,
1641 .__heap_end => .__heap_end,
1569 _ => {1642 _ => {
1570 const object_index = @intFromEnum(id) - first_object;1643 const object_index = @intFromEnum(id) - first_object;
15711644
...@@ -1601,7 +1674,7 @@ pub const DataId = enum(u32) {...@@ -1601,7 +1674,7 @@ pub const DataId = enum(u32) {
16011674
1602 pub fn category(id: DataId, wasm: *const Wasm) Category {1675 pub fn category(id: DataId, wasm: *const Wasm) Category {
1603 return switch (unpack(id, wasm)) {1676 return switch (unpack(id, wasm)) {
1604 .__zig_error_names, .__zig_error_name_table => .data,1677 .__zig_error_names, .__zig_error_name_table, .__heap_base, .__heap_end => .data,
1605 .object => |i| {1678 .object => |i| {
1606 const ptr = i.ptr(wasm);1679 const ptr = i.ptr(wasm);
1607 if (ptr.flags.tls) return .tls;1680 if (ptr.flags.tls) return .tls;
...@@ -1622,7 +1695,7 @@ pub const DataId = enum(u32) {...@@ -1622,7 +1695,7 @@ pub const DataId = enum(u32) {
16221695
1623 pub fn isTls(id: DataId, wasm: *const Wasm) bool {1696 pub fn isTls(id: DataId, wasm: *const Wasm) bool {
1624 return switch (unpack(id, wasm)) {1697 return switch (unpack(id, wasm)) {
1625 .__zig_error_names, .__zig_error_name_table => false,1698 .__zig_error_names, .__zig_error_name_table, .__heap_base, .__heap_end => false,
1626 .object => |i| i.ptr(wasm).flags.tls,1699 .object => |i| i.ptr(wasm).flags.tls,
1627 .uav_exe, .uav_obj => false,1700 .uav_exe, .uav_obj => false,
1628 inline .nav_exe, .nav_obj => |i| {1701 inline .nav_exe, .nav_obj => |i| {
...@@ -1640,7 +1713,7 @@ pub const DataId = enum(u32) {...@@ -1640,7 +1713,7 @@ pub const DataId = enum(u32) {
16401713
1641 pub fn name(id: DataId, wasm: *const Wasm) []const u8 {1714 pub fn name(id: DataId, wasm: *const Wasm) []const u8 {
1642 return switch (unpack(id, wasm)) {1715 return switch (unpack(id, wasm)) {
1643 .__zig_error_names, .__zig_error_name_table, .uav_exe, .uav_obj => ".data",1716 .__zig_error_names, .__zig_error_name_table, .uav_exe, .uav_obj, .__heap_base, .__heap_end => ".data",
1644 .object => |i| i.ptr(wasm).name.unwrap().?.slice(wasm),1717 .object => |i| i.ptr(wasm).name.unwrap().?.slice(wasm),
1645 inline .nav_exe, .nav_obj => |i| {1718 inline .nav_exe, .nav_obj => |i| {
1646 const zcu = wasm.base.comp.zcu.?;1719 const zcu = wasm.base.comp.zcu.?;
...@@ -1654,7 +1727,7 @@ pub const DataId = enum(u32) {...@@ -1654,7 +1727,7 @@ pub const DataId = enum(u32) {
1654 pub fn alignment(id: DataId, wasm: *const Wasm) Alignment {1727 pub fn alignment(id: DataId, wasm: *const Wasm) Alignment {
1655 return switch (unpack(id, wasm)) {1728 return switch (unpack(id, wasm)) {
1656 .__zig_error_names => .@"1",1729 .__zig_error_names => .@"1",
1657 .__zig_error_name_table => wasm.pointerAlignment(),1730 .__zig_error_name_table, .__heap_base, .__heap_end => wasm.pointerAlignment(),
1658 .object => |i| i.ptr(wasm).flags.alignment,1731 .object => |i| i.ptr(wasm).flags.alignment,
1659 inline .uav_exe, .uav_obj => |i| {1732 inline .uav_exe, .uav_obj => |i| {
1660 const zcu = wasm.base.comp.zcu.?;1733 const zcu = wasm.base.comp.zcu.?;
...@@ -1683,7 +1756,7 @@ pub const DataId = enum(u32) {...@@ -1683,7 +1756,7 @@ pub const DataId = enum(u32) {
1683 return switch (unpack(id, wasm)) {1756 return switch (unpack(id, wasm)) {
1684 .__zig_error_names => @intCast(wasm.error_name_offs.items.len),1757 .__zig_error_names => @intCast(wasm.error_name_offs.items.len),
1685 .__zig_error_name_table => wasm.error_name_table_ref_count,1758 .__zig_error_name_table => wasm.error_name_table_ref_count,
1686 .object, .uav_obj, .nav_obj => 0,1759 .object, .uav_obj, .nav_obj, .__heap_base, .__heap_end => 0,
1687 inline .uav_exe, .nav_exe => |i| i.value(wasm).count,1760 inline .uav_exe, .nav_exe => |i| i.value(wasm).count,
1688 };1761 };
1689 }1762 }
...@@ -1692,7 +1765,7 @@ pub const DataId = enum(u32) {...@@ -1692,7 +1765,7 @@ pub const DataId = enum(u32) {
1692 const comp = wasm.base.comp;1765 const comp = wasm.base.comp;
1693 if (comp.config.import_memory and !id.isBss(wasm)) return true;1766 if (comp.config.import_memory and !id.isBss(wasm)) return true;
1694 return switch (unpack(id, wasm)) {1767 return switch (unpack(id, wasm)) {
1695 .__zig_error_names, .__zig_error_name_table => false,1768 .__zig_error_names, .__zig_error_name_table, .__heap_base, .__heap_end => false,
1696 .object => |i| i.ptr(wasm).flags.is_passive,1769 .object => |i| i.ptr(wasm).flags.is_passive,
1697 .uav_exe, .uav_obj, .nav_exe, .nav_obj => false,1770 .uav_exe, .uav_obj, .nav_exe, .nav_obj => false,
1698 };1771 };
...@@ -1700,7 +1773,7 @@ pub const DataId = enum(u32) {...@@ -1700,7 +1773,7 @@ pub const DataId = enum(u32) {
17001773
1701 pub fn isEmpty(id: DataId, wasm: *const Wasm) bool {1774 pub fn isEmpty(id: DataId, wasm: *const Wasm) bool {
1702 return switch (unpack(id, wasm)) {1775 return switch (unpack(id, wasm)) {
1703 .__zig_error_names, .__zig_error_name_table => false,1776 .__zig_error_names, .__zig_error_name_table, .__heap_base, .__heap_end => false,
1704 .object => |i| i.ptr(wasm).payload.off == .none,1777 .object => |i| i.ptr(wasm).payload.off == .none,
1705 inline .uav_exe, .uav_obj, .nav_exe, .nav_obj => |i| i.value(wasm).code.off == .none,1778 inline .uav_exe, .uav_obj, .nav_exe, .nav_obj => |i| i.value(wasm).code.off == .none,
1706 };1779 };
...@@ -1716,6 +1789,7 @@ pub const DataId = enum(u32) {...@@ -1716,6 +1789,7 @@ pub const DataId = enum(u32) {
1716 const elem_size = ZcuType.slice_const_u8_sentinel_0.abiSize(zcu);1789 const elem_size = ZcuType.slice_const_u8_sentinel_0.abiSize(zcu);
1717 return @intCast(errors_len * elem_size);1790 return @intCast(errors_len * elem_size);
1718 },1791 },
1792 .__heap_base, .__heap_end => wasm.pointerSize(),
1719 .object => |i| i.ptr(wasm).payload.len,1793 .object => |i| i.ptr(wasm).payload.len,
1720 inline .uav_exe, .uav_obj, .nav_exe, .nav_obj => |i| i.value(wasm).code.len,1794 inline .uav_exe, .uav_obj, .nav_exe, .nav_obj => |i| i.value(wasm).code.len,
1721 };1795 };
...@@ -2110,6 +2184,55 @@ pub const GlobalImportId = enum(u32) {...@@ -2110,6 +2184,55 @@ pub const GlobalImportId = enum(u32) {
2110 }2184 }
2111};2185};
21122186
2187/// 0. Index into `Wasm.object_data_imports`.
2188/// 1. Index into `Wasm.imports`.
2189pub const DataImportId = enum(u32) {
2190 _,
2191
2192 pub const Unpacked = union(enum) {
2193 object_data_import: ObjectDataImport.Index,
2194 zcu_import: ZcuImportIndex,
2195 };
2196
2197 pub fn pack(unpacked: Unpacked, wasm: *const Wasm) DataImportId {
2198 return switch (unpacked) {
2199 .object_data_import => |i| @enumFromInt(@intFromEnum(i)),
2200 .zcu_import => |i| @enumFromInt(@intFromEnum(i) - wasm.object_data_imports.entries.len),
2201 };
2202 }
2203
2204 pub fn unpack(id: DataImportId, wasm: *const Wasm) Unpacked {
2205 const i = @intFromEnum(id);
2206 if (i < wasm.object_data_imports.entries.len) return .{ .object_data_import = @enumFromInt(i) };
2207 const zcu_import_i = i - wasm.object_data_imports.entries.len;
2208 return .{ .zcu_import = @enumFromInt(zcu_import_i) };
2209 }
2210
2211 pub fn fromZcuImport(zcu_import: ZcuImportIndex, wasm: *const Wasm) DataImportId {
2212 return pack(.{ .zcu_import = zcu_import }, wasm);
2213 }
2214
2215 pub fn fromObject(object_data_import: ObjectDataImport.Index, wasm: *const Wasm) DataImportId {
2216 return pack(.{ .object_data_import = object_data_import }, wasm);
2217 }
2218
2219 pub fn sourceLocation(id: DataImportId, wasm: *const Wasm) SourceLocation {
2220 switch (id.unpack(wasm)) {
2221 .object_data_import => |obj_data_index| {
2222 // TODO binary search
2223 for (wasm.objects.items, 0..) |o, i| {
2224 if (o.data_imports.off <= @intFromEnum(obj_data_index) and
2225 o.data_imports.off + o.data_imports.len > @intFromEnum(obj_data_index))
2226 {
2227 return .pack(.{ .object_index = @enumFromInt(i) }, wasm);
2228 }
2229 } else unreachable;
2230 },
2231 .zcu_import => return .zig_object_nofile, // TODO give a better source location
2232 }
2233 }
2234};
2235
2113/// Index into `Wasm.symbol_table`.2236/// Index into `Wasm.symbol_table`.
2114pub const SymbolTableIndex = enum(u32) {2237pub const SymbolTableIndex = enum(u32) {
2115 _,2238 _,
...@@ -2716,6 +2839,7 @@ pub fn deinit(wasm: *Wasm) void {...@@ -2716,6 +2839,7 @@ pub fn deinit(wasm: *Wasm) void {
2716 wasm.object_memory_imports.deinit(gpa);2839 wasm.object_memory_imports.deinit(gpa);
2717 wasm.object_memories.deinit(gpa);2840 wasm.object_memories.deinit(gpa);
2718 wasm.object_relocations.deinit(gpa);2841 wasm.object_relocations.deinit(gpa);
2842 wasm.object_data_imports.deinit(gpa);
2719 wasm.object_data_segments.deinit(gpa);2843 wasm.object_data_segments.deinit(gpa);
2720 wasm.object_datas.deinit(gpa);2844 wasm.object_datas.deinit(gpa);
2721 wasm.object_custom_segments.deinit(gpa);2845 wasm.object_custom_segments.deinit(gpa);
...@@ -2734,6 +2858,8 @@ pub fn deinit(wasm: *Wasm) void {...@@ -2734,6 +2858,8 @@ pub fn deinit(wasm: *Wasm) void {
2734 wasm.global_imports.deinit(gpa);2858 wasm.global_imports.deinit(gpa);
2735 wasm.table_imports.deinit(gpa);2859 wasm.table_imports.deinit(gpa);
2736 wasm.tables.deinit(gpa);2860 wasm.tables.deinit(gpa);
2861 wasm.data_imports.deinit(gpa);
2862 wasm.data_segments.deinit(gpa);
2737 wasm.symbol_table.deinit(gpa);2863 wasm.symbol_table.deinit(gpa);
2738 wasm.out_relocs.deinit(gpa);2864 wasm.out_relocs.deinit(gpa);
2739 wasm.uav_fixups.deinit(gpa);2865 wasm.uav_fixups.deinit(gpa);
...@@ -2805,15 +2931,16 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index...@@ -2805,15 +2931,16 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index
2805 const name = try wasm.internString(ext.name.toSlice(ip));2931 const name = try wasm.internString(ext.name.toSlice(ip));
2806 if (ext.lib_name.toSlice(ip)) |ext_name| _ = try wasm.internString(ext_name);2932 if (ext.lib_name.toSlice(ip)) |ext_name| _ = try wasm.internString(ext_name);
2807 try wasm.imports.ensureUnusedCapacity(gpa, 1);2933 try wasm.imports.ensureUnusedCapacity(gpa, 1);
2934 try wasm.function_imports.ensureUnusedCapacity(gpa, 1);
2935 try wasm.data_imports.ensureUnusedCapacity(gpa, 1);
2936 const zcu_import = wasm.addZcuImportReserved(ext.owner_nav);
2808 if (ip.isFunctionType(nav.typeOf(ip))) {2937 if (ip.isFunctionType(nav.typeOf(ip))) {
2809 try wasm.function_imports.ensureUnusedCapacity(gpa, 1);
2810 const zcu_import = wasm.addZcuImportReserved(ext.owner_nav);
2811 wasm.function_imports.putAssumeCapacity(name, .fromZcuImport(zcu_import, wasm));2938 wasm.function_imports.putAssumeCapacity(name, .fromZcuImport(zcu_import, wasm));
2812 // Ensure there is a corresponding function type table entry.2939 // Ensure there is a corresponding function type table entry.
2813 const fn_info = zcu.typeToFunc(.fromInterned(ext.ty)).?;2940 const fn_info = zcu.typeToFunc(.fromInterned(ext.ty)).?;
2814 _ = try internFunctionType(wasm, fn_info.cc, fn_info.param_types.get(ip), .fromInterned(fn_info.return_type), target);2941 _ = try internFunctionType(wasm, fn_info.cc, fn_info.param_types.get(ip), .fromInterned(fn_info.return_type), target);
2815 } else {2942 } else {
2816 @panic("TODO extern data");2943 wasm.data_imports.putAssumeCapacity(name, .fromZcuImport(zcu_import, wasm));
2817 }2944 }
2818 return;2945 return;
2819 },2946 },
...@@ -3023,6 +3150,12 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v...@@ -3023,6 +3150,12 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v
3023 try markTableImport(wasm, name, import, @enumFromInt(i));3150 try markTableImport(wasm, name, import, @enumFromInt(i));
3024 }3151 }
3025 }3152 }
3153
3154 for (wasm.object_data_imports.keys(), wasm.object_data_imports.values(), 0..) |name, *import, i| {
3155 if (import.flags.isIncluded(rdynamic)) {
3156 try markDataImport(wasm, name, import, @enumFromInt(i));
3157 }
3158 }
3026}3159}
30273160
3028fn markFunctionImport(3161fn markFunctionImport(
...@@ -3163,13 +3296,45 @@ fn markTableImport(...@@ -3163,13 +3296,45 @@ fn markTableImport(
3163}3296}
31643297
3165fn markDataSegment(wasm: *Wasm, segment_index: ObjectDataSegment.Index) link.File.FlushError!void {3298fn markDataSegment(wasm: *Wasm, segment_index: ObjectDataSegment.Index) link.File.FlushError!void {
3299 const comp = wasm.base.comp;
3166 const segment = segment_index.ptr(wasm);3300 const segment = segment_index.ptr(wasm);
3167 if (segment.flags.alive) return;3301 if (segment.flags.alive) return;
3168 segment.flags.alive = true;3302 segment.flags.alive = true;
31693303
3304 wasm.any_passive_inits = wasm.any_passive_inits or segment.flags.is_passive or
3305 (comp.config.import_memory and !wasm.isBss(segment.name));
3306
3307 try wasm.data_segments.put(comp.gpa, .pack(wasm, .{ .object = segment_index }), {});
3170 try wasm.markRelocations(segment.relocations(wasm));3308 try wasm.markRelocations(segment.relocations(wasm));
3171}3309}
31723310
3311fn markDataImport(
3312 wasm: *Wasm,
3313 name: String,
3314 import: *ObjectDataImport,
3315 data_index: ObjectDataImport.Index,
3316) link.File.FlushError!void {
3317 if (import.flags.alive) return;
3318 import.flags.alive = true;
3319
3320 const comp = wasm.base.comp;
3321 const gpa = comp.gpa;
3322
3323 if (import.resolution == .unresolved) {
3324 if (name == wasm.preloaded_strings.__heap_base) {
3325 import.resolution = .__heap_base;
3326 wasm.data_segments.putAssumeCapacity(.__heap_base, {});
3327 } else if (name == wasm.preloaded_strings.__heap_end) {
3328 import.resolution = .__heap_end;
3329 wasm.data_segments.putAssumeCapacity(.__heap_end, {});
3330 } else {
3331 try wasm.data_imports.put(gpa, name, .fromObject(data_index, wasm));
3332 }
3333 } else {
3334 try markDataSegment(wasm, import.resolution.toDataId().?.unpack(wasm).object);
3335 }
3336}
3337
3173fn markRelocations(wasm: *Wasm, relocs: ObjectRelocation.IterableSlice) link.File.FlushError!void {3338fn markRelocations(wasm: *Wasm, relocs: ObjectRelocation.IterableSlice) link.File.FlushError!void {
3174 for (relocs.slice.tags(wasm), relocs.slice.pointees(wasm), relocs.slice.offsets(wasm)) |tag, pointee, offset| {3339 for (relocs.slice.tags(wasm), relocs.slice.pointees(wasm), relocs.slice.offsets(wasm)) |tag, pointee, offset| {
3175 if (offset >= relocs.end) break;3340 if (offset >= relocs.end) break;
...@@ -3199,6 +3364,22 @@ fn markRelocations(wasm: *Wasm, relocs: ObjectRelocation.IterableSlice) link.Fil...@@ -3199,6 +3364,22 @@ fn markRelocations(wasm: *Wasm, relocs: ObjectRelocation.IterableSlice) link.Fil
3199 const i: TableImport.Index = @enumFromInt(wasm.object_table_imports.getIndex(name).?);3364 const i: TableImport.Index = @enumFromInt(wasm.object_table_imports.getIndex(name).?);
3200 try markTableImport(wasm, name, i.value(wasm), i);3365 try markTableImport(wasm, name, i.value(wasm), i);
3201 },3366 },
3367 .memory_addr_import_leb,
3368 .memory_addr_import_sleb,
3369 .memory_addr_import_i32,
3370 .memory_addr_import_rel_sleb,
3371 .memory_addr_import_leb64,
3372 .memory_addr_import_sleb64,
3373 .memory_addr_import_i64,
3374 .memory_addr_import_rel_sleb64,
3375 .memory_addr_import_tls_sleb,
3376 .memory_addr_import_locrel_i32,
3377 .memory_addr_import_tls_sleb64,
3378 => {
3379 const name = pointee.symbol_name;
3380 const i = ObjectDataImport.Index.fromSymbolName(wasm, name).?;
3381 try markDataImport(wasm, name, i.value(wasm), i);
3382 },
32023383
3203 .function_index_leb,3384 .function_index_leb,
3204 .function_index_i32,3385 .function_index_i32,
...@@ -3220,26 +3401,6 @@ fn markRelocations(wasm: *Wasm, relocs: ObjectRelocation.IterableSlice) link.Fil...@@ -3220,26 +3401,6 @@ fn markRelocations(wasm: *Wasm, relocs: ObjectRelocation.IterableSlice) link.Fil
3220 .section_offset_i32 => {3401 .section_offset_i32 => {
3221 log.warn("TODO: ensure section {d} is included in output", .{pointee.section});3402 log.warn("TODO: ensure section {d} is included in output", .{pointee.section});
3222 },3403 },
3223 .memory_addr_import_leb,
3224 .memory_addr_import_sleb,
3225 .memory_addr_import_i32,
3226 .memory_addr_import_rel_sleb,
3227 .memory_addr_import_leb64,
3228 .memory_addr_import_sleb64,
3229 .memory_addr_import_i64,
3230 .memory_addr_import_rel_sleb64,
3231 .memory_addr_import_tls_sleb,
3232 .memory_addr_import_locrel_i32,
3233 .memory_addr_import_tls_sleb64,
3234 => {
3235 const name = pointee.symbol_name;
3236 if (name == wasm.preloaded_strings.__heap_end or
3237 name == wasm.preloaded_strings.__heap_base)
3238 {
3239 continue;
3240 }
3241 log.warn("TODO: ensure data symbol {s} is included in output", .{name.slice(wasm)});
3242 },
32433404
3244 .memory_addr_leb,3405 .memory_addr_leb,
3245 .memory_addr_sleb,3406 .memory_addr_sleb,
...@@ -3309,6 +3470,7 @@ pub fn flushModule(...@@ -3309,6 +3470,7 @@ pub fn flushModule(
3309 try wasm.flush_buffer.missing_exports.reinit(gpa, wasm.missing_exports.keys(), &.{});3470 try wasm.flush_buffer.missing_exports.reinit(gpa, wasm.missing_exports.keys(), &.{});
3310 try wasm.flush_buffer.function_imports.reinit(gpa, wasm.function_imports.keys(), wasm.function_imports.values());3471 try wasm.flush_buffer.function_imports.reinit(gpa, wasm.function_imports.keys(), wasm.function_imports.values());
3311 try wasm.flush_buffer.global_imports.reinit(gpa, wasm.global_imports.keys(), wasm.global_imports.values());3472 try wasm.flush_buffer.global_imports.reinit(gpa, wasm.global_imports.keys(), wasm.global_imports.values());
3473 try wasm.flush_buffer.data_imports.reinit(gpa, wasm.data_imports.keys(), wasm.data_imports.values());
33123474
3313 return wasm.flush_buffer.finish(wasm) catch |err| switch (err) {3475 return wasm.flush_buffer.finish(wasm) catch |err| switch (err) {
3314 error.OutOfMemory => return error.OutOfMemory,3476 error.OutOfMemory => return error.OutOfMemory,
...@@ -4117,6 +4279,15 @@ fn pointerAlignment(wasm: *const Wasm) Alignment {...@@ -4117,6 +4279,15 @@ fn pointerAlignment(wasm: *const Wasm) Alignment {
4117 };4279 };
4118}4280}
41194281
4282fn pointerSize(wasm: *const Wasm) u32 {
4283 const target = &wasm.base.comp.root_mod.resolved_target.result;
4284 return switch (target.cpu.arch) {
4285 .wasm32 => 4,
4286 .wasm64 => 8,
4287 else => unreachable,
4288 };
4289}
4290
4120fn addZcuImportReserved(wasm: *Wasm, nav_index: InternPool.Nav.Index) ZcuImportIndex {4291fn addZcuImportReserved(wasm: *Wasm, nav_index: InternPool.Nav.Index) ZcuImportIndex {
4121 const gop = wasm.imports.getOrPutAssumeCapacity(nav_index);4292 const gop = wasm.imports.getOrPutAssumeCapacity(nav_index);
4122 gop.value_ptr.* = {};4293 gop.value_ptr.* = {};
src/link/Wasm/Flush.zig+15-14
...@@ -32,6 +32,7 @@ binary_bytes: std.ArrayListUnmanaged(u8) = .empty,...@@ -32,6 +32,7 @@ binary_bytes: std.ArrayListUnmanaged(u8) = .empty,
32missing_exports: std.AutoArrayHashMapUnmanaged(String, void) = .empty,32missing_exports: std.AutoArrayHashMapUnmanaged(String, void) = .empty,
33function_imports: std.AutoArrayHashMapUnmanaged(String, Wasm.FunctionImportId) = .empty,33function_imports: std.AutoArrayHashMapUnmanaged(String, Wasm.FunctionImportId) = .empty,
34global_imports: std.AutoArrayHashMapUnmanaged(String, Wasm.GlobalImportId) = .empty,34global_imports: std.AutoArrayHashMapUnmanaged(String, Wasm.GlobalImportId) = .empty,
35data_imports: std.AutoArrayHashMapUnmanaged(String, Wasm.DataImportId) = .empty,
3536
36/// For debug purposes only.37/// For debug purposes only.
37memory_layout_finished: bool = false,38memory_layout_finished: bool = false,
...@@ -50,6 +51,7 @@ pub fn deinit(f: *Flush, gpa: Allocator) void {...@@ -50,6 +51,7 @@ pub fn deinit(f: *Flush, gpa: Allocator) void {
50 f.missing_exports.deinit(gpa);51 f.missing_exports.deinit(gpa);
51 f.function_imports.deinit(gpa);52 f.function_imports.deinit(gpa);
52 f.global_imports.deinit(gpa);53 f.global_imports.deinit(gpa);
54 f.data_imports.deinit(gpa);
53 f.* = undefined;55 f.* = undefined;
54}56}
5557
...@@ -108,7 +110,9 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -108,7 +110,9 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
108 .global_index = Wasm.GlobalIndex.fromIpNav(wasm, nav_export.nav_index).?,110 .global_index = Wasm.GlobalIndex.fromIpNav(wasm, nav_export.nav_index).?,
109 });111 });
110 _ = f.missing_exports.swapRemove(nav_export.name);112 _ = f.missing_exports.swapRemove(nav_export.name);
111 _ = f.global_imports.swapRemove(nav_export.name);113 _ = f.data_imports.swapRemove(nav_export.name);
114 // `f.global_imports` is ignored because Zcu has no way to
115 // export wasm globals.
112 }116 }
113 }117 }
114118
...@@ -139,6 +143,10 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -139,6 +143,10 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
139 const src_loc = table_import_id.value(wasm).source_location;143 const src_loc = table_import_id.value(wasm).source_location;
140 src_loc.addError(wasm, "undefined table: {s}", .{name.slice(wasm)});144 src_loc.addError(wasm, "undefined table: {s}", .{name.slice(wasm)});
141 }145 }
146 for (f.data_imports.keys(), f.data_imports.values()) |name, data_import_id| {
147 const src_loc = data_import_id.sourceLocation(wasm);
148 src_loc.addError(wasm, "undefined data: {s}", .{name.slice(wasm)});
149 }
142 }150 }
143151
144 if (diags.hasErrors()) return error.LinkFailure;152 if (diags.hasErrors()) return error.LinkFailure;
...@@ -151,11 +159,9 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -151,11 +159,9 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
151 try wasm.functions.put(gpa, .__wasm_call_ctors, {});159 try wasm.functions.put(gpa, .__wasm_call_ctors, {});
152 }160 }
153161
154 var any_passive_inits = false;
155
156 // Merge and order the data segments. Depends on garbage collection so that162 // Merge and order the data segments. Depends on garbage collection so that
157 // unused segments can be omitted.163 // unused segments can be omitted.
158 try f.data_segments.ensureUnusedCapacity(gpa, wasm.object_data_segments.items.len +164 try f.data_segments.ensureUnusedCapacity(gpa, wasm.data_segments.entries.len +
159 wasm.uavs_obj.entries.len + wasm.navs_obj.entries.len +165 wasm.uavs_obj.entries.len + wasm.navs_obj.entries.len +
160 wasm.uavs_exe.entries.len + wasm.navs_exe.entries.len + 2);166 wasm.uavs_exe.entries.len + wasm.navs_exe.entries.len + 2);
161 if (is_obj) assert(wasm.uavs_exe.entries.len == 0);167 if (is_obj) assert(wasm.uavs_exe.entries.len == 0);
...@@ -174,18 +180,11 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -174,18 +180,11 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
174 for (0..wasm.navs_exe.entries.len) |navs_index| f.data_segments.putAssumeCapacityNoClobber(.pack(wasm, .{180 for (0..wasm.navs_exe.entries.len) |navs_index| f.data_segments.putAssumeCapacityNoClobber(.pack(wasm, .{
175 .nav_exe = @enumFromInt(navs_index),181 .nav_exe = @enumFromInt(navs_index),
176 }), @as(u32, undefined));182 }), @as(u32, undefined));
177 for (wasm.object_data_segments.items, 0..) |*ds, i| {
178 if (!ds.flags.alive) continue;
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));
181 _ = f.data_segments.putAssumeCapacityNoClobber(.pack(wasm, .{
182 .object = obj_seg_index,
183 }), @as(u32, undefined));
184 }
185 if (wasm.error_name_table_ref_count > 0) {183 if (wasm.error_name_table_ref_count > 0) {
186 f.data_segments.putAssumeCapacity(.__zig_error_names, @as(u32, undefined));184 f.data_segments.putAssumeCapacity(.__zig_error_names, @as(u32, undefined));
187 f.data_segments.putAssumeCapacity(.__zig_error_name_table, @as(u32, undefined));185 f.data_segments.putAssumeCapacity(.__zig_error_name_table, @as(u32, undefined));
188 }186 }
187 for (wasm.data_segments.keys()) |data_id| f.data_segments.putAssumeCapacity(data_id, @as(u32, undefined));
189188
190 try wasm.functions.ensureUnusedCapacity(gpa, 3);189 try wasm.functions.ensureUnusedCapacity(gpa, 3);
191190
...@@ -194,7 +193,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -194,7 +193,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
194 // dropped in __wasm_init_memory, which is registered as the start function193 // dropped in __wasm_init_memory, which is registered as the start function
195 // We also initialize bss segments (using memory.fill) as part of this194 // We also initialize bss segments (using memory.fill) as part of this
196 // function.195 // function.
197 if (any_passive_inits) {196 if (wasm.any_passive_inits) {
198 wasm.functions.putAssumeCapacity(.__wasm_init_memory, {});197 wasm.functions.putAssumeCapacity(.__wasm_init_memory, {});
199 }198 }
200199
...@@ -349,7 +348,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -349,7 +348,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
349 if (category != .zero) try f.data_segment_groups.append(gpa, @intCast(memory_ptr));348 if (category != .zero) try f.data_segment_groups.append(gpa, @intCast(memory_ptr));
350 }349 }
351350
352 if (shared_memory and any_passive_inits) {351 if (shared_memory and wasm.any_passive_inits) {
353 memory_ptr = pointer_alignment.forward(memory_ptr);352 memory_ptr = pointer_alignment.forward(memory_ptr);
354 virtual_addrs.init_memory_flag = @intCast(memory_ptr);353 virtual_addrs.init_memory_flag = @intCast(memory_ptr);
355 memory_ptr += 4;354 memory_ptr += 4;
...@@ -774,6 +773,8 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -774,6 +773,8 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
774 const code_start = binary_bytes.items.len;773 const code_start = binary_bytes.items.len;
775 append: {774 append: {
776 const code = switch (segment_id.unpack(wasm)) {775 const code = switch (segment_id.unpack(wasm)) {
776 .__heap_base => @panic("TODO"),
777 .__heap_end => @panic("TODO"),
777 .__zig_error_names => {778 .__zig_error_names => {
778 try binary_bytes.appendSlice(gpa, wasm.error_name_bytes.items);779 try binary_bytes.appendSlice(gpa, wasm.error_name_bytes.items);
779 break :append;780 break :append;
src/link/Wasm/Object.zig+59-15
...@@ -26,14 +26,16 @@ start_function: Wasm.OptionalObjectFunctionIndex,...@@ -26,14 +26,16 @@ start_function: Wasm.OptionalObjectFunctionIndex,
26/// (or therefore missing) and must generate an error when another object uses26/// (or therefore missing) and must generate an error when another object uses
27/// features that are not supported by the other.27/// features that are not supported by the other.
28features: Wasm.Feature.Set,28features: Wasm.Feature.Set,
29/// Points into Wasm object_functions29/// Points into `Wasm.object_functions`
30functions: RelativeSlice,30functions: RelativeSlice,
31/// Points into Wasm object_function_imports31/// Points into `Wasm.object_function_imports`
32function_imports: RelativeSlice,32function_imports: RelativeSlice,
33/// Points into Wasm object_global_imports33/// Points into `Wasm.object_global_imports`
34global_imports: RelativeSlice,34global_imports: RelativeSlice,
35/// Points into Wasm object_table_imports35/// Points into `Wasm.object_table_imports`
36table_imports: RelativeSlice,36table_imports: RelativeSlice,
37// Points into `Wasm.object_data_imports`
38data_imports: RelativeSlice,
37/// Points into Wasm object_custom_segments39/// Points into Wasm object_custom_segments
38custom_segments: RelativeSlice,40custom_segments: RelativeSlice,
39/// Points into Wasm object_init_funcs41/// Points into Wasm object_init_funcs
...@@ -280,6 +282,7 @@ pub fn parse(...@@ -280,6 +282,7 @@ pub fn parse(
280 const function_imports_start: u32 = @intCast(wasm.object_function_imports.entries.len);282 const function_imports_start: u32 = @intCast(wasm.object_function_imports.entries.len);
281 const global_imports_start: u32 = @intCast(wasm.object_global_imports.entries.len);283 const global_imports_start: u32 = @intCast(wasm.object_global_imports.entries.len);
282 const table_imports_start: u32 = @intCast(wasm.object_table_imports.entries.len);284 const table_imports_start: u32 = @intCast(wasm.object_table_imports.entries.len);
285 const data_imports_start: u32 = @intCast(wasm.object_data_imports.entries.len);
283 const local_section_index_base = wasm.object_total_sections;286 const local_section_index_base = wasm.object_total_sections;
284 const object_index: Wasm.ObjectIndex = @enumFromInt(wasm.objects.items.len);287 const object_index: Wasm.ObjectIndex = @enumFromInt(wasm.objects.items.len);
285 const source_location: Wasm.SourceLocation = .fromObject(object_index, wasm);288 const source_location: Wasm.SourceLocation = .fromObject(object_index, wasm);
...@@ -1087,6 +1090,19 @@ pub fn parse(...@@ -1087,6 +1090,19 @@ pub fn parse(
1087 gop.value_ptr.flags.ref_type = .from(ptr.ref_type);1090 gop.value_ptr.flags.ref_type = .from(ptr.ref_type);
1088 }1091 }
1089 },1092 },
1093 .data_import => {
1094 const name = symbol.name.unwrap().?;
1095 if (symbol.flags.binding == .local) {
1096 diags.addParseError(path, "local symbol '{s}' references import", .{name.slice(wasm)});
1097 continue;
1098 }
1099 const gop = try wasm.object_data_imports.getOrPut(gpa, name);
1100 if (!gop.found_existing) gop.value_ptr.* = .{
1101 .flags = symbol.flags,
1102 .source_location = source_location,
1103 .resolution = .unresolved,
1104 };
1105 },
1090 .function => |index| {1106 .function => |index| {
1091 assert(!symbol.flags.undefined);1107 assert(!symbol.flags.undefined);
1092 const ptr = index.ptr(wasm);1108 const ptr = index.ptr(wasm);
...@@ -1134,12 +1150,13 @@ pub fn parse(...@@ -1134,12 +1150,13 @@ pub fn parse(
1134 }1150 }
1135 },1151 },
1136 .global => |index| {1152 .global => |index| {
1153 assert(!symbol.flags.undefined);
1137 const ptr = index.ptr(wasm);1154 const ptr = index.ptr(wasm);
1138 ptr.name = symbol.name;1155 ptr.name = symbol.name;
1139 ptr.flags = symbol.flags;1156 ptr.flags = symbol.flags;
1140 if (symbol.flags.binding == .local) continue; // No participation in symbol resolution.1157 if (symbol.flags.binding == .local) continue; // No participation in symbol resolution.
1141 const new_ty = ptr.type();
1142 const name = symbol.name.unwrap().?;1158 const name = symbol.name.unwrap().?;
1159 const new_ty = ptr.type();
1143 const gop = try wasm.object_global_imports.getOrPut(gpa, name);1160 const gop = try wasm.object_global_imports.getOrPut(gpa, name);
1144 if (gop.found_existing) {1161 if (gop.found_existing) {
1145 const existing_ty = gop.value_ptr.type();1162 const existing_ty = gop.value_ptr.type();
...@@ -1192,12 +1209,42 @@ pub fn parse(...@@ -1192,12 +1209,42 @@ pub fn parse(
1192 }1209 }
1193 },1210 },
1194 .table => |i| {1211 .table => |i| {
1212 assert(!symbol.flags.undefined);
1195 const ptr = i.ptr(wasm);1213 const ptr = i.ptr(wasm);
1196 ptr.name = symbol.name;1214 ptr.name = symbol.name;
1197 ptr.flags = symbol.flags;1215 ptr.flags = symbol.flags;
1198 if (symbol.flags.undefined and symbol.flags.binding == .local) {1216 },
1199 const name = ptr.name.slice(wasm).?;1217 .data => |index| {
1200 diags.addParseError(path, "local symbol '{s}' references import", .{name});1218 assert(!symbol.flags.undefined);
1219 const ptr = index.ptr(wasm);
1220 const name = ptr.name;
1221 assert(name.toOptional() == symbol.name);
1222 ptr.flags = symbol.flags;
1223 if (symbol.flags.binding == .local) continue; // No participation in symbol resolution.
1224 const gop = try wasm.object_data_imports.getOrPut(gpa, name);
1225 if (gop.found_existing) {
1226 if (gop.value_ptr.resolution == .unresolved or gop.value_ptr.flags.binding == .weak) {
1227 // Intentional: if they're both weak, take the last one.
1228 gop.value_ptr.source_location = source_location;
1229 gop.value_ptr.resolution = .fromObjectDataIndex(wasm, index);
1230 gop.value_ptr.flags = symbol.flags;
1231 continue;
1232 }
1233 if (ptr.flags.binding == .weak) {
1234 // Keep the existing one.
1235 continue;
1236 }
1237 var err = try diags.addErrorWithNotes(2);
1238 try err.addMsg("symbol collision: {s}", .{name.slice(wasm)});
1239 gop.value_ptr.source_location.addNote(&err, "exported here", .{});
1240 source_location.addNote(&err, "exported here", .{});
1241 continue;
1242 } else {
1243 gop.value_ptr.* = .{
1244 .flags = symbol.flags,
1245 .source_location = source_location,
1246 .resolution = .unresolved,
1247 };
1201 }1248 }
1202 },1249 },
1203 .section => |i| {1250 .section => |i| {
...@@ -1210,13 +1257,6 @@ pub fn parse(...@@ -1210,13 +1257,6 @@ pub fn parse(
1210 diags.addParseError(path, "local symbol '{s}' references import", .{name});1257 diags.addParseError(path, "local symbol '{s}' references import", .{name});
1211 }1258 }
1212 },1259 },
1213 .data_import => {
1214 if (symbol.flags.undefined and symbol.flags.binding == .local) {
1215 const name = symbol.name.slice(wasm).?;
1216 diags.addParseError(path, "local symbol '{s}' references import", .{name});
1217 }
1218 },
1219 .data => continue, // `wasm.object_datas` has already been populated.
1220 };1260 };
12211261
1222 // Apply export section info. This is done after the symbol table above so1262 // Apply export section info. This is done after the symbol table above so
...@@ -1317,6 +1357,10 @@ pub fn parse(...@@ -1317,6 +1357,10 @@ pub fn parse(
1317 .off = table_imports_start,1357 .off = table_imports_start,
1318 .len = @intCast(wasm.object_table_imports.entries.len - table_imports_start),1358 .len = @intCast(wasm.object_table_imports.entries.len - table_imports_start),
1319 },1359 },
1360 .data_imports = .{
1361 .off = data_imports_start,
1362 .len = @intCast(wasm.object_data_imports.entries.len - data_imports_start),
1363 },
1320 .init_funcs = .{1364 .init_funcs = .{
1321 .off = init_funcs_start,1365 .off = init_funcs_start,
1322 .len = @intCast(wasm.object_init_funcs.items.len - init_funcs_start),1366 .len = @intCast(wasm.object_init_funcs.items.len - init_funcs_start),