authorgravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2026-07-26 22:01:41+02:00
committergravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2026-07-28 22:42:11+02:00
loge045b77d9981434af7e87512f94ecfe5b9dc376f
tree1e5f06f7b401e6fe6c148e4503a832eeb185e401
parentde5c25420b05aab47346a7cd4c8d9def85b9d0f9

stage2-wasm: linker emit obj + fixes/hacks


15 files changed, 2177 insertions(+), 474 deletions(-)

src/Compilation.zig+4-4
......@@ -3675,11 +3675,11 @@ pub fn saveState(comp: *Compilation) !void {
36753675 addBuf(&bufs, @ptrCast(wasm.object_relocations_table.values()));
36763676 addBuf(&bufs, @ptrCast(wasm.object_comdat_symbols.items(.kind)));
36773677 addBuf(&bufs, @ptrCast(wasm.object_comdat_symbols.items(.index)));
3678 addBuf(&bufs, @ptrCast(wasm.out_relocs.items(.tag)));
3679 addBuf(&bufs, @ptrCast(wasm.out_relocs.items(.offset)));
3678 addBuf(&bufs, @ptrCast(wasm.zcu_relocations.items(.tag)));
3679 addBuf(&bufs, @ptrCast(wasm.zcu_relocations.items(.offset)));
36803680 // TODO handle the union safety field
3681 //addBuf(&bufs, @ptrCast(wasm.out_relocs.items(.pointee)));
3682 addBuf(&bufs, @ptrCast(wasm.out_relocs.items(.addend)));
3681 //addBuf(&bufs, @ptrCast(wasm.zcu_relocations.items(.pointee)));
3682 addBuf(&bufs, @ptrCast(wasm.zcu_relocations.items(.addend)));
36833683 addBuf(&bufs, @ptrCast(wasm.uav_fixups.items));
36843684 addBuf(&bufs, @ptrCast(wasm.nav_fixups.items));
36853685 addBuf(&bufs, @ptrCast(wasm.func_table_fixups.items));
src/codegen.zig+1-30
......@@ -767,11 +767,9 @@ fn lowerNavRef(
767767 offset: u64,
768768) (Error || std.Io.Writer.Error)!void {
769769 const zcu = pt.zcu;
770 const gpa = zcu.gpa;
771770 const ip = &zcu.intern_pool;
772771 const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result;
773772 const ptr_width_bytes = @divExact(target.ptrBitWidth(), 8);
774 const is_obj = lf.comp.config.output_mode == .Obj;
775773 const nav_ty = Type.fromInterned(ip.getNav(nav_index).resolved.?.type);
776774
777775 if (!nav_ty.isRuntimeFnOrHasRuntimeBits(zcu) and ip.getNav(nav_index).getExtern(ip) == null) {
......@@ -786,34 +784,7 @@ fn lowerNavRef(
786784 dev.check(link.File.Tag.wasm.devFeature());
787785 const wasm = lf.cast(.wasm).?;
788786 assert(reloc_parent == .none);
789 if (nav_ty.zigTypeTag(zcu) == .@"fn") {
790 const gop = try wasm.zcu_indirect_function_set.getOrPut(gpa, nav_index);
791 if (!gop.found_existing) gop.value_ptr.* = {};
792 if (is_obj) {
793 @panic("TODO add out_reloc for this");
794 } else {
795 try wasm.func_table_fixups.append(gpa, .{
796 .table_index = @fromBackingInt(@intCast(gop.index)),
797 .offset = @intCast(w.end),
798 });
799 }
800 } else {
801 if (is_obj) {
802 try wasm.out_relocs.append(gpa, .{
803 .offset = @intCast(w.end),
804 .pointee = .{ .symbol_index = try wasm.navSymbolIndex(nav_index) },
805 .tag = if (ptr_width_bytes == 4) .memory_addr_i32 else .memory_addr_i64,
806 .addend = @intCast(offset),
807 });
808 } else {
809 try wasm.nav_fixups.ensureUnusedCapacity(gpa, 1);
810 wasm.nav_fixups.appendAssumeCapacity(.{
811 .navs_exe_index = try wasm.refNavExe(nav_index),
812 .offset = @intCast(w.end),
813 .addend = @intCast(offset),
814 });
815 }
816 }
787 try wasm.addNavReloc(w.end, nav_index, nav_ty, @intCast(offset));
817788 try w.splatByteAll(0, ptr_width_bytes);
818789 return;
819790 },
src/codegen/wasm/CodeGen.zig+4-1
......@@ -4923,7 +4923,8 @@ fn lowerPtr(cg: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerErro
49234923 const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr;
49244924 const offset: u64 = prev_offset + ptr.byte_offset;
49254925 return switch (ptr.base_addr) {
4926 .nav => |nav| return if (Type.fromInterned(ip.getNav(nav).resolved.?.type).isRuntimeFnOrHasRuntimeBits(zcu))
4926 .nav => |nav| return if (ip.getNav(nav).getExtern(ip) != null or
4927 Type.fromInterned(ip.getNav(nav).resolved.?.type).isRuntimeFnOrHasRuntimeBits(zcu))
49274928 .{ .nav_ref = .{ .nav_index = nav, .offset = @intCast(offset) } }
49284929 else
49294930 .{ .imm32 = @intCast(zcu.navAlignment(nav).forward(@as(u32, 0xaaaaaaaa))) },
......@@ -5607,6 +5608,8 @@ fn bitcastClass(cg: *CodeGen, ty: Type) BitcastClass {
56075608}
56085609
56095610fn bitcast(cg: *CodeGen, dest_ty: Type, src_ty: Type, operand: WValue) InnerError!?WValue {
5611 if (dest_ty.eql(src_ty)) return null;
5612
56105613 const zcu = cg.pt.zcu;
56115614 const src_class = cg.bitcastClass(src_ty);
56125615 const dest_class = cg.bitcastClass(dest_ty);
src/codegen/wasm/Emit.zig+123-47
......@@ -21,7 +21,7 @@ pub const Error = error{
2121 OutOfMemory,
2222};
2323
24pub fn lowerToCode(emit: *Emit) Error!void {
24pub fn lower(emit: *Emit) Error!void {
2525 const mir = &emit.mir;
2626 const code = emit.code;
2727 const wasm = emit.wasm;
......@@ -31,6 +31,47 @@ pub fn lowerToCode(emit: *Emit) Error!void {
3131 const target = &comp.root_mod.resolved_target.result;
3232 const is_wasm32 = target.cpu.arch == .wasm32;
3333
34 // Write the locals in the prologue of the function body.
35 try code.ensureUnusedCapacity(gpa, 5 + mir.locals.len * 6 + 38);
36
37 writeUleb128(code, @as(u32, @intCast(mir.locals.len)));
38
39 for (mir.locals) |local| {
40 writeUleb128(code, @as(u32, 1));
41 code.appendAssumeCapacity(@backingInt(local));
42 }
43
44 // Stack management section of function prologue.
45 const stack_alignment = mir.prologue.flags.stack_alignment;
46 if (stack_alignment.toByteUnits()) |align_bytes| {
47 // load stack pointer
48 code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.global_get));
49 try appendStackPointerGlobalIndex(wasm, code, is_obj);
50 // store stack pointer so we can restore it when we return from the function
51 code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.local_tee));
52 writeUleb128(code, mir.prologue.sp_local);
53 // get the total stack size
54 const aligned_stack: i32 = @intCast(stack_alignment.forward(mir.prologue.stack_size));
55 code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.i32_const));
56 writeSleb128(code, aligned_stack);
57 // subtract it from the current stack pointer
58 code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.i32_sub));
59 // Get negative stack alignment
60 const neg_stack_align = @as(i32, @intCast(align_bytes)) * -1;
61 code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.i32_const));
62 writeSleb128(code, neg_stack_align);
63 // Bitwise-and the value to get the new stack pointer to ensure the
64 // pointers are aligned with the abi alignment.
65 code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.i32_and));
66 // The bottom will be used to calculate all stack pointer offsets.
67 code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.local_tee));
68 writeUleb128(code, mir.prologue.bottom_stack_local);
69 // Store the current stack pointer value into the global stack pointer so other function calls will
70 // start from this value instead and not overwrite the current stack.
71 code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.global_set));
72 try appendStackPointerGlobalIndex(wasm, code, is_obj);
73 }
74
3475 const tags = mir.instructions.items(.tag);
3576 const datas = mir.instructions.items(.data);
3677 var inst: u32 = 0;
......@@ -78,14 +119,21 @@ pub fn lowerToCode(emit: *Emit) Error!void {
78119 continue :loop tags[inst];
79120 },
80121 .func_ref => {
81 const indirect_func_idx: Wasm.ZcuIndirectFunctionSetIndex = @fromBackingInt(@intCast(
82 wasm.zcu_indirect_function_set.getIndex(datas[inst].nav_index).?,
83 ));
84 code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.i32_const));
122 try code.ensureUnusedCapacity(gpa, 11);
123 const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const;
124 code.appendAssumeCapacity(@backingInt(opcode));
85125 if (is_obj) {
86 @panic("TODO");
126 try wasm.zcu_relocations.append(gpa, .{
127 .offset = @intCast(code.items.len),
128 .pointee = .{ .function_nav = datas[inst].nav_index },
129 .tag = if (is_wasm32) .table_index_sleb else .table_index_sleb64,
130 .addend = 0,
131 });
132 appendSlebRelocPlaceholder(code, is_wasm32);
87133 } else {
88 writeSleb128(code, 1 + @backingInt(indirect_func_idx));
134 const function_index = Wasm.OutputFunctionIndex.fromIpNav(wasm, datas[inst].nav_index);
135 const table_index = wasm.flush_buffer.indirect_function_table.getIndex(function_index).? + 1;
136 writeSleb128(code, table_index);
89137 }
90138 inst += 1;
91139 continue :loop tags[inst];
......@@ -105,18 +153,17 @@ pub fn lowerToCode(emit: *Emit) Error!void {
105153 continue :loop tags[inst];
106154 },
107155 .error_name_table_ref => {
108 wasm.error_name_table_ref_count += 1;
109156 try code.ensureUnusedCapacity(gpa, 11);
110157 const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const;
111158 code.appendAssumeCapacity(@backingInt(opcode));
112159 if (is_obj) {
113 try wasm.out_relocs.append(gpa, .{
160 try wasm.zcu_relocations.append(gpa, .{
114161 .offset = @intCast(code.items.len),
115 .pointee = .{ .symbol_index = try wasm.errorNameTableSymbolIndex() },
116 .tag = if (is_wasm32) .memory_addr_leb else .memory_addr_leb64,
162 .pointee = .{ .data_resolution = .__zig_error_name_table },
163 .tag = if (is_wasm32) .memory_addr_sleb else .memory_addr_sleb64,
117164 .addend = 0,
118165 });
119 code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10);
166 appendSlebRelocPlaceholder(code, is_wasm32);
120167
121168 inst += 1;
122169 continue :loop tags[inst];
......@@ -164,13 +211,13 @@ pub fn lowerToCode(emit: *Emit) Error!void {
164211 try code.ensureUnusedCapacity(gpa, 6);
165212 code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.call));
166213 if (is_obj) {
167 try wasm.out_relocs.append(gpa, .{
214 try wasm.zcu_relocations.append(gpa, .{
168215 .offset = @intCast(code.items.len),
169 .pointee = .{ .symbol_index = try wasm.navSymbolIndex(datas[inst].nav_index) },
216 .pointee = .{ .function_nav = datas[inst].nav_index },
170217 .tag = .function_index_leb,
171218 .addend = 0,
172219 });
173 code.appendNTimesAssumeCapacity(0, 5);
220 appendUlebRelocPlaceholder(code);
174221 } else {
175222 appendOutputFunctionIndex(code, .fromIpNav(wasm, datas[inst].nav_index));
176223 }
......@@ -191,13 +238,13 @@ pub fn lowerToCode(emit: *Emit) Error!void {
191238 ).?;
192239 if (is_obj) {
193240 code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.call_indirect));
194 try wasm.out_relocs.append(gpa, .{
241 try wasm.zcu_relocations.append(gpa, .{
195242 .offset = @intCast(code.items.len),
196243 .pointee = .{ .type_index = func_ty_index },
197244 .tag = .type_index_leb,
198245 .addend = 0,
199246 });
200 code.appendNTimesAssumeCapacity(0, 5);
247 appendUlebRelocPlaceholder(code);
201248 } else {
202249 const index: Wasm.Flush.FuncTypeIndex = @fromBackingInt(@intCast(wasm.flush_buffer.func_types.getIndex(func_ty_index) orelse {
203250 // In this case we tried to call a function pointer for
......@@ -224,13 +271,13 @@ pub fn lowerToCode(emit: *Emit) Error!void {
224271 try code.ensureUnusedCapacity(gpa, 6);
225272 code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.call));
226273 if (is_obj) {
227 try wasm.out_relocs.append(gpa, .{
274 try wasm.zcu_relocations.append(gpa, .{
228275 .offset = @intCast(code.items.len),
229 .pointee = .{ .symbol_index = try wasm.tagTableIndexSymbolIndex(datas[inst].ip_index) },
276 .pointee = .{ .tag_function = datas[inst].ip_index },
230277 .tag = .function_index_leb,
231278 .addend = 0,
232279 });
233 code.appendNTimesAssumeCapacity(0, 5);
280 appendUlebRelocPlaceholder(code);
234281 } else {
235282 appendOutputFunctionIndex(code, .fromTagIndexType(wasm, datas[inst].ip_index));
236283 }
......@@ -244,14 +291,20 @@ pub fn lowerToCode(emit: *Emit) Error!void {
244291 const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const;
245292 code.appendAssumeCapacity(@backingInt(opcode));
246293 if (is_obj) {
247 @panic("TODO");
294 try wasm.zcu_relocations.append(gpa, .{
295 .offset = @intCast(code.items.len),
296 .pointee = .{ .data_resolution = .__zig_tag_name_table },
297 .tag = if (is_wasm32) .memory_addr_sleb else .memory_addr_sleb64,
298 .addend = @intCast(wasm.tagIndexTableOffset(datas[inst].ip_index)),
299 });
300 appendSlebRelocPlaceholder(code, is_wasm32);
248301 } else {
249302 const addr: u32 = wasm.tagIndexTableAddr(datas[inst].ip_index);
250303 writeSleb128(code, addr);
251
252 inst += 1;
253 continue :loop tags[inst];
254304 }
305
306 inst += 1;
307 continue :loop tags[inst];
255308 },
256309
257310 .call_intrinsic => {
......@@ -263,13 +316,13 @@ pub fn lowerToCode(emit: *Emit) Error!void {
263316 try code.ensureUnusedCapacity(gpa, 6);
264317 code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.call));
265318 if (is_obj) {
266 try wasm.out_relocs.append(gpa, .{
319 try wasm.zcu_relocations.append(gpa, .{
267320 .offset = @intCast(code.items.len),
268 .pointee = .{ .symbol_index = try wasm.symbolNameIndex(symbol_name) },
321 .pointee = .{ .function_name = symbol_name },
269322 .tag = .function_index_leb,
270323 .addend = 0,
271324 });
272 code.appendNTimesAssumeCapacity(0, 5);
325 appendUlebRelocPlaceholder(code);
273326 } else {
274327 appendOutputFunctionIndex(code, .fromSymbolName(wasm, symbol_name));
275328 }
......@@ -281,18 +334,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
281334 .global_set_sp => {
282335 try code.ensureUnusedCapacity(gpa, 6);
283336 code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.global_set));
284 if (is_obj) {
285 try wasm.out_relocs.append(gpa, .{
286 .offset = @intCast(code.items.len),
287 .pointee = .{ .symbol_index = try wasm.stackPointerSymbolIndex() },
288 .tag = .global_index_leb,
289 .addend = 0,
290 });
291 code.appendNTimesAssumeCapacity(0, 5);
292 } else {
293 const sp_global: Wasm.GlobalIndex = .stack_pointer;
294 writeUleb128(code, @backingInt(sp_global));
295 }
337 try appendStackPointerGlobalIndex(wasm, code, is_obj);
296338
297339 inst += 1;
298340 continue :loop tags[inst];
......@@ -960,13 +1002,13 @@ fn uavRefObj(wasm: *Wasm, code: *ArrayList(u8), value: InternPool.Index, offset:
9601002 try code.ensureUnusedCapacity(gpa, 11);
9611003 code.appendAssumeCapacity(@backingInt(opcode));
9621004
963 try wasm.out_relocs.append(gpa, .{
1005 try wasm.zcu_relocations.append(gpa, .{
9641006 .offset = @intCast(code.items.len),
965 .pointee = .{ .symbol_index = try wasm.uavSymbolIndex(value) },
966 .tag = if (is_wasm32) .memory_addr_leb else .memory_addr_leb64,
1007 .pointee = .{ .data_uav = value },
1008 .tag = if (is_wasm32) .memory_addr_sleb else .memory_addr_sleb64,
9671009 .addend = offset,
9681010 });
969 code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10);
1011 appendSlebRelocPlaceholder(code, is_wasm32);
9701012}
9711013
9721014fn uavRefExe(wasm: *Wasm, code: *ArrayList(u8), value: InternPool.Index, offset: i32, is_wasm32: bool) !void {
......@@ -995,13 +1037,13 @@ fn navRefOff(wasm: *Wasm, code: *ArrayList(u8), data: Mir.NavRefOff, is_wasm32:
9951037 const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const;
9961038 code.appendAssumeCapacity(@backingInt(opcode));
9971039 if (is_obj) {
998 try wasm.out_relocs.append(gpa, .{
1040 try wasm.zcu_relocations.append(gpa, .{
9991041 .offset = @intCast(code.items.len),
1000 .pointee = .{ .symbol_index = try wasm.navSymbolIndex(data.nav_index) },
1001 .tag = if (is_wasm32) .memory_addr_leb else .memory_addr_leb64,
1042 .pointee = .{ .data_nav = data.nav_index },
1043 .tag = if (is_wasm32) .memory_addr_sleb else .memory_addr_sleb64,
10021044 .addend = data.offset,
10031045 });
1004 code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10);
1046 appendSlebRelocPlaceholder(code, is_wasm32);
10051047 } else {
10061048 const addr = wasm.navAddr(data.nav_index);
10071049 writeSleb128(code, @as(u32, @intCast(@as(i64, addr) + data.offset)));
......@@ -1012,6 +1054,40 @@ fn appendOutputFunctionIndex(code: *ArrayList(u8), i: Wasm.OutputFunctionIndex)
10121054 writeUleb128(code, @backingInt(i));
10131055}
10141056
1057fn appendStackPointerGlobalIndex(
1058 wasm: *Wasm,
1059 code: *ArrayList(u8),
1060 is_obj: bool,
1061) Error!void {
1062 if (is_obj) {
1063 try wasm.zcu_relocations.append(wasm.base.comp.gpa, .{
1064 .offset = @intCast(code.items.len),
1065 .pointee = .stack_pointer,
1066 .tag = .global_index_leb,
1067 .addend = 0,
1068 });
1069 appendUlebRelocPlaceholder(code);
1070 } else {
1071 const sp_global: Wasm.GlobalIndex = .stack_pointer;
1072 writeUleb128(code, @backingInt(sp_global));
1073 }
1074}
1075
1076fn appendUlebRelocPlaceholder(code: *ArrayList(u8)) void {
1077 code.appendSliceAssumeCapacity(&.{ 0x80, 0x80, 0x80, 0x80, 0x00 });
1078}
1079
1080fn appendSlebRelocPlaceholder(code: *ArrayList(u8), is_wasm32: bool) void {
1081 if (is_wasm32) {
1082 code.appendSliceAssumeCapacity(&.{ 0x80, 0x80, 0x80, 0x80, 0x00 });
1083 } else {
1084 code.appendSliceAssumeCapacity(&.{
1085 0x80, 0x80, 0x80, 0x80, 0x80,
1086 0x80, 0x80, 0x80, 0x80, 0x00,
1087 });
1088 }
1089}
1090
10151091fn writeUleb128(code: *ArrayList(u8), arg: anytype) void {
10161092 var w: std.Io.Writer = .fixed(code.unusedCapacitySlice());
10171093 w.writeUleb128(arg) catch unreachable;
src/codegen/wasm/Mir.zig+2-50
......@@ -114,7 +114,7 @@ pub const Inst = struct {
114114 ///
115115 /// Uses `payload` pointing to a `NavRefOff`.
116116 nav_ref_off,
117 /// Lowers to an i32_const which is the index of the function in the
117 /// Lowers to an iNN_const which is the index of the function in the
118118 /// table section.
119119 ///
120120 /// Uses `nav_index`.
......@@ -679,60 +679,12 @@ pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {
679679}
680680
681681pub fn lower(mir: *const Mir, wasm: *Wasm, code: *std.ArrayList(u8)) std.mem.Allocator.Error!void {
682 const gpa = wasm.base.comp.gpa;
683
684 // Write the locals in the prologue of the function body.
685 try code.ensureUnusedCapacity(gpa, 5 + mir.locals.len * 6 + 38);
686
687 var w: std.Io.Writer = .fixed(code.unusedCapacitySlice());
688
689 w.writeLeb128(@as(u32, @intCast(mir.locals.len))) catch unreachable;
690
691 for (mir.locals) |local| {
692 w.writeLeb128(@as(u32, 1)) catch unreachable;
693 w.writeByte(@backingInt(local)) catch unreachable;
694 }
695
696 // Stack management section of function prologue.
697 const stack_alignment = mir.prologue.flags.stack_alignment;
698 if (stack_alignment.toByteUnits()) |align_bytes| {
699 const sp_global: Wasm.GlobalIndex = .stack_pointer;
700 // load stack pointer
701 w.writeByte(@backingInt(std.wasm.Opcode.global_get)) catch unreachable;
702 w.writeUleb128(@backingInt(sp_global)) catch unreachable;
703 // store stack pointer so we can restore it when we return from the function
704 w.writeByte(@backingInt(std.wasm.Opcode.local_tee)) catch unreachable;
705 w.writeUleb128(mir.prologue.sp_local) catch unreachable;
706 // get the total stack size
707 const aligned_stack: i32 = @intCast(stack_alignment.forward(mir.prologue.stack_size));
708 w.writeByte(@backingInt(std.wasm.Opcode.i32_const)) catch unreachable;
709 w.writeSleb128(aligned_stack) catch unreachable;
710 // subtract it from the current stack pointer
711 w.writeByte(@backingInt(std.wasm.Opcode.i32_sub)) catch unreachable;
712 // Get negative stack alignment
713 const neg_stack_align = @as(i32, @intCast(align_bytes)) * -1;
714 w.writeByte(@backingInt(std.wasm.Opcode.i32_const)) catch unreachable;
715 w.writeSleb128(neg_stack_align) catch unreachable;
716 // Bitwise-and the value to get the new stack pointer to ensure the
717 // pointers are aligned with the abi alignment.
718 w.writeByte(@backingInt(std.wasm.Opcode.i32_and)) catch unreachable;
719 // The bottom will be used to calculate all stack pointer offsets.
720 w.writeByte(@backingInt(std.wasm.Opcode.local_tee)) catch unreachable;
721 w.writeUleb128(mir.prologue.bottom_stack_local) catch unreachable;
722 // Store the current stack pointer value into the global stack pointer so other function calls will
723 // start from this value instead and not overwrite the current stack.
724 w.writeByte(@backingInt(std.wasm.Opcode.global_set)) catch unreachable;
725 w.writeUleb128(@backingInt(sp_global)) catch unreachable;
726 }
727
728 code.items.len += w.end;
729
730682 var emit: Emit = .{
731683 .mir = mir.*,
732684 .wasm = wasm,
733685 .code = code,
734686 };
735 try emit.lowerToCode();
687 try emit.lower();
736688}
737689
738690pub fn extraData(self: *const Mir, comptime T: type, index: usize) struct { data: T, end: usize } {
src/link/Wasm.zig+927-189
......@@ -133,25 +133,21 @@ object_total_sections: u32 = 0,
133133/// All comdat symbols from all objects concatenated.
134134object_comdat_symbols: std.MultiArrayList(Comdat.Symbol) = .empty,
135135
136/// Relocations to be emitted into an object file. Remains empty when not
137/// emitting an object file.
138out_relocs: std.MultiArrayList(OutReloc) = .empty,
136/// Relocations produced by Zig code and data lowering. These retain semantic
137/// targets until `flush`, where final output indexes are known.
138zcu_relocations: std.MultiArrayList(ZcuRelocation) = .empty,
139139/// List of locations within `string_bytes` that must be patched with the virtual
140140/// memory address of a Uav during `flush`.
141/// When emitting an object file, `out_relocs` is used instead.
141/// When emitting an object file, `zcu_relocations` is used instead.
142142uav_fixups: std.ArrayList(UavFixup) = .empty,
143143/// List of locations within `string_bytes` that must be patched with the virtual
144144/// memory address of a Nav during `flush`.
145/// When emitting an object file, `out_relocs` is used instead.
145/// When emitting an object file, `zcu_relocations` is used instead.
146146/// No functions here only global variables.
147147nav_fixups: std.ArrayList(NavFixup) = .empty,
148148/// When a nav reference is a function pointer, this tracks the required function
149149/// table entry index that needs to overwrite the code in the final output.
150150func_table_fixups: std.ArrayList(FuncTableFixup) = .empty,
151/// Symbols to be emitted into an object file. Remains empty when not emitting
152/// an object file.
153symbol_table: std.array_hash_map.Auto(String, void) = .empty,
154
155151/// When importing objects from the host environment, a name must be supplied.
156152/// LLVM uses "env" by default when none is given.
157153/// This value is passed to object files since wasm tooling conventions provides
......@@ -244,7 +240,9 @@ function_imports: std.array_hash_map.Auto(String, FunctionImportId) = .empty,
244240/// remove elements from the table, and the remainder are either undefined
245241/// symbol errors, or symbol table entries depending on the output mode.
246242data_imports: std.array_hash_map.Auto(String, DataImportId) = .empty,
247/// Set of data symbols that will appear in the final binary. Used to populate
243/// Set of data symbols that will appear in the final binary when outputting an object file.
244datas: std.array_hash_map.Auto(ObjectDataImport.Resolution, void) = .empty,
245/// Set of data segment symbols that will appear in the final binary. Used to populate
248246/// `Flush.data_segments` before sorting.
249247data_segments: std.array_hash_map.Auto(DataSegmentId, void) = .empty,
250248
......@@ -302,11 +300,6 @@ pub const TagNameOff = extern struct {
302300 len: u32,
303301};
304302
305/// Index into `Wasm.zcu_indirect_function_set`.
306pub const ZcuIndirectFunctionSetIndex = enum(u32) {
307 _,
308};
309
310303pub const UavFixup = extern struct {
311304 uavs_exe_index: UavsExeIndex,
312305 /// Index into `string_bytes`.
......@@ -315,14 +308,14 @@ pub const UavFixup = extern struct {
315308};
316309
317310pub const NavFixup = extern struct {
318 navs_exe_index: NavsExeIndex,
311 nav_index: InternPool.Nav.Index,
319312 /// Index into `string_bytes`.
320313 offset: u32,
321314 addend: u32,
322315};
323316
324317pub const FuncTableFixup = extern struct {
325 table_index: ZcuIndirectFunctionSetIndex,
318 nav_index: InternPool.Nav.Index,
326319 /// Index into `string_bytes`.
327320 offset: u32,
328321};
......@@ -355,7 +348,9 @@ pub const FunctionIndex = enum(u32) {
355348
356349 pub fn fromSymbolName(wasm: *const Wasm, name: String) ?FunctionIndex {
357350 if (wasm.object_function_imports.getPtr(name)) |import| {
358 return fromResolution(wasm, import.resolution);
351 if (import.resolution != .unresolved) {
352 return fromResolution(wasm, import.resolution);
353 }
359354 }
360355 if (wasm.function_exports.get(name)) |index| return index;
361356 if (wasm.hidden_function_exports.get(name)) |index| return index;
......@@ -374,7 +369,8 @@ pub const GlobalExport = extern struct {
374369};
375370
376371/// 0. Index into `Flush.function_imports`
377/// 1. Index into `functions`.
372/// 1. Index into `Flush.intrinsic_function_imports`
373/// 2. Index into `functions`.
378374///
379375/// Note that function_imports indexes are subject to swap removals during
380376/// `flush`.
......@@ -386,7 +382,11 @@ pub const OutputFunctionIndex = enum(u32) {
386382 }
387383
388384 pub fn fromFunctionIndex(wasm: *const Wasm, index: FunctionIndex) OutputFunctionIndex {
389 return @fromBackingInt(@intCast(wasm.flush_buffer.function_imports.entries.len + @backingInt(index)));
385 return @fromBackingInt(@intCast(
386 wasm.flush_buffer.function_imports.entries.len +
387 wasm.flush_buffer.intrinsic_function_imports.entries.len +
388 @backingInt(index),
389 ));
390390 }
391391
392392 pub fn fromObjectFunction(wasm: *const Wasm, index: ObjectFunctionIndex) OutputFunctionIndex {
......@@ -429,6 +429,9 @@ pub const OutputFunctionIndex = enum(u32) {
429429
430430 pub fn fromSymbolName(wasm: *const Wasm, name: String) OutputFunctionIndex {
431431 if (wasm.flush_buffer.function_imports.getIndex(name)) |i| return @fromBackingInt(@intCast(i));
432 if (wasm.flush_buffer.intrinsic_function_imports.getIndex(name)) |i| return @fromBackingInt(@intCast(
433 wasm.flush_buffer.function_imports.entries.len + i,
434 ));
432435 return fromFunctionIndex(wasm, FunctionIndex.fromSymbolName(wasm, name) orelse {
433436 if (std.debug.runtime_safety) {
434437 std.debug.panic("function index for symbol not found: {s}", .{name.slice(wasm)});
......@@ -437,6 +440,56 @@ pub const OutputFunctionIndex = enum(u32) {
437440 }
438441};
439442
443// Order
444// 0. Flush.data_imports
445// 1. Wasm.datas
446pub const OutputDataIndex = enum(u32) {
447 _,
448
449 pub fn fromSymbolName(wasm: *const Wasm, name: String) OutputDataIndex {
450 if (wasm.flush_buffer.data_imports.getIndex(name)) |i| return @fromBackingInt(@intCast(i));
451 if (wasm.object_data_imports.getPtr(name)) |import| {
452 if (import.resolution != .unresolved) return fromResolution(wasm, import.resolution).?;
453 }
454 if (wasm.flush_buffer.data_exports.get(name)) |symbol| return fromResolution(wasm, symbol.resolution).?;
455 if (std.debug.runtime_safety) {
456 std.debug.panic("data index for symbol not found: {s}", .{name.slice(wasm)});
457 } else unreachable;
458 }
459
460 pub fn fromObjectData(wasm: *const Wasm, index: ObjectData.Index) OutputDataIndex {
461 return fromResolution(wasm, .fromObjectDataIndex(wasm, index)).?;
462 }
463
464 pub fn fromResolution(wasm: *const Wasm, resolution: ObjectDataImport.Resolution) ?OutputDataIndex {
465 const i = wasm.datas.getIndex(resolution) orelse return null;
466 return @fromBackingInt(@intCast(wasm.flush_buffer.data_imports.entries.len + i));
467 }
468
469 pub fn fromUav(wasm: *const Wasm, ip_index: InternPool.Index) OutputDataIndex {
470 const comp = wasm.base.comp;
471 const resolution: ObjectDataImport.Resolution = if (comp.config.output_mode == .Obj)
472 .pack(wasm, .{ .uav_obj = @fromBackingInt(@intCast(wasm.uavs_obj.getIndex(ip_index).?)) })
473 else
474 .pack(wasm, .{ .uav_exe = @fromBackingInt(@intCast(wasm.uavs_exe.getIndex(ip_index).?)) });
475 return fromResolution(wasm, resolution).?;
476 }
477
478 pub fn fromNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) OutputDataIndex {
479 const zcu = wasm.base.comp.zcu.?;
480 const ip = &zcu.intern_pool;
481 const nav = ip.getNav(nav_index);
482 if (nav.getExtern(ip)) |ext| {
483 return fromSymbolName(wasm, wasm.getExistingString(ext.name.toSlice(ip)).?);
484 }
485 const resolution: ObjectDataImport.Resolution = if (wasm.base.comp.config.output_mode == .Obj)
486 .pack(wasm, .{ .nav_obj = @fromBackingInt(@intCast(wasm.navs_obj.getIndex(nav_index).?)) })
487 else
488 .pack(wasm, .{ .nav_exe = @fromBackingInt(@intCast(wasm.navs_exe.getIndex(nav_index).?)) });
489 return fromResolution(wasm, resolution).?;
490 }
491};
492
440493/// Index into `Wasm.globals`.
441494pub const GlobalIndex = enum(u32) {
442495 _,
......@@ -452,17 +505,17 @@ pub const GlobalIndex = enum(u32) {
452505 return .stack_pointer;
453506 }
454507
455 pub fn ptr(index: GlobalIndex, f: *const Flush) *Wasm.GlobalImport.Resolution {
456 return &f.globals.items[@backingInt(index)];
508 pub fn fromResolution(wasm: *const Wasm, resolution: GlobalImport.Resolution) ?GlobalIndex {
509 const i = wasm.globals.getIndex(resolution) orelse return null;
510 return @fromBackingInt(@intCast(wasm.flush_buffer.global_imports.entries.len + i));
457511 }
458512
459513 pub fn fromIpNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) ?GlobalIndex {
460 const i = wasm.globals.getIndex(.fromIpNav(wasm, nav_index)) orelse return null;
461 return @fromBackingInt(@intCast(i));
514 return fromResolution(wasm, .fromIpNav(wasm, nav_index));
462515 }
463516
464517 pub fn fromObjectGlobal(wasm: *const Wasm, i: ObjectGlobalIndex) GlobalIndex {
465 return @fromBackingInt(@intCast(wasm.globals.getIndex(.fromObjectGlobal(wasm, i)).?));
518 return fromResolution(wasm, .fromObjectGlobal(wasm, i)).?;
466519 }
467520
468521 pub fn fromObjectGlobalHandlingWeak(wasm: *const Wasm, index: ObjectGlobalIndex) GlobalIndex {
......@@ -474,8 +527,9 @@ pub const GlobalIndex = enum(u32) {
474527 }
475528
476529 pub fn fromSymbolName(wasm: *const Wasm, name: String) GlobalIndex {
530 if (wasm.flush_buffer.global_imports.getIndex(name)) |i| return @fromBackingInt(@intCast(i));
477531 const import = wasm.object_global_imports.getPtr(name).?;
478 return @fromBackingInt(@intCast(wasm.globals.getIndex(import.resolution).?));
532 return fromResolution(wasm, import.resolution).?;
479533 }
480534};
481535
......@@ -483,10 +537,6 @@ pub const GlobalIndex = enum(u32) {
483537pub const TableIndex = enum(u32) {
484538 _,
485539
486 pub fn ptr(index: TableIndex, f: *const Flush) *Wasm.TableImport.Resolution {
487 return &f.tables.items[@backingInt(index)];
488 }
489
490540 pub fn fromObjectTable(wasm: *const Wasm, i: ObjectTableIndex) TableIndex {
491541 return @fromBackingInt(@intCast(wasm.tables.getIndex(.fromObjectTable(i)).?));
492542 }
......@@ -668,9 +718,10 @@ pub const SymbolFlags = packed struct(u32) {
668718 flags.ref_type = .funcref;
669719 }
670720
671 pub fn isIncluded(flags: SymbolFlags, is_dynamic: bool) bool {
721 pub fn isIncluded(flags: SymbolFlags, is_dynamic: bool, is_obj: bool) bool {
672722 return flags.exported or
673723 (is_dynamic and !flags.visibility_hidden) or
724 (is_obj and flags.binding != .local) or
674725 (flags.no_strip and flags.must_link);
675726 }
676727
......@@ -696,8 +747,8 @@ pub const SymbolFlags = packed struct(u32) {
696747 /// Masks off the Zig-specific stuff.
697748 pub fn toAbiInteger(flags: SymbolFlags) u32 {
698749 var copy = flags;
699 copy.initZigSpecific(false, false);
700 return @bitCast(copy);
750 copy.initZigSpecific(false, flags.no_strip);
751 return @backingInt(copy);
701752 }
702753};
703754
......@@ -812,7 +863,7 @@ pub const UavsExeIndex = enum(u32) {
812863/// Used when emitting a relocatable object.
813864pub const ZcuDataObj = extern struct {
814865 code: DataPayload,
815 relocs: OutReloc.Slice,
866 relocs: ZcuRelocation.Slice,
816867};
817868
818869/// Used when not emitting a relocatable object.
......@@ -855,7 +906,9 @@ const ZcuDataStarts = struct {
855906 var uavs_i = zds.uavs_i;
856907 while (uavs_i < wasm.uavs_obj.entries.len) : (uavs_i += 1) {
857908 // Call to `lowerZcuData` here possibly creates more entries in these tables.
858 wasm.uavs_obj.values()[uavs_i] = try lowerZcuData(wasm, pt, wasm.uavs_obj.keys()[uavs_i]);
909 const uav = wasm.uavs_obj.keys()[uavs_i];
910 const zcu_data = try lowerZcuData(wasm, pt, uav);
911 wasm.uavs_obj.values()[uavs_i] = zcu_data;
859912 }
860913 }
861914
......@@ -906,6 +959,51 @@ pub const ZcuFunc = union {
906959 return &wasm.zcu_funcs.values()[@backingInt(i)];
907960 }
908961
962 pub fn flags(i: @This(), wasm: *const Wasm) SymbolFlags {
963 const zcu = wasm.base.comp.zcu.?;
964 const ip = &zcu.intern_pool;
965 const ip_index = i.key(wasm).*;
966 switch (ip.indexToKey(ip_index)) {
967 .func => |func| {
968 const nav = ip.getNav(func.owner_nav);
969 if (nav.getExtern(ip)) |ext| {
970 const name_slice = ext.name.toSlice(ip);
971 const name_string = wasm.getExistingString(name_slice).?;
972 return .{
973 .binding = switch (ext.linkage) {
974 .internal => .local,
975 .strong => .strong,
976 .weak => .weak,
977 .link_once => @panic("TODO: COMDAT"),
978 },
979 .visibility_hidden = switch (ext.visibility) {
980 .default => false,
981 .hidden => true,
982 .protected => false,
983 },
984 .undefined = false,
985 .exported = wasm.missing_exports.contains(name_string),
986 .explicit_name = false,
987 .no_strip = false,
988 .tls = ext.is_threadlocal,
989 .absolute = false,
990 };
991 } else {
992 return .{
993 .binding = .local,
994 .tls = nav.resolved.?.@"threadlocal",
995 };
996 }
997 },
998 .enum_type => {
999 return .{
1000 .binding = .local,
1001 };
1002 },
1003 else => unreachable,
1004 }
1005 }
1006
9091007 pub fn name(i: @This(), wasm: *const Wasm) [:0]const u8 {
9101008 const zcu = wasm.base.comp.zcu.?;
9111009 const ip = &zcu.intern_pool;
......@@ -1034,6 +1132,15 @@ pub const FunctionImport = extern struct {
10341132 return pack(wasm, .{ .object_function = object_function });
10351133 }
10361134
1135 pub fn flags(r: Resolution, wasm: *Wasm) SymbolFlags {
1136 return switch (unpack(r, wasm)) {
1137 .unresolved => unreachable,
1138 .__wasm_apply_global_tls_relocs, .__wasm_call_ctors, .__wasm_init_memory, .__wasm_init_tls => unreachable,
1139 .object_function => |i| i.ptr(wasm).flags,
1140 .zcu_func => |i| i.flags(wasm),
1141 };
1142 }
1143
10371144 pub fn isNavOrUnresolved(r: Resolution, wasm: *const Wasm) bool {
10381145 return switch (r.unpack(wasm)) {
10391146 .unresolved, .zcu_func => true,
......@@ -1136,6 +1243,7 @@ pub const GlobalImport = extern struct {
11361243 __tls_base,
11371244 __tls_size,
11381245 // Next, index into `object_globals`.
1246 // Next, index into `uavs_obj` or `uavs_exe` depending on whether emitting an object.
11391247 // Next, index into `navs_obj` or `navs_exe` depending on whether emitting an object.
11401248 _,
11411249
......@@ -1150,6 +1258,8 @@ pub const GlobalImport = extern struct {
11501258 __tls_base,
11511259 __tls_size,
11521260 object_global: ObjectGlobalIndex,
1261 uav_exe: UavsExeIndex,
1262 uav_obj: UavsObjIndex,
11531263 nav_exe: NavsExeIndex,
11541264 nav_obj: NavsObjIndex,
11551265 };
......@@ -1170,12 +1280,22 @@ pub const GlobalImport = extern struct {
11701280 return .{ .object_global = @fromBackingInt(@intCast(object_global_index)) };
11711281 const comp = wasm.base.comp;
11721282 const is_obj = comp.config.output_mode == .Obj;
1173 const nav_index = object_global_index - wasm.object_globals.items.len;
1174 return if (is_obj) .{
1175 .nav_obj = @fromBackingInt(@intCast(nav_index)),
1176 } else .{
1177 .nav_exe = @fromBackingInt(@intCast(nav_index)),
1178 };
1283 const uav_index = object_global_index - wasm.object_globals.items.len;
1284 if (is_obj) {
1285 if (uav_index < wasm.uavs_obj.entries.len) {
1286 return .{ .uav_obj = @fromBackingInt(@intCast(uav_index)) };
1287 }
1288 return .{ .nav_obj = @fromBackingInt(
1289 @intCast(uav_index - wasm.uavs_obj.entries.len),
1290 ) };
1291 } else {
1292 if (uav_index < wasm.uavs_exe.entries.len) {
1293 return .{ .uav_exe = @fromBackingInt(@intCast(uav_index)) };
1294 }
1295 return .{ .nav_exe = @fromBackingInt(
1296 @intCast(uav_index - wasm.uavs_exe.entries.len),
1297 ) };
1298 }
11791299 },
11801300 };
11811301 }
......@@ -1190,11 +1310,29 @@ pub const GlobalImport = extern struct {
11901310 .__tls_base => .__tls_base,
11911311 .__tls_size => .__tls_size,
11921312 .object_global => |i| @fromBackingInt(@intCast(first_object_global + @backingInt(i))),
1193 .nav_obj => |i| @fromBackingInt(@intCast(first_object_global + wasm.object_globals.items.len + @backingInt(i))),
1194 .nav_exe => |i| @fromBackingInt(@intCast(first_object_global + wasm.object_globals.items.len + @backingInt(i))),
1313 inline .uav_obj, .uav_exe => |i| @fromBackingInt(@intCast(
1314 first_object_global + wasm.object_globals.items.len + @backingInt(i),
1315 )),
1316 .nav_obj => |i| @fromBackingInt(@intCast(
1317 first_object_global + wasm.object_globals.items.len +
1318 wasm.uavs_obj.entries.len + @backingInt(i),
1319 )),
1320 .nav_exe => |i| @fromBackingInt(@intCast(
1321 first_object_global + wasm.object_globals.items.len +
1322 wasm.uavs_exe.entries.len + @backingInt(i),
1323 )),
11951324 };
11961325 }
11971326
1327 pub fn fromIpIndex(wasm: *const Wasm, ip_index: InternPool.Index) Resolution {
1328 const is_obj = wasm.base.comp.config.output_mode == .Obj;
1329 return pack(wasm, if (is_obj) .{
1330 .uav_obj = @fromBackingInt(@intCast(wasm.uavs_obj.getIndex(ip_index).?)),
1331 } else .{
1332 .uav_exe = @fromBackingInt(@intCast(wasm.uavs_exe.getIndex(ip_index).?)),
1333 });
1334 }
1335
11981336 pub fn fromIpNav(wasm: *const Wasm, ip_nav: InternPool.Nav.Index) Resolution {
11991337 const comp = wasm.base.comp;
12001338 const is_obj = comp.config.output_mode == .Obj;
......@@ -1209,7 +1347,22 @@ pub const GlobalImport = extern struct {
12091347 return pack(wasm, .{ .object_global = object_global });
12101348 }
12111349
1212 pub fn name(r: Resolution, wasm: *const Wasm) ?[]const u8 {
1350 pub fn flags(r: Resolution, wasm: *const Wasm) SymbolFlags {
1351 return switch (unpack(r, wasm)) {
1352 .unresolved,
1353 .__heap_base,
1354 .__heap_end,
1355 .__stack_pointer,
1356 .__tls_align,
1357 .__tls_base,
1358 .__tls_size,
1359 => unreachable,
1360 .object_global => |i| i.ptr(wasm).flags,
1361 .uav_obj, .uav_exe, .nav_obj, .nav_exe => unreachable,
1362 };
1363 }
1364
1365 pub fn name(r: Resolution, wasm: *const Wasm, buf: []u8) ?[]const u8 {
12131366 return switch (unpack(r, wasm)) {
12141367 .unresolved => unreachable,
12151368 .__heap_base => @tagName(Unpacked.__heap_base),
......@@ -1219,6 +1372,11 @@ pub const GlobalImport = extern struct {
12191372 .__tls_base => @tagName(Unpacked.__tls_base),
12201373 .__tls_size => @tagName(Unpacked.__tls_size),
12211374 .object_global => |i| i.name(wasm).slice(wasm),
1375 inline .uav_obj, .uav_exe => |i| std.fmt.bufPrint(
1376 buf,
1377 "__anon_{d}",
1378 .{@backingInt(i.key(wasm).*)},
1379 ) catch unreachable,
12221380 .nav_obj => |i| i.name(wasm),
12231381 .nav_exe => |i| i.name(wasm),
12241382 };
......@@ -1349,6 +1507,22 @@ pub const TableImport = extern struct {
13491507 return pack(.{ .object_table = object_table });
13501508 }
13511509
1510 pub fn name(r: Resolution, wasm: *const Wasm) ?[]const u8 {
1511 return switch (unpack(r)) {
1512 .unresolved => unreachable,
1513 .__indirect_function_table => @tagName(Unpacked.__indirect_function_table),
1514 .object_table => |i| i.ptr(wasm).name.slice(wasm),
1515 };
1516 }
1517
1518 pub fn flags(r: Resolution, wasm: *const Wasm) SymbolFlags {
1519 return switch (unpack(r)) {
1520 .unresolved => unreachable,
1521 .__indirect_function_table => unreachable,
1522 .object_table => |i| i.ptr(wasm).flags,
1523 };
1524 }
1525
13521526 pub fn refType(r: Resolution, wasm: *const Wasm) std.wasm.RefType {
13531527 return switch (unpack(r)) {
13541528 .unresolved => unreachable,
......@@ -1602,6 +1776,8 @@ pub const ObjectDataImport = extern struct {
16021776 unresolved,
16031777 __zig_error_names,
16041778 __zig_error_name_table,
1779 __zig_tag_names,
1780 __zig_tag_name_table,
16051781 __heap_base,
16061782 __heap_end,
16071783 /// Next, an `ObjectData.Index`.
......@@ -1615,6 +1791,8 @@ pub const ObjectDataImport = extern struct {
16151791 unresolved,
16161792 __zig_error_names,
16171793 __zig_error_name_table,
1794 __zig_tag_names,
1795 __zig_tag_name_table,
16181796 __heap_base,
16191797 __heap_end,
16201798 object: ObjectData.Index,
......@@ -1629,6 +1807,8 @@ pub const ObjectDataImport = extern struct {
16291807 .unresolved => .unresolved,
16301808 .__zig_error_names => .__zig_error_names,
16311809 .__zig_error_name_table => .__zig_error_name_table,
1810 .__zig_tag_names => .__zig_tag_names,
1811 .__zig_tag_name_table => .__zig_tag_name_table,
16321812 .__heap_base => .__heap_base,
16331813 .__heap_end => .__heap_end,
16341814 _ => {
......@@ -1665,6 +1845,8 @@ pub const ObjectDataImport = extern struct {
16651845 .unresolved => .unresolved,
16661846 .__zig_error_names => .__zig_error_names,
16671847 .__zig_error_name_table => .__zig_error_name_table,
1848 .__zig_tag_names => .__zig_tag_names,
1849 .__zig_tag_name_table => .__zig_tag_name_table,
16681850 .__heap_base => .__heap_base,
16691851 .__heap_end => .__heap_end,
16701852 .object => |i| @fromBackingInt(@intCast(first_object + @backingInt(i))),
......@@ -1678,12 +1860,32 @@ pub const ObjectDataImport = extern struct {
16781860 return pack(wasm, .{ .object = object_data_index });
16791861 }
16801862
1863 pub fn fromIpIndex(wasm: *const Wasm, ip_index: InternPool.Index) Resolution {
1864 const is_obj = wasm.base.comp.config.output_mode == .Obj;
1865 return pack(wasm, if (is_obj) .{
1866 .uav_obj = @fromBackingInt(@intCast(wasm.uavs_obj.getIndex(ip_index).?)),
1867 } else .{
1868 .uav_exe = @fromBackingInt(@intCast(wasm.uavs_exe.getIndex(ip_index).?)),
1869 });
1870 }
1871
1872 pub fn fromIpNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) Resolution {
1873 const is_obj = wasm.base.comp.config.output_mode == .Obj;
1874 return pack(wasm, if (is_obj) .{
1875 .nav_obj = @fromBackingInt(@intCast(wasm.navs_obj.getIndex(nav_index).?)),
1876 } else .{
1877 .nav_exe = @fromBackingInt(@intCast(wasm.navs_exe.getIndex(nav_index).?)),
1878 });
1879 }
1880
16811881 pub fn objectDataSegment(r: Resolution, wasm: *const Wasm) ?ObjectDataSegment.Index {
16821882 return switch (unpack(r, wasm)) {
16831883 .unresolved => unreachable,
16841884 .object => |i| i.ptr(wasm).segment,
16851885 .__zig_error_names,
16861886 .__zig_error_name_table,
1887 .__zig_tag_names,
1888 .__zig_tag_name_table,
16871889 .__heap_base,
16881890 .__heap_end,
16891891 .uav_exe,
......@@ -1706,12 +1908,107 @@ pub const ObjectDataImport = extern struct {
17061908 },
17071909 .__zig_error_names => .{ .segment = .__zig_error_names, .offset = 0 },
17081910 .__zig_error_name_table => .{ .segment = .__zig_error_name_table, .offset = 0 },
1911 .__zig_tag_names => .{ .segment = .__zig_tag_names, .offset = 0 },
1912 .__zig_tag_name_table => .{ .segment = .__zig_tag_name_table, .offset = 0 },
17091913 .__heap_base => .{ .segment = .__heap_base, .offset = 0 },
17101914 .__heap_end => .{ .segment = .__heap_end, .offset = 0 },
1711 .uav_exe => @panic("TODO"),
1712 .uav_obj => @panic("TODO"),
1713 .nav_exe => @panic("TODO"),
1714 .nav_obj => @panic("TODO"),
1915 .uav_exe => |i| .{ .segment = .pack(wasm, .{ .uav_exe = i }), .offset = 0 },
1916 .uav_obj => |i| .{ .segment = .pack(wasm, .{ .uav_obj = i }), .offset = 0 },
1917 .nav_exe => |i| .{ .segment = .pack(wasm, .{ .nav_exe = i }), .offset = 0 },
1918 .nav_obj => |i| .{ .segment = .pack(wasm, .{ .nav_obj = i }), .offset = 0 },
1919 };
1920 }
1921
1922 pub fn flags(r: Resolution, wasm: *const Wasm) SymbolFlags {
1923 return switch (unpack(r, wasm)) {
1924 .unresolved => unreachable,
1925 .__zig_error_names,
1926 .__zig_error_name_table,
1927 .__zig_tag_names,
1928 .__zig_tag_name_table,
1929 => .{ .binding = .local },
1930 .__heap_base,
1931 .__heap_end,
1932 => unreachable,
1933 .object => |i| i.ptr(wasm).flags,
1934 inline .nav_exe, .nav_obj => |i| {
1935 const zcu = wasm.base.comp.zcu.?;
1936 const ip = &zcu.intern_pool;
1937 const nav = ip.getNav(i.key(wasm).*);
1938 if (nav.getExtern(ip)) |ext| {
1939 const name_slice = ext.name.toSlice(ip);
1940 const name_string = wasm.getExistingString(name_slice).?;
1941 return .{
1942 .binding = switch (ext.linkage) {
1943 .internal => .local,
1944 .strong => .strong,
1945 .weak => .weak,
1946 .link_once => @panic("TODO: COMDAT"),
1947 },
1948 .visibility_hidden = switch (ext.visibility) {
1949 .default => false,
1950 .hidden => true,
1951 .protected => false,
1952 },
1953 .undefined = false,
1954 .exported = wasm.missing_exports.contains(name_string),
1955 .explicit_name = false,
1956 .no_strip = false,
1957 .tls = ext.is_threadlocal,
1958 .absolute = false,
1959 };
1960 } else {
1961 return .{
1962 .binding = .local,
1963 .tls = nav.resolved.?.@"threadlocal",
1964 };
1965 }
1966 },
1967 .uav_exe, .uav_obj => .{ .binding = .local },
1968 };
1969 }
1970
1971 pub fn name(r: Resolution, wasm: *const Wasm, buf: []u8) []const u8 {
1972 return switch (unpack(r, wasm)) {
1973 .unresolved => unreachable,
1974 .object => |i| i.ptr(wasm).name.slice(wasm),
1975 .__zig_error_names => @tagName(.__zig_error_names),
1976 .__zig_error_name_table => @tagName(.__zig_error_name_table),
1977 .__zig_tag_names => @tagName(.__zig_tag_names),
1978 .__zig_tag_name_table => @tagName(.__zig_tag_name_table),
1979 .__heap_base => @tagName(.__heap_base),
1980 .__heap_end => @tagName(.__heap_end),
1981 inline .uav_exe, .uav_obj => |i| std.fmt.bufPrint(
1982 buf,
1983 "__anon_{d}",
1984 .{@backingInt(i.key(wasm).*)},
1985 ) catch unreachable,
1986 inline .nav_exe, .nav_obj => |i| i.name(wasm),
1987 };
1988 }
1989
1990 pub fn size(r: Resolution, wasm: *const Wasm) u32 {
1991 return switch (unpack(r, wasm)) {
1992 .unresolved => unreachable,
1993 .__zig_error_names => @intCast(wasm.error_name_bytes.items.len),
1994 .__zig_error_name_table => {
1995 const comp = wasm.base.comp;
1996 const zcu = comp.zcu.?;
1997 const errors_len = wasm.error_name_offs.items.len;
1998 const elem_size = Zcu.Type.slice_const_u8_sentinel_0.abiSize(zcu);
1999 return @intCast(errors_len * elem_size);
2000 },
2001 .__zig_tag_names => @intCast(wasm.tag_name_bytes.items.len),
2002 .__zig_tag_name_table => {
2003 const comp = wasm.base.comp;
2004 const zcu = comp.zcu.?;
2005 const table_len = wasm.tag_name_offs.items.len;
2006 const elem_size = Zcu.Type.slice_const_u8_sentinel_0.abiSize(zcu);
2007 return @intCast(table_len * elem_size);
2008 },
2009 .__heap_base, .__heap_end => wasm.pointerSize(),
2010 .object => |i| i.ptr(wasm).size,
2011 inline .uav_exe, .uav_obj, .nav_exe, .nav_obj => |i| i.value(wasm).code.len,
17152012 };
17162013 }
17172014 };
......@@ -1910,6 +2207,38 @@ pub const DataSegmentId = enum(u32) {
19102207 };
19112208 }
19122209
2210 pub fn isStrings(id: DataSegmentId, wasm: *const Wasm) bool {
2211 return switch (unpack(id, wasm)) {
2212 .__zig_error_names, .__zig_tag_names => true,
2213
2214 .__zig_error_name_table,
2215 .__zig_tag_name_table,
2216 .__heap_base,
2217 .__heap_end,
2218 => false,
2219
2220 .object => |i| i.ptr(wasm).flags.strings,
2221 .uav_exe, .uav_obj => false,
2222 .nav_exe, .nav_obj => false,
2223 };
2224 }
2225
2226 pub fn isRetain(id: DataSegmentId, wasm: *const Wasm) bool {
2227 return switch (unpack(id, wasm)) {
2228 .__zig_error_names,
2229 .__zig_error_name_table,
2230 .__zig_tag_names,
2231 .__zig_tag_name_table,
2232 .__heap_base,
2233 .__heap_end,
2234 => false,
2235
2236 .object => |i| i.ptr(wasm).flags.retain,
2237 .uav_exe, .uav_obj => false,
2238 .nav_exe, .nav_obj => false,
2239 };
2240 }
2241
19132242 pub fn isBss(id: DataSegmentId, wasm: *const Wasm) bool {
19142243 return id.category(wasm) == .zero;
19152244 }
......@@ -2181,6 +2510,7 @@ const PreloadedStrings = struct {
21812510 _initialize: String,
21822511 _start: String,
21832512 memory: String,
2513 env: String,
21842514};
21852515
21862516/// Index into string_bytes
......@@ -2262,6 +2592,34 @@ pub const ZcuImportIndex = enum(u32) {
22622592 return &wasm.imports.keys()[@backingInt(index)];
22632593 }
22642594
2595 pub fn flags(index: ZcuImportIndex, wasm: *const Wasm) SymbolFlags {
2596 const zcu = wasm.base.comp.zcu.?;
2597 const ip = &zcu.intern_pool;
2598 const nav_index = index.ptr(wasm).*;
2599 const ext = ip.indexToKey(ip.getNav(nav_index).resolved.?.value).@"extern";
2600 const name_slice = ext.name.toSlice(ip);
2601 const name_string = wasm.getExistingString(name_slice).?;
2602 return .{
2603 .binding = switch (ext.linkage) {
2604 .internal => .local,
2605 .strong => .strong,
2606 .weak => .weak,
2607 .link_once => @panic("TODO: COMDAT"),
2608 },
2609 .visibility_hidden = switch (ext.visibility) {
2610 .default => false,
2611 .hidden => true,
2612 .protected => false,
2613 },
2614 .undefined = true,
2615 .exported = wasm.missing_exports.contains(name_string),
2616 .explicit_name = false,
2617 .no_strip = false,
2618 .tls = ext.is_threadlocal,
2619 .absolute = false,
2620 };
2621 }
2622
22652623 pub fn importName(index: ZcuImportIndex, wasm: *const Wasm) String {
22662624 const zcu = wasm.base.comp.zcu.?;
22672625 const ip = &zcu.intern_pool;
......@@ -2348,6 +2706,13 @@ pub const FunctionImportId = enum(u32) {
23482706 }
23492707 }
23502708
2709 pub fn flags(id: FunctionImportId, wasm: *const Wasm) SymbolFlags {
2710 return switch (id.unpack(wasm)) {
2711 .object_function_import => |i| i.value(wasm).flags,
2712 .zcu_import => |i| i.flags(wasm),
2713 };
2714 }
2715
23512716 pub fn importName(id: FunctionImportId, wasm: *const Wasm) String {
23522717 return switch (unpack(id, wasm)) {
23532718 inline .object_function_import, .zcu_import => |i| i.importName(wasm),
......@@ -2385,38 +2750,61 @@ pub const FunctionImportId = enum(u32) {
23852750 }
23862751};
23872752
2388/// 0. Index into `object_global_imports`.
2389/// 1. Index into `imports`.
2753/// 0. `__stack_pointer`.
2754/// 1. Index into `object_global_imports`.
2755/// 2. Index into `imports`.
23902756pub const GlobalImportId = enum(u32) {
2757 __stack_pointer,
23912758 _,
23922759
23932760 pub const Unpacked = union(enum) {
2761 __stack_pointer,
23942762 object_global_import: GlobalImport.Index,
23952763 zcu_import: ZcuImportIndex,
23962764 };
23972765
23982766 pub fn pack(unpacked: Unpacked, wasm: *const Wasm) GlobalImportId {
23992767 return switch (unpacked) {
2400 .object_global_import => |i| @fromBackingInt(@intCast(@backingInt(i))),
2401 .zcu_import => |i| @fromBackingInt(@intCast(@backingInt(i) + wasm.object_global_imports.entries.len)),
2768 .__stack_pointer => .__stack_pointer,
2769 .object_global_import => |i| @fromBackingInt(@intCast(@backingInt(i) + 1)),
2770 .zcu_import => |i| @fromBackingInt(@intCast(@backingInt(i) + wasm.object_global_imports.entries.len + 1)),
24022771 };
24032772 }
24042773
24052774 pub fn unpack(id: GlobalImportId, wasm: *const Wasm) Unpacked {
2406 const i = @backingInt(id);
2407 if (i < wasm.object_global_imports.entries.len) return .{ .object_global_import = @fromBackingInt(@intCast(i)) };
2408 const zcu_import_i = i - wasm.object_global_imports.entries.len;
2409 return .{ .zcu_import = @fromBackingInt(@intCast(zcu_import_i)) };
2775 return switch (id) {
2776 .__stack_pointer => .__stack_pointer,
2777 _ => {
2778 const i = @backingInt(id) - 1;
2779 if (i < wasm.object_global_imports.entries.len) {
2780 return .{ .object_global_import = @fromBackingInt(@intCast(i)) };
2781 }
2782 const zcu_import_i = i - wasm.object_global_imports.entries.len;
2783 return .{ .zcu_import = @fromBackingInt(@intCast(zcu_import_i)) };
2784 },
2785 };
24102786 }
24112787
24122788 pub fn fromObject(object_global_import: GlobalImport.Index, wasm: *const Wasm) GlobalImportId {
24132789 return pack(.{ .object_global_import = object_global_import }, wasm);
24142790 }
24152791
2792 pub fn flags(id: GlobalImportId, wasm: *const Wasm) SymbolFlags {
2793 return switch (id.unpack(wasm)) {
2794 .__stack_pointer => .{
2795 .binding = .strong,
2796 .undefined = true,
2797 },
2798 .object_global_import => |i| i.value(wasm).flags,
2799 .zcu_import => |i| i.flags(wasm),
2800 };
2801 }
2802
24162803 /// This function is allowed O(N) lookup because it is only called during
24172804 /// diagnostic generation.
24182805 pub fn sourceLocation(id: GlobalImportId, wasm: *const Wasm) SourceLocation {
24192806 switch (id.unpack(wasm)) {
2807 .__stack_pointer => return .zig_object_nofile,
24202808 .object_global_import => |obj_global_index| {
24212809 // TODO binary search
24222810 for (wasm.objects.items, 0..) |o, i| {
......@@ -2433,18 +2821,28 @@ pub const GlobalImportId = enum(u32) {
24332821
24342822 pub fn importName(id: GlobalImportId, wasm: *const Wasm) String {
24352823 return switch (unpack(id, wasm)) {
2824 .__stack_pointer => wasm.preloaded_strings.__stack_pointer,
24362825 inline .object_global_import, .zcu_import => |i| i.importName(wasm),
24372826 };
24382827 }
24392828
24402829 pub fn moduleName(id: GlobalImportId, wasm: *const Wasm) OptionalString {
24412830 return switch (unpack(id, wasm)) {
2831 .__stack_pointer => wasm.preloaded_strings.env.toOptional(),
24422832 inline .object_global_import, .zcu_import => |i| i.moduleName(wasm),
24432833 };
24442834 }
24452835
24462836 pub fn globalType(id: GlobalImportId, wasm: *Wasm) ObjectGlobal.Type {
24472837 return switch (unpack(id, wasm)) {
2838 .__stack_pointer => .{
2839 .valtype = switch (wasm.pointerSize()) {
2840 4 => .i32,
2841 8 => .i64,
2842 else => unreachable,
2843 },
2844 .mutable = true,
2845 },
24482846 inline .object_global_import, .zcu_import => |i| i.globalType(wasm),
24492847 };
24502848 }
......@@ -2482,6 +2880,13 @@ pub const DataImportId = enum(u32) {
24822880 return pack(.{ .object_data_import = object_data_import }, wasm);
24832881 }
24842882
2883 pub fn flags(id: DataImportId, wasm: *const Wasm) SymbolFlags {
2884 return switch (id.unpack(wasm)) {
2885 .object_data_import => |i| i.value(wasm).flags,
2886 .zcu_import => |i| i.flags(wasm),
2887 };
2888 }
2889
24852890 pub fn sourceLocation(id: DataImportId, wasm: *const Wasm) SourceLocation {
24862891 switch (id.unpack(wasm)) {
24872892 .object_data_import => |obj_data_index| {
......@@ -2499,33 +2904,42 @@ pub const DataImportId = enum(u32) {
24992904 }
25002905};
25012906
2502/// Index into `Wasm.symbol_table`.
2503pub const SymbolTableIndex = enum(u32) {
2504 _,
2505
2506 pub fn key(i: @This(), wasm: *const Wasm) *String {
2507 return &wasm.symbol_table.keys()[@backingInt(i)];
2508 }
2509};
2510
2511pub const OutReloc = struct {
2907pub const ZcuRelocation = struct {
25122908 tag: Object.RelocationType,
25132909 offset: u32,
25142910 pointee: Pointee,
25152911 addend: i32,
25162912
2517 pub const Pointee = union {
2518 symbol_index: SymbolTableIndex,
2913 pub const Pointee = union(enum) {
2914 function_nav: InternPool.Nav.Index,
2915 function_name: String,
2916 tag_function: InternPool.Index,
2917 data_uav: InternPool.Index,
2918 data_nav: InternPool.Nav.Index,
2919 data_resolution: ObjectDataImport.Resolution,
2920 stack_pointer,
25192921 type_index: FunctionType.Index,
25202922 };
25212923
25222924 pub const Slice = extern struct {
2523 /// Index into `out_relocs`.
2925 /// Index into `zcu_relocations`.
25242926 off: u32,
25252927 len: u32,
25262928
2527 pub fn slice(s: Slice, wasm: *const Wasm) []OutReloc {
2528 return wasm.relocations.items[s.off..][0..s.len];
2929 pub fn tags(s: Slice, wasm: *const Wasm) []const Object.RelocationType {
2930 return wasm.zcu_relocations.items(.tag)[s.off..][0..s.len];
2931 }
2932
2933 pub fn offsets(s: Slice, wasm: *const Wasm) []const u32 {
2934 return wasm.zcu_relocations.items(.offset)[s.off..][0..s.len];
2935 }
2936
2937 pub fn pointees(s: Slice, wasm: *const Wasm) []const Pointee {
2938 return wasm.zcu_relocations.items(.pointee)[s.off..][0..s.len];
2939 }
2940
2941 pub fn addends(s: Slice, wasm: *const Wasm) []const i32 {
2942 return wasm.zcu_relocations.items(.addend)[s.off..][0..s.len];
25292943 }
25302944 };
25312945};
......@@ -3137,9 +3551,9 @@ pub fn deinit(wasm: *Wasm) void {
31373551 wasm.table_imports.deinit(gpa);
31383552 wasm.tables.deinit(gpa);
31393553 wasm.data_imports.deinit(gpa);
3554 wasm.datas.deinit(gpa);
31403555 wasm.data_segments.deinit(gpa);
3141 wasm.symbol_table.deinit(gpa);
3142 wasm.out_relocs.deinit(gpa);
3556 wasm.zcu_relocations.deinit(gpa);
31433557 wasm.uav_fixups.deinit(gpa);
31443558 wasm.nav_fixups.deinit(gpa);
31453559 wasm.func_table_fixups.deinit(gpa);
......@@ -3351,6 +3765,25 @@ pub fn updateExports(
33513765 const zcu = pt.zcu;
33523766 const gpa = zcu.gpa;
33533767 const ip = &zcu.intern_pool;
3768 const is_obj = wasm.base.comp.config.output_mode == .Obj;
3769 switch (exported) {
3770 .nav => {}, // handled in updateNav
3771 .uav => |uav_index| { // export may be the only reference
3772 const zds: ZcuDataStarts = .init(wasm);
3773 if (is_obj) {
3774 const gop = try wasm.uavs_obj.getOrPut(gpa, uav_index);
3775 if (!gop.found_existing) gop.value_ptr.* = undefined;
3776 } else {
3777 const gop = try wasm.uavs_exe.getOrPut(gpa, uav_index);
3778 if (!gop.found_existing) gop.value_ptr.* = .{
3779 .code = undefined,
3780 .count = 0,
3781 };
3782 gop.value_ptr.count += 1;
3783 }
3784 try zds.finish(wasm, pt);
3785 },
3786 }
33543787 for (export_indices) |export_idx| {
33553788 const exp = export_idx.ptr(zcu);
33563789 const name_slice = exp.opts.name.toSlice(ip);
......@@ -3443,7 +3876,11 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.Error!void {
34433876 // Zig always depends on a stack pointer global.
34443877 // If emitting an object, it's an import. Otherwise, the linker synthesizes it.
34453878 if (is_obj) {
3446 @panic("TODO");
3879 try wasm.global_imports.putNoClobber(
3880 gpa,
3881 wasm.preloaded_strings.__stack_pointer,
3882 .__stack_pointer,
3883 );
34473884 } else {
34483885 try wasm.globals.put(gpa, .__stack_pointer, {});
34493886 assert(wasm.globals.entries.len - 1 == @backingInt(GlobalIndex.stack_pointer));
......@@ -3453,7 +3890,7 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.Error!void {
34533890 // These loops do both recursive marking of alive symbols well as checking for undefined symbols.
34543891 // At the end, output functions and globals will be populated.
34553892 for (wasm.object_function_imports.keys(), wasm.object_function_imports.values(), 0..) |name, *import, i| {
3456 if (import.flags.isIncluded(rdynamic)) {
3893 if (import.flags.isIncluded(rdynamic, is_obj)) {
34573894 try markFunctionImport(wasm, name, import, @fromBackingInt(@intCast(i)));
34583895 }
34593896 }
......@@ -3467,7 +3904,7 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.Error!void {
34673904 wasm.functions_end_prelink = @intCast(wasm.functions.entries.len);
34683905
34693906 for (wasm.object_global_imports.keys(), wasm.object_global_imports.values(), 0..) |name, *import, i| {
3470 if (import.flags.isIncluded(rdynamic)) {
3907 if (import.flags.isIncluded(rdynamic, is_obj)) {
34713908 try markGlobalImport(wasm, name, import, @fromBackingInt(@intCast(i)));
34723909 }
34733910 }
......@@ -3475,13 +3912,13 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.Error!void {
34753912 wasm.global_exports_len = @intCast(wasm.global_exports.items.len);
34763913
34773914 for (wasm.object_table_imports.keys(), wasm.object_table_imports.values(), 0..) |name, *import, i| {
3478 if (import.flags.isIncluded(rdynamic)) {
3915 if (import.flags.isIncluded(rdynamic, is_obj)) {
34793916 try markTableImport(wasm, name, import, @fromBackingInt(@intCast(i)));
34803917 }
34813918 }
34823919
34833920 for (wasm.object_data_imports.keys(), wasm.object_data_imports.values(), 0..) |name, *import, i| {
3484 if (import.flags.isIncluded(rdynamic)) {
3921 if (import.flags.isIncluded(rdynamic, is_obj)) {
34853922 try markDataImport(wasm, name, import, @fromBackingInt(@intCast(i)));
34863923 }
34873924 }
......@@ -3512,18 +3949,23 @@ pub fn markFunctionImport(
35123949
35133950 const comp = wasm.base.comp;
35143951 const gpa = comp.gpa;
3952 const is_obj = comp.config.output_mode == .Obj;
35153953
35163954 try wasm.functions.ensureUnusedCapacity(gpa, 1);
35173955
35183956 if (import.resolution == .unresolved) {
3519 if (name == wasm.preloaded_strings.__wasm_init_memory) {
3520 try wasm.resolveFunctionSynthetic(import, .__wasm_init_memory, &.{}, &.{});
3521 } else if (name == wasm.preloaded_strings.__wasm_apply_global_tls_relocs) {
3522 try wasm.resolveFunctionSynthetic(import, .__wasm_apply_global_tls_relocs, &.{}, &.{});
3523 } else if (name == wasm.preloaded_strings.__wasm_call_ctors) {
3524 try wasm.resolveFunctionSynthetic(import, .__wasm_call_ctors, &.{}, &.{});
3525 } else if (name == wasm.preloaded_strings.__wasm_init_tls) {
3526 try wasm.resolveFunctionSynthetic(import, .__wasm_init_tls, &.{.i32}, &.{});
3957 if (!is_obj) {
3958 if (name == wasm.preloaded_strings.__wasm_init_memory) {
3959 try wasm.resolveFunctionSynthetic(import, .__wasm_init_memory, &.{}, &.{});
3960 } else if (name == wasm.preloaded_strings.__wasm_apply_global_tls_relocs) {
3961 try wasm.resolveFunctionSynthetic(import, .__wasm_apply_global_tls_relocs, &.{}, &.{});
3962 } else if (name == wasm.preloaded_strings.__wasm_call_ctors) {
3963 try wasm.resolveFunctionSynthetic(import, .__wasm_call_ctors, &.{}, &.{});
3964 } else if (name == wasm.preloaded_strings.__wasm_init_tls) {
3965 try wasm.resolveFunctionSynthetic(import, .__wasm_init_tls, &.{.i32}, &.{});
3966 } else {
3967 try wasm.function_imports.put(gpa, name, .fromObject(func_index, wasm));
3968 }
35273969 } else {
35283970 try wasm.function_imports.put(gpa, name, .fromObject(func_index, wasm));
35293971 }
......@@ -3576,28 +4018,33 @@ fn markGlobalImport(
35764018
35774019 const comp = wasm.base.comp;
35784020 const gpa = comp.gpa;
4021 const is_obj = comp.config.output_mode == .Obj;
35794022
35804023 try wasm.globals.ensureUnusedCapacity(gpa, 1);
35814024
35824025 if (import.resolution == .unresolved) {
3583 if (name == wasm.preloaded_strings.__heap_base) {
3584 import.resolution = .__heap_base;
3585 wasm.globals.putAssumeCapacity(.__heap_base, {});
3586 } else if (name == wasm.preloaded_strings.__heap_end) {
3587 import.resolution = .__heap_end;
3588 wasm.globals.putAssumeCapacity(.__heap_end, {});
3589 } else if (name == wasm.preloaded_strings.__stack_pointer) {
3590 import.resolution = .__stack_pointer;
3591 wasm.globals.putAssumeCapacity(.__stack_pointer, {});
3592 } else if (name == wasm.preloaded_strings.__tls_align) {
3593 import.resolution = .__tls_align;
3594 wasm.globals.putAssumeCapacity(.__tls_align, {});
3595 } else if (name == wasm.preloaded_strings.__tls_base) {
3596 import.resolution = .__tls_base;
3597 wasm.globals.putAssumeCapacity(.__tls_base, {});
3598 } else if (name == wasm.preloaded_strings.__tls_size) {
3599 import.resolution = .__tls_size;
3600 wasm.globals.putAssumeCapacity(.__tls_size, {});
4026 if (!is_obj) {
4027 if (name == wasm.preloaded_strings.__heap_base) {
4028 import.resolution = .__heap_base;
4029 wasm.globals.putAssumeCapacity(.__heap_base, {});
4030 } else if (name == wasm.preloaded_strings.__heap_end) {
4031 import.resolution = .__heap_end;
4032 wasm.globals.putAssumeCapacity(.__heap_end, {});
4033 } else if (name == wasm.preloaded_strings.__stack_pointer) {
4034 import.resolution = .__stack_pointer;
4035 wasm.globals.putAssumeCapacity(.__stack_pointer, {});
4036 } else if (name == wasm.preloaded_strings.__tls_align) {
4037 import.resolution = .__tls_align;
4038 wasm.globals.putAssumeCapacity(.__tls_align, {});
4039 } else if (name == wasm.preloaded_strings.__tls_base) {
4040 import.resolution = .__tls_base;
4041 wasm.globals.putAssumeCapacity(.__tls_base, {});
4042 } else if (name == wasm.preloaded_strings.__tls_size) {
4043 import.resolution = .__tls_size;
4044 wasm.globals.putAssumeCapacity(.__tls_size, {});
4045 } else {
4046 try wasm.global_imports.put(gpa, name, .fromObject(global_index, wasm));
4047 }
36014048 } else {
36024049 try wasm.global_imports.put(gpa, name, .fromObject(global_index, wasm));
36034050 }
......@@ -3625,7 +4072,7 @@ fn markGlobal(wasm: *Wasm, i: ObjectGlobalIndex, override_export: bool) link.Err
36254072 try wasm.markRelocations(global.relocations(wasm));
36264073}
36274074
3628fn markTableImport(
4075pub fn markTableImport(
36294076 wasm: *Wasm,
36304077 name: String,
36314078 import: *TableImport,
......@@ -3636,13 +4083,18 @@ fn markTableImport(
36364083
36374084 const comp = wasm.base.comp;
36384085 const gpa = comp.gpa;
4086 const is_obj = comp.config.output_mode == .Obj;
36394087
36404088 try wasm.tables.ensureUnusedCapacity(gpa, 1);
36414089
36424090 if (import.resolution == .unresolved) {
3643 if (name == wasm.preloaded_strings.__indirect_function_table) {
3644 import.resolution = .__indirect_function_table;
3645 wasm.tables.putAssumeCapacity(.__indirect_function_table, {});
4091 if (!is_obj) {
4092 if (name == wasm.preloaded_strings.__indirect_function_table) {
4093 import.resolution = .__indirect_function_table;
4094 wasm.tables.putAssumeCapacity(.__indirect_function_table, {});
4095 } else {
4096 try wasm.table_imports.put(gpa, name, table_index);
4097 }
36464098 } else {
36474099 try wasm.table_imports.put(gpa, name, table_index);
36484100 }
......@@ -3676,22 +4128,38 @@ pub fn markDataImport(
36764128
36774129 const comp = wasm.base.comp;
36784130 const gpa = comp.gpa;
4131 const is_obj = comp.config.output_mode == .Obj;
4132
4133 try wasm.data_segments.ensureUnusedCapacity(gpa, 1);
36794134
36804135 if (import.resolution == .unresolved) {
3681 if (name == wasm.preloaded_strings.__heap_base) {
3682 import.resolution = .__heap_base;
3683 wasm.data_segments.putAssumeCapacity(.__heap_base, {});
3684 } else if (name == wasm.preloaded_strings.__heap_end) {
3685 import.resolution = .__heap_end;
3686 wasm.data_segments.putAssumeCapacity(.__heap_end, {});
4136 if (!is_obj) {
4137 if (name == wasm.preloaded_strings.__heap_base) {
4138 import.resolution = .__heap_base;
4139 wasm.data_segments.putAssumeCapacity(.__heap_base, {});
4140 } else if (name == wasm.preloaded_strings.__heap_end) {
4141 import.resolution = .__heap_end;
4142 wasm.data_segments.putAssumeCapacity(.__heap_end, {});
4143 } else {
4144 try wasm.data_imports.put(gpa, name, .fromObject(data_index, wasm));
4145 }
36874146 } else {
36884147 try wasm.data_imports.put(gpa, name, .fromObject(data_index, wasm));
36894148 }
3690 } else if (import.resolution.objectDataSegment(wasm)) |segment_index| {
3691 try markDataSegment(wasm, segment_index);
4149 } else switch (import.resolution.unpack(wasm)) {
4150 .object => |object_data_index| try markData(wasm, object_data_index),
4151 else => {},
36924152 }
36934153}
36944154
4155fn markData(wasm: *Wasm, i: ObjectData.Index) link.Error!void {
4156 const gpa = wasm.base.comp.gpa;
4157 const gop = try wasm.datas.getOrPut(gpa, .fromObjectDataIndex(wasm, i));
4158 if (gop.found_existing) return;
4159
4160 try markDataSegment(wasm, i.ptr(wasm).segment);
4161}
4162
36954163fn markRelocations(wasm: *Wasm, relocs: ObjectRelocation.IterableSlice) link.Error!void {
36964164 const gpa = wasm.base.comp.gpa;
36974165 for (relocs.slice.tags(wasm), relocs.slice.pointees(wasm), relocs.slice.offsets(wasm)) |tag, pointee, offset| {
......@@ -3782,7 +4250,7 @@ fn markRelocations(wasm: *Wasm, relocs: ObjectRelocation.IterableSlice) link.Err
37824250 .memory_addr_tls_sleb,
37834251 .memory_addr_locrel_i32,
37844252 .memory_addr_tls_sleb64,
3785 => try markDataSegment(wasm, pointee.data.ptr(wasm).segment),
4253 => try markData(wasm, pointee.data),
37864254
37874255 .type_index_leb => continue,
37884256 }
......@@ -3829,7 +4297,13 @@ pub fn flush(
38294297 const hidden_function_exports_end_zcu: u32 = @intCast(wasm.hidden_function_exports.entries.len);
38304298 defer wasm.hidden_function_exports.shrinkRetainingCapacity(hidden_function_exports_end_zcu);
38314299
4300 const global_exports_end_zcu: u32 = @intCast(wasm.global_exports.items.len);
4301 defer wasm.global_exports.shrinkRetainingCapacity(global_exports_end_zcu);
4302
38324303 wasm.flush_buffer.clear();
4304 wasm.tag_name_bytes.clearRetainingCapacity();
4305 wasm.tag_name_offs.clearRetainingCapacity();
4306 wasm.tag_name_table_ref_count = 0;
38334307 try wasm.flush_buffer.missing_exports.reinit(gpa, wasm.missing_exports.keys(), &.{});
38344308 try wasm.flush_buffer.function_imports.reinit(gpa, wasm.function_imports.keys(), wasm.function_imports.values());
38354309 try wasm.flush_buffer.global_imports.reinit(gpa, wasm.global_imports.keys(), wasm.global_imports.values());
......@@ -3953,6 +4427,255 @@ pub fn getExistingFunctionType(
39534427 });
39544428}
39554429
4430fn internIntrinsicType(
4431 wasm: *Wasm,
4432 params: []const InternPool.Index,
4433 return_type: Zcu.Type,
4434) Allocator.Error!FunctionType.Index {
4435 const target = &wasm.base.comp.root_mod.resolved_target.result;
4436 return wasm.internFunctionType(.{ .wasm_mvp = .{} }, params, return_type, false, target);
4437}
4438
4439pub fn intrinsicFunctionType(wasm: *Wasm, intrinsic: Mir.Intrinsic) Allocator.Error!FunctionType.Index {
4440 return switch (intrinsic) {
4441 .__addhf3 => internIntrinsicType(wasm, &.{ .f16_type, .f16_type }, .f16),
4442 .__addtf3 => internIntrinsicType(wasm, &.{ .f128_type, .f128_type }, .f128),
4443 .__addxf3 => internIntrinsicType(wasm, &.{ .f80_type, .f80_type }, .f80),
4444 .__ashlti3 => internIntrinsicType(wasm, &.{ .i128_type, .i32_type }, .i128),
4445 .__ashrti3 => internIntrinsicType(wasm, &.{ .i128_type, .i32_type }, .i128),
4446 .__bitreversedi2 => internIntrinsicType(wasm, &.{.u64_type}, .u64),
4447 .__bitreversesi2 => internIntrinsicType(wasm, &.{.u32_type}, .u32),
4448 .__bswapdi2 => internIntrinsicType(wasm, &.{.u64_type}, .u64),
4449 .__bswapsi2 => internIntrinsicType(wasm, &.{.u32_type}, .u32),
4450 .__ceilh => internIntrinsicType(wasm, &.{.f16_type}, .f16),
4451 .__ceilx => internIntrinsicType(wasm, &.{.f80_type}, .f80),
4452 .__cosh => internIntrinsicType(wasm, &.{.f16_type}, .f16),
4453 .__cosx => internIntrinsicType(wasm, &.{.f80_type}, .f80),
4454 .__divei5 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .usize_type, .usize_type, .usize_type }, .void),
4455 .__divhf3 => internIntrinsicType(wasm, &.{ .f16_type, .f16_type }, .f16),
4456 .__divtf3 => internIntrinsicType(wasm, &.{ .f128_type, .f128_type }, .f128),
4457 .__divti3 => internIntrinsicType(wasm, &.{ .i128_type, .i128_type }, .i128),
4458 .__divxf3 => internIntrinsicType(wasm, &.{ .f80_type, .f80_type }, .f80),
4459 .__eqtf2 => internIntrinsicType(wasm, &.{ .f128_type, .f128_type }, .bool),
4460 .__eqxf2 => internIntrinsicType(wasm, &.{ .f80_type, .f80_type }, .bool),
4461 .__exp2h => internIntrinsicType(wasm, &.{.f16_type}, .f16),
4462 .__exp2x => internIntrinsicType(wasm, &.{.f80_type}, .f80),
4463 .__exph => internIntrinsicType(wasm, &.{.f16_type}, .f16),
4464 .__expx => internIntrinsicType(wasm, &.{.f80_type}, .f80),
4465 .__extenddftf2 => internIntrinsicType(wasm, &.{.f64_type}, .f128),
4466 .__extenddfxf2 => internIntrinsicType(wasm, &.{.f64_type}, .f80),
4467 .__extendhfsf2 => internIntrinsicType(wasm, &.{.f16_type}, .f32),
4468 .__extendhftf2 => internIntrinsicType(wasm, &.{.f16_type}, .f128),
4469 .__extendhfxf2 => internIntrinsicType(wasm, &.{.f16_type}, .f80),
4470 .__extendsftf2 => internIntrinsicType(wasm, &.{.f32_type}, .f128),
4471 .__extendsfxf2 => internIntrinsicType(wasm, &.{.f32_type}, .f80),
4472 .__extendxftf2 => internIntrinsicType(wasm, &.{.f80_type}, .f128),
4473 .__fabsh => internIntrinsicType(wasm, &.{.f16_type}, .f16),
4474 .__fabsx => internIntrinsicType(wasm, &.{.f80_type}, .f80),
4475 .__fixdfdi => internIntrinsicType(wasm, &.{.f64_type}, .i64),
4476 .__fixdfei => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .f64_type }, .void),
4477 .__fixdfsi => internIntrinsicType(wasm, &.{.f64_type}, .i32),
4478 .__fixdfti => internIntrinsicType(wasm, &.{.f64_type}, .i128),
4479 .__fixhfdi => internIntrinsicType(wasm, &.{.f16_type}, .i64),
4480 .__fixhfei => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .f16_type }, .void),
4481 .__fixhfsi => internIntrinsicType(wasm, &.{.f16_type}, .i32),
4482 .__fixhfti => internIntrinsicType(wasm, &.{.f16_type}, .i128),
4483 .__fixsfdi => internIntrinsicType(wasm, &.{.f32_type}, .i64),
4484 .__fixsfei => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .f32_type }, .void),
4485 .__fixsfsi => internIntrinsicType(wasm, &.{.f32_type}, .i32),
4486 .__fixsfti => internIntrinsicType(wasm, &.{.f32_type}, .i128),
4487 .__fixtfdi => internIntrinsicType(wasm, &.{.f128_type}, .i64),
4488 .__fixtfei => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .f128_type }, .void),
4489 .__fixtfsi => internIntrinsicType(wasm, &.{.f128_type}, .i32),
4490 .__fixtfti => internIntrinsicType(wasm, &.{.f128_type}, .i128),
4491 .__fixunsdfdi => internIntrinsicType(wasm, &.{.f64_type}, .u64),
4492 .__fixunsdfei => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .f64_type }, .void),
4493 .__fixunsdfsi => internIntrinsicType(wasm, &.{.f64_type}, .u32),
4494 .__fixunsdfti => internIntrinsicType(wasm, &.{.f64_type}, .u128),
4495 .__fixunshfdi => internIntrinsicType(wasm, &.{.f16_type}, .u64),
4496 .__fixunshfei => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .f16_type }, .void),
4497 .__fixunshfsi => internIntrinsicType(wasm, &.{.f16_type}, .u32),
4498 .__fixunshfti => internIntrinsicType(wasm, &.{.f16_type}, .u128),
4499 .__fixunssfdi => internIntrinsicType(wasm, &.{.f32_type}, .u64),
4500 .__fixunssfei => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .f32_type }, .void),
4501 .__fixunssfsi => internIntrinsicType(wasm, &.{.f32_type}, .u32),
4502 .__fixunssfti => internIntrinsicType(wasm, &.{.f32_type}, .u128),
4503 .__fixunstfdi => internIntrinsicType(wasm, &.{.f128_type}, .u64),
4504 .__fixunstfei => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .f128_type }, .void),
4505 .__fixunstfsi => internIntrinsicType(wasm, &.{.f128_type}, .u32),
4506 .__fixunstfti => internIntrinsicType(wasm, &.{.f128_type}, .u128),
4507 .__fixunsxfdi => internIntrinsicType(wasm, &.{.f80_type}, .u64),
4508 .__fixunsxfei => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .f80_type }, .void),
4509 .__fixunsxfsi => internIntrinsicType(wasm, &.{.f80_type}, .u32),
4510 .__fixunsxfti => internIntrinsicType(wasm, &.{.f80_type}, .u128),
4511 .__fixxfdi => internIntrinsicType(wasm, &.{.f80_type}, .i64),
4512 .__fixxfei => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .f80_type }, .void),
4513 .__fixxfsi => internIntrinsicType(wasm, &.{.f80_type}, .i32),
4514 .__fixxfti => internIntrinsicType(wasm, &.{.f80_type}, .i128),
4515 .__floatdidf => internIntrinsicType(wasm, &.{.i64_type}, .f64),
4516 .__floatdihf => internIntrinsicType(wasm, &.{.i64_type}, .f16),
4517 .__floatdisf => internIntrinsicType(wasm, &.{.i64_type}, .f32),
4518 .__floatditf => internIntrinsicType(wasm, &.{.i64_type}, .f128),
4519 .__floatdixf => internIntrinsicType(wasm, &.{.i64_type}, .f80),
4520 .__floateidf => internIntrinsicType(wasm, &.{ .usize_type, .usize_type }, .f64),
4521 .__floateihf => internIntrinsicType(wasm, &.{ .usize_type, .usize_type }, .f16),
4522 .__floateisf => internIntrinsicType(wasm, &.{ .usize_type, .usize_type }, .f32),
4523 .__floateitf => internIntrinsicType(wasm, &.{ .usize_type, .usize_type }, .f128),
4524 .__floateixf => internIntrinsicType(wasm, &.{ .usize_type, .usize_type }, .f80),
4525 .__floatsidf => internIntrinsicType(wasm, &.{.i32_type}, .f64),
4526 .__floatsihf => internIntrinsicType(wasm, &.{.i32_type}, .f16),
4527 .__floatsisf => internIntrinsicType(wasm, &.{.i32_type}, .f32),
4528 .__floatsitf => internIntrinsicType(wasm, &.{.i32_type}, .f128),
4529 .__floatsixf => internIntrinsicType(wasm, &.{.i32_type}, .f80),
4530 .__floattidf => internIntrinsicType(wasm, &.{.i128_type}, .f64),
4531 .__floattihf => internIntrinsicType(wasm, &.{.i128_type}, .f16),
4532 .__floattisf => internIntrinsicType(wasm, &.{.i128_type}, .f32),
4533 .__floattitf => internIntrinsicType(wasm, &.{.i128_type}, .f128),
4534 .__floattixf => internIntrinsicType(wasm, &.{.i128_type}, .f80),
4535 .__floatundidf => internIntrinsicType(wasm, &.{.u64_type}, .f64),
4536 .__floatundihf => internIntrinsicType(wasm, &.{.u64_type}, .f16),
4537 .__floatundisf => internIntrinsicType(wasm, &.{.u64_type}, .f32),
4538 .__floatunditf => internIntrinsicType(wasm, &.{.u64_type}, .f128),
4539 .__floatundixf => internIntrinsicType(wasm, &.{.u64_type}, .f80),
4540 .__floatuneidf => internIntrinsicType(wasm, &.{ .usize_type, .usize_type }, .f64),
4541 .__floatuneihf => internIntrinsicType(wasm, &.{ .usize_type, .usize_type }, .f16),
4542 .__floatuneisf => internIntrinsicType(wasm, &.{ .usize_type, .usize_type }, .f32),
4543 .__floatuneitf => internIntrinsicType(wasm, &.{ .usize_type, .usize_type }, .f128),
4544 .__floatuneixf => internIntrinsicType(wasm, &.{ .usize_type, .usize_type }, .f80),
4545 .__floatunsidf => internIntrinsicType(wasm, &.{.u32_type}, .f64),
4546 .__floatunsihf => internIntrinsicType(wasm, &.{.u32_type}, .f16),
4547 .__floatunsisf => internIntrinsicType(wasm, &.{.u32_type}, .f32),
4548 .__floatunsitf => internIntrinsicType(wasm, &.{.u32_type}, .f128),
4549 .__floatunsixf => internIntrinsicType(wasm, &.{.u32_type}, .f80),
4550 .__floatuntidf => internIntrinsicType(wasm, &.{.u128_type}, .f64),
4551 .__floatuntihf => internIntrinsicType(wasm, &.{.u128_type}, .f16),
4552 .__floatuntisf => internIntrinsicType(wasm, &.{.u128_type}, .f32),
4553 .__floatuntitf => internIntrinsicType(wasm, &.{.u128_type}, .f128),
4554 .__floatuntixf => internIntrinsicType(wasm, &.{.u128_type}, .f80),
4555 .__floorh => internIntrinsicType(wasm, &.{.f16_type}, .f16),
4556 .__floorx => internIntrinsicType(wasm, &.{.f80_type}, .f80),
4557 .__fmah => internIntrinsicType(wasm, &.{ .f16_type, .f16_type, .f16_type }, .f16),
4558 .__fmax => internIntrinsicType(wasm, &.{ .f80_type, .f80_type, .f80_type }, .f80),
4559 .__fmaxh => internIntrinsicType(wasm, &.{ .f16_type, .f16_type }, .f16),
4560 .__fmaxx => internIntrinsicType(wasm, &.{ .f80_type, .f80_type }, .f80),
4561 .__fminh => internIntrinsicType(wasm, &.{ .f16_type, .f16_type }, .f16),
4562 .__fminx => internIntrinsicType(wasm, &.{ .f80_type, .f80_type }, .f80),
4563 .__fmodh => internIntrinsicType(wasm, &.{ .f16_type, .f16_type }, .f16),
4564 .__fmodx => internIntrinsicType(wasm, &.{ .f80_type, .f80_type }, .f80),
4565 .__getf2 => internIntrinsicType(wasm, &.{ .f128_type, .f128_type }, .bool),
4566 .__gexf2 => internIntrinsicType(wasm, &.{ .f80_type, .f80_type }, .bool),
4567 .__gttf2 => internIntrinsicType(wasm, &.{ .f128_type, .f128_type }, .bool),
4568 .__gtxf2 => internIntrinsicType(wasm, &.{ .f80_type, .f80_type }, .bool),
4569 .__letf2 => internIntrinsicType(wasm, &.{ .f128_type, .f128_type }, .bool),
4570 .__lexf2 => internIntrinsicType(wasm, &.{ .f80_type, .f80_type }, .bool),
4571 .__log10h => internIntrinsicType(wasm, &.{.f16_type}, .f16),
4572 .__log10x => internIntrinsicType(wasm, &.{.f80_type}, .f80),
4573 .__log2h => internIntrinsicType(wasm, &.{.f16_type}, .f16),
4574 .__log2x => internIntrinsicType(wasm, &.{.f80_type}, .f80),
4575 .__logh => internIntrinsicType(wasm, &.{.f16_type}, .f16),
4576 .__logx => internIntrinsicType(wasm, &.{.f80_type}, .f80),
4577 .__lshrti3 => internIntrinsicType(wasm, &.{ .i128_type, .i32_type }, .i128),
4578 .__lttf2 => internIntrinsicType(wasm, &.{ .f128_type, .f128_type }, .bool),
4579 .__ltxf2 => internIntrinsicType(wasm, &.{ .f80_type, .f80_type }, .bool),
4580 .__modei5 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .usize_type, .usize_type, .usize_type }, .void),
4581 .__modti3 => internIntrinsicType(wasm, &.{ .i128_type, .i128_type }, .i128),
4582 .__mulhf3 => internIntrinsicType(wasm, &.{ .f16_type, .f16_type }, .f16),
4583 .__mulodi4 => internIntrinsicType(wasm, &.{ .i64_type, .i64_type, .usize_type }, .i64),
4584 .__muloti4 => internIntrinsicType(wasm, &.{ .i128_type, .i128_type, .usize_type }, .i128),
4585 .__multf3 => internIntrinsicType(wasm, &.{ .f128_type, .f128_type }, .f128),
4586 .__multi3 => internIntrinsicType(wasm, &.{ .i128_type, .i128_type }, .i128),
4587 .__mulxf3 => internIntrinsicType(wasm, &.{ .f80_type, .f80_type }, .f80),
4588 .__netf2 => internIntrinsicType(wasm, &.{ .f128_type, .f128_type }, .bool),
4589 .__nexf2 => internIntrinsicType(wasm, &.{ .f80_type, .f80_type }, .bool),
4590 .__roundh => internIntrinsicType(wasm, &.{.f16_type}, .f16),
4591 .__roundx => internIntrinsicType(wasm, &.{.f80_type}, .f80),
4592 .__sinh => internIntrinsicType(wasm, &.{.f16_type}, .f16),
4593 .__sinx => internIntrinsicType(wasm, &.{.f80_type}, .f80),
4594 .__sqrth => internIntrinsicType(wasm, &.{.f16_type}, .f16),
4595 .__sqrtx => internIntrinsicType(wasm, &.{.f80_type}, .f80),
4596 .__subhf3 => internIntrinsicType(wasm, &.{ .f16_type, .f16_type }, .f16),
4597 .__subtf3 => internIntrinsicType(wasm, &.{ .f128_type, .f128_type }, .f128),
4598 .__subxf3 => internIntrinsicType(wasm, &.{ .f80_type, .f80_type }, .f80),
4599 .__tanh => internIntrinsicType(wasm, &.{.f16_type}, .f16),
4600 .__tanx => internIntrinsicType(wasm, &.{.f80_type}, .f80),
4601 .__trunch => internIntrinsicType(wasm, &.{.f16_type}, .f16),
4602 .__truncsfhf2 => internIntrinsicType(wasm, &.{.f32_type}, .f16),
4603 .__trunctfdf2 => internIntrinsicType(wasm, &.{.f128_type}, .f64),
4604 .__trunctfhf2 => internIntrinsicType(wasm, &.{.f128_type}, .f16),
4605 .__trunctfsf2 => internIntrinsicType(wasm, &.{.f128_type}, .f32),
4606 .__trunctfxf2 => internIntrinsicType(wasm, &.{.f128_type}, .f80),
4607 .__truncx => internIntrinsicType(wasm, &.{.f80_type}, .f80),
4608 .__truncxfdf2 => internIntrinsicType(wasm, &.{.f80_type}, .f64),
4609 .__truncxfhf2 => internIntrinsicType(wasm, &.{.f80_type}, .f16),
4610 .__truncxfsf2 => internIntrinsicType(wasm, &.{.f80_type}, .f32),
4611 .__udivei5 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .usize_type, .usize_type, .usize_type }, .void),
4612 .__udivti3 => internIntrinsicType(wasm, &.{ .u128_type, .u128_type }, .u128),
4613 .__umodei5 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .usize_type, .usize_type, .usize_type }, .void),
4614 .__umodti3 => internIntrinsicType(wasm, &.{ .u128_type, .u128_type }, .u128),
4615 .ceilq => internIntrinsicType(wasm, &.{.f128_type}, .f128),
4616 .cos => internIntrinsicType(wasm, &.{.f64_type}, .f64),
4617 .cosf => internIntrinsicType(wasm, &.{.f32_type}, .f32),
4618 .cosq => internIntrinsicType(wasm, &.{.f128_type}, .f128),
4619 .exp => internIntrinsicType(wasm, &.{.f64_type}, .f64),
4620 .exp2 => internIntrinsicType(wasm, &.{.f64_type}, .f64),
4621 .exp2f => internIntrinsicType(wasm, &.{.f32_type}, .f32),
4622 .exp2q => internIntrinsicType(wasm, &.{.f128_type}, .f128),
4623 .expf => internIntrinsicType(wasm, &.{.f32_type}, .f32),
4624 .expq => internIntrinsicType(wasm, &.{.f128_type}, .f128),
4625 .fabsq => internIntrinsicType(wasm, &.{.f128_type}, .f128),
4626 .floorq => internIntrinsicType(wasm, &.{.f128_type}, .f128),
4627 .fma => internIntrinsicType(wasm, &.{ .f64_type, .f64_type, .f64_type }, .f64),
4628 .fmaf => internIntrinsicType(wasm, &.{ .f32_type, .f32_type, .f32_type }, .f32),
4629 .fmaq => internIntrinsicType(wasm, &.{ .f128_type, .f128_type, .f128_type }, .f128),
4630 .fmax => internIntrinsicType(wasm, &.{ .f64_type, .f64_type }, .f64),
4631 .fmaxf => internIntrinsicType(wasm, &.{ .f32_type, .f32_type }, .f32),
4632 .fmaxq => internIntrinsicType(wasm, &.{ .f128_type, .f128_type }, .f128),
4633 .fmin => internIntrinsicType(wasm, &.{ .f64_type, .f64_type }, .f64),
4634 .fminf => internIntrinsicType(wasm, &.{ .f32_type, .f32_type }, .f32),
4635 .fminq => internIntrinsicType(wasm, &.{ .f128_type, .f128_type }, .f128),
4636 .fmod => internIntrinsicType(wasm, &.{ .f64_type, .f64_type }, .f64),
4637 .fmodf => internIntrinsicType(wasm, &.{ .f32_type, .f32_type }, .f32),
4638 .fmodq => internIntrinsicType(wasm, &.{ .f128_type, .f128_type }, .f128),
4639 .log => internIntrinsicType(wasm, &.{.f64_type}, .f64),
4640 .log10 => internIntrinsicType(wasm, &.{.f64_type}, .f64),
4641 .log10f => internIntrinsicType(wasm, &.{.f32_type}, .f32),
4642 .log10q => internIntrinsicType(wasm, &.{.f128_type}, .f128),
4643 .log2 => internIntrinsicType(wasm, &.{.f64_type}, .f64),
4644 .log2f => internIntrinsicType(wasm, &.{.f32_type}, .f32),
4645 .log2q => internIntrinsicType(wasm, &.{.f128_type}, .f128),
4646 .logf => internIntrinsicType(wasm, &.{.f32_type}, .f32),
4647 .logq => internIntrinsicType(wasm, &.{.f128_type}, .f128),
4648 .roundq => internIntrinsicType(wasm, &.{.f128_type}, .f128),
4649 .sin => internIntrinsicType(wasm, &.{.f64_type}, .f64),
4650 .sinf => internIntrinsicType(wasm, &.{.f32_type}, .f32),
4651 .sinq => internIntrinsicType(wasm, &.{.f128_type}, .f128),
4652 .sqrtq => internIntrinsicType(wasm, &.{.f128_type}, .f128),
4653 .tan => internIntrinsicType(wasm, &.{.f64_type}, .f64),
4654 .tanf => internIntrinsicType(wasm, &.{.f32_type}, .f32),
4655 .tanq => internIntrinsicType(wasm, &.{.f128_type}, .f128),
4656 .truncq => internIntrinsicType(wasm, &.{.f128_type}, .f128),
4657 .memcpy => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .usize_type }, .usize),
4658 .memmove => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .usize_type }, .usize),
4659 .memset => internIntrinsicType(wasm, &.{ .usize_type, .i32_type, .usize_type }, .usize),
4660 .__addo_limb64 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .usize_type, .bool_type, .u16_type }, .bool),
4661 .__subo_limb64 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .usize_type, .bool_type, .u16_type }, .bool),
4662 .__cmp_limb64 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .bool_type, .u16_type }, .i8),
4663 .__and_limb64 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .usize_type, .u16_type }, .void),
4664 .__or_limb64 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .usize_type, .u16_type }, .void),
4665 .__xor_limb64 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .usize_type, .u16_type }, .void),
4666 .__not_limb64 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .bool_type, .u16_type }, .void),
4667 .__shlo_limb64 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .u16_type, .bool_type, .u16_type }, .bool),
4668 .__shr_limb64 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .u16_type, .bool_type, .u16_type }, .void),
4669 .__clz_limb64 => internIntrinsicType(wasm, &.{ .usize_type, .u16_type }, .u16),
4670 .__ctz_limb64 => internIntrinsicType(wasm, &.{ .usize_type, .u16_type }, .u16),
4671 .__popcount_limb64 => internIntrinsicType(wasm, &.{ .usize_type, .u16_type }, .u16),
4672 .__bitreverse_limb64 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .bool_type, .u16_type }, .void),
4673 .__byteswap_limb64 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .bool_type, .u16_type }, .void),
4674 .__mulo_limb64 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .usize_type, .bool_type, .u16_type }, .bool),
4675 .__abs_limb64 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .u16_type }, .void),
4676 };
4677}
4678
39564679pub fn addExpr(wasm: *Wasm, bytes: []const u8) Allocator.Error!Expr {
39574680 const gpa = wasm.base.comp.gpa;
39584681 // We can't use string table deduplication here since these expressions can
......@@ -3972,64 +4695,63 @@ pub fn addRelocatableDataPayload(wasm: *Wasm, bytes: []const u8) Allocator.Error
39724695 };
39734696}
39744697
3975pub fn uavSymbolIndex(wasm: *Wasm, ip_index: InternPool.Index) Allocator.Error!SymbolTableIndex {
3976 const comp = wasm.base.comp;
3977 assert(comp.config.output_mode == .Obj);
3978 const gpa = comp.gpa;
3979 const name = try wasm.internStringFmt("__anon_{d}", .{@backingInt(ip_index)});
3980 const gop = try wasm.symbol_table.getOrPut(gpa, name);
3981 gop.value_ptr.* = {};
3982 return @fromBackingInt(@intCast(gop.index));
3983}
3984
3985pub fn navSymbolIndex(wasm: *Wasm, nav_index: InternPool.Nav.Index) Allocator.Error!SymbolTableIndex {
4698pub fn addNavReloc(
4699 wasm: *Wasm,
4700 reloc_offset: usize,
4701 nav_index: InternPool.Nav.Index,
4702 nav_ty: Zcu.Type,
4703 addend: u32,
4704) !void {
39864705 const comp = wasm.base.comp;
3987 assert(comp.config.output_mode == .Obj);
39884706 const zcu = comp.zcu.?;
39894707 const ip = &zcu.intern_pool;
39904708 const gpa = comp.gpa;
3991 const nav = ip.getNav(nav_index);
3992 const name = try wasm.internString(nav.fqn.toSlice(ip));
3993 const gop = try wasm.symbol_table.getOrPut(gpa, name);
3994 gop.value_ptr.* = {};
3995 return @fromBackingInt(@intCast(gop.index));
3996}
39974709
3998pub fn errorNameTableSymbolIndex(wasm: *Wasm) Allocator.Error!SymbolTableIndex {
3999 const comp = wasm.base.comp;
4000 assert(comp.config.output_mode == .Obj);
4001 const gpa = comp.gpa;
4002 const gop = try wasm.symbol_table.getOrPut(gpa, wasm.preloaded_strings.__zig_error_name_table);
4003 gop.value_ptr.* = {};
4004 return @fromBackingInt(@intCast(gop.index));
4005}
4006
4007pub fn stackPointerSymbolIndex(wasm: *Wasm) Allocator.Error!SymbolTableIndex {
4008 const comp = wasm.base.comp;
4009 assert(comp.config.output_mode == .Obj);
4010 const gpa = comp.gpa;
4011 const gop = try wasm.symbol_table.getOrPut(gpa, wasm.preloaded_strings.__stack_pointer);
4012 gop.value_ptr.* = {};
4013 return @fromBackingInt(@intCast(gop.index));
4014}
4015
4016pub fn tagTableIndexSymbolIndex(wasm: *Wasm, ip_index: InternPool.Index) Allocator.Error!SymbolTableIndex {
4017 const comp = wasm.base.comp;
4018 assert(comp.config.output_mode == .Obj);
4019 const gpa = comp.gpa;
4020 const name = try wasm.internStringFmt("__zig_tag_name_{d}", .{ip_index});
4021 const gop = try wasm.symbol_table.getOrPut(gpa, name);
4022 gop.value_ptr.* = {};
4023 return @fromBackingInt(@intCast(gop.index));
4024}
4710 const is_obj = comp.config.output_mode == .Obj;
40254711
4026pub fn symbolNameIndex(wasm: *Wasm, name: String) Allocator.Error!SymbolTableIndex {
4027 const comp = wasm.base.comp;
4028 assert(comp.config.output_mode == .Obj);
4029 const gpa = comp.gpa;
4030 const gop = try wasm.symbol_table.getOrPut(gpa, name);
4031 gop.value_ptr.* = {};
4032 return @fromBackingInt(@intCast(gop.index));
4712 if (nav_ty.zigTypeTag(zcu) == .@"fn") {
4713 const gop = try wasm.zcu_indirect_function_set.getOrPut(gpa, nav_index);
4714 if (!gop.found_existing) gop.value_ptr.* = {};
4715 if (is_obj) {
4716 assert(addend == 0);
4717 try wasm.zcu_relocations.append(gpa, .{
4718 .offset = @intCast(reloc_offset),
4719 .pointee = .{ .function_nav = nav_index },
4720 .tag = switch (wasm.pointerSize()) {
4721 4 => .table_index_i32,
4722 8 => .table_index_i64,
4723 else => unreachable,
4724 },
4725 .addend = 0,
4726 });
4727 } else {
4728 try wasm.func_table_fixups.append(gpa, .{
4729 .nav_index = nav_index,
4730 .offset = @intCast(reloc_offset),
4731 });
4732 }
4733 } else {
4734 if (is_obj) {
4735 if (ip.getNav(nav_index).getExtern(ip) == null) _ = try wasm.refNavObj(nav_index);
4736 try wasm.zcu_relocations.append(gpa, .{
4737 .offset = @intCast(reloc_offset),
4738 .pointee = .{ .data_nav = nav_index },
4739 .tag = switch (wasm.pointerSize()) {
4740 4 => .memory_addr_i32,
4741 8 => .memory_addr_i64,
4742 else => unreachable,
4743 },
4744 .addend = @intCast(addend),
4745 });
4746 } else {
4747 try wasm.nav_fixups.ensureUnusedCapacity(gpa, 1);
4748 wasm.nav_fixups.appendAssumeCapacity(.{
4749 .nav_index = nav_index,
4750 .offset = @intCast(reloc_offset),
4751 .addend = addend,
4752 });
4753 }
4754 }
40334755}
40344756
40354757pub fn addUavReloc(
......@@ -4057,12 +4779,12 @@ pub fn addUavReloc(
40574779 if (comp.config.output_mode == .Obj) {
40584780 const gop = try wasm.uavs_obj.getOrPut(gpa, uav_val);
40594781 if (!gop.found_existing) gop.value_ptr.* = undefined; // to avoid recursion, `ZcuDataStarts` will lower the value later
4060 try wasm.out_relocs.append(gpa, .{
4782 try wasm.zcu_relocations.append(gpa, .{
40614783 .offset = @intCast(reloc_offset),
4062 .pointee = .{ .symbol_index = try wasm.uavSymbolIndex(uav_val) },
4784 .pointee = .{ .data_uav = uav_val },
40634785 .tag = switch (wasm.pointerSize()) {
4064 32 => .memory_addr_i32,
4065 64 => .memory_addr_i64,
4786 4 => .memory_addr_i32,
4787 8 => .memory_addr_i64,
40664788 else => unreachable,
40674789 },
40684790 .addend = @intCast(addend),
......@@ -4085,7 +4807,7 @@ pub fn addUavReloc(
40854807pub fn refNavObj(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsObjIndex {
40864808 const comp = wasm.base.comp;
40874809 const gpa = comp.gpa;
4088 assert(comp.config.output_mode != .Obj);
4810 assert(comp.config.output_mode == .Obj);
40894811 const gop = try wasm.navs_obj.getOrPut(gpa, nav_index);
40904812 if (!gop.found_existing) gop.value_ptr.* = .{
40914813 // Lowering the value is delayed to avoid recursion.
......@@ -4113,7 +4835,7 @@ pub fn refNavExe(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsExeIndex {
41134835}
41144836
41154837/// Asserts it is called after `Flush.data_segments` is fully populated and sorted.
4116pub fn uavAddr(wasm: *Wasm, ip_index: InternPool.Index) u32 {
4838pub fn uavAddr(wasm: *const Wasm, ip_index: InternPool.Index) u32 {
41174839 assert(wasm.flush_buffer.memory_layout_finished);
41184840 const comp = wasm.base.comp;
41194841 assert(comp.config.output_mode != .Obj);
......@@ -4123,7 +4845,7 @@ pub fn uavAddr(wasm: *Wasm, ip_index: InternPool.Index) u32 {
41234845}
41244846
41254847/// Asserts it is called after `Flush.data_segments` is fully populated and sorted.
4126pub fn navAddr(wasm: *Wasm, nav_index: InternPool.Nav.Index) u32 {
4848pub fn navAddr(wasm: *const Wasm, nav_index: InternPool.Nav.Index) u32 {
41274849 assert(wasm.flush_buffer.memory_layout_finished);
41284850 const comp = wasm.base.comp;
41294851 assert(comp.config.output_mode != .Obj);
......@@ -4139,23 +4861,34 @@ pub fn navAddr(wasm: *Wasm, nav_index: InternPool.Nav.Index) u32 {
41394861 .@"extern" => |ext| if (wasm.getExistingString(ext.name.toSlice(ip))) |symbol_name| {
41404862 if (wasm.object_data_imports.getPtr(symbol_name)) |import| {
41414863 switch (import.resolution.unpack(wasm)) {
4142 .unresolved => unreachable,
4864 .unresolved => {},
41434865 .object => |object_data_index| {
41444866 const object_data = object_data_index.ptr(wasm);
41454867 const ds_id: DataSegmentId = .fromObjectDataSegment(wasm, object_data.segment);
41464868 const segment_base_addr = wasm.flush_buffer.data_segments.get(ds_id).?;
41474869 return segment_base_addr + object_data.offset;
41484870 },
4149 .__zig_error_names => @panic("TODO"),
4150 .__zig_error_name_table => @panic("TODO"),
4151 .__heap_base => @panic("TODO"),
4152 .__heap_end => @panic("TODO"),
4153 .uav_exe => @panic("TODO"),
4154 .uav_obj => @panic("TODO"),
4155 .nav_exe => @panic("TODO"),
4156 .nav_obj => @panic("TODO"),
4871 .__heap_base,
4872 .__heap_end,
4873 .uav_exe,
4874 .nav_exe,
4875 => {
4876 const data_loc = import.resolution.dataLoc(wasm);
4877 return wasm.flush_buffer.data_segments.get(data_loc.segment).? + data_loc.offset;
4878 },
4879 .__zig_error_names,
4880 .__zig_error_name_table,
4881 .__zig_tag_names,
4882 .__zig_tag_name_table,
4883 .uav_obj,
4884 .nav_obj,
4885 => unreachable,
41574886 }
41584887 }
4888 if (wasm.flush_buffer.data_exports.get(symbol_name)) |symbol| {
4889 const data_loc = symbol.resolution.dataLoc(wasm);
4890 return wasm.flush_buffer.data_segments.get(data_loc.segment).? + data_loc.offset;
4891 }
41594892 },
41604893 else => {},
41614894 }
......@@ -4177,8 +4910,12 @@ pub fn tagIndexTableAddr(wasm: *Wasm, ip_index: InternPool.Index) u32 {
41774910 assert(comp.config.output_mode != .Obj);
41784911 const f = &wasm.flush_buffer;
41794912 const table_base_addr = f.data_segments.get(.__zig_tag_name_table).?;
4180 const table_index = f.enum_tag_name_table.get(ip_index).?;
4181 return table_base_addr + table_index * 8;
4913 return table_base_addr + wasm.tagIndexTableOffset(ip_index);
4914}
4915
4916pub fn tagIndexTableOffset(wasm: *const Wasm, ip_index: InternPool.Index) u32 {
4917 const table_index = wasm.flush_buffer.enum_tag_name_table.get(ip_index).?;
4918 return table_index * wasm.pointerSize() * 2;
41824919}
41834920
41844921fn convertZcuFnType(
......@@ -4255,7 +4992,7 @@ pub fn isBss(wasm: *const Wasm, optional_name: OptionalString) bool {
42554992/// those entries.
42564993fn lowerZcuData(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !ZcuDataObj {
42574994 const code_start: u32 = @intCast(wasm.string_bytes.items.len);
4258 const relocs_start: u32 = @intCast(wasm.out_relocs.len);
4995 const relocs_start: u32 = @intCast(wasm.zcu_relocations.len);
42594996 const uav_fixups_start: u32 = @intCast(wasm.uav_fixups.items.len);
42604997 const nav_fixups_start: u32 = @intCast(wasm.nav_fixups.items.len);
42614998 const func_table_fixups_start: u32 = @intCast(wasm.func_table_fixups.items.len);
......@@ -4271,8 +5008,9 @@ fn lowerZcuData(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !Zcu
42715008 }
42725009
42735010 const code_len: u32 = @intCast(wasm.string_bytes.items.len - code_start);
4274 const relocs_len: u32 = @intCast(wasm.out_relocs.len - relocs_start);
5011 const relocs_len: u32 = @intCast(wasm.zcu_relocations.len - relocs_start);
42755012 const any_fixups =
5013 relocs_len != 0 or
42765014 uav_fixups_start != wasm.uav_fixups.items.len or
42775015 nav_fixups_start != wasm.nav_fixups.items.len or
42785016 func_table_fixups_start != wasm.func_table_fixups.items.len;
src/link/Wasm/Flush.zig+1114-131
......@@ -7,7 +7,6 @@ const Object = @import("Object.zig");
77const Zcu = @import("../../Zcu.zig");
88const Alignment = Wasm.Alignment;
99const String = Wasm.String;
10const Relocation = Wasm.Relocation;
1110const InternPool = @import("../../InternPool.zig");
1211const Mir = @import("../../codegen/wasm/Mir.zig");
1312
......@@ -33,8 +32,13 @@ data_segment_groups: ArrayList(DataSegmentGroup) = .empty,
3332binary_bytes: ArrayList(u8) = .empty,
3433missing_exports: std.array_hash_map.Auto(String, void) = .empty,
3534function_imports: std.array_hash_map.Auto(String, Wasm.FunctionImportId) = .empty,
35intrinsic_function_imports: std.array_hash_map.Auto(String, Wasm.FunctionType.Index) = .empty,
36/// Function aliases emitted after function symbols.
37function_export_symbols: std.array_hash_map.Auto(String, FunctionExportSymbol) = .empty,
3638global_imports: std.array_hash_map.Auto(String, Wasm.GlobalImportId) = .empty,
3739data_imports: std.array_hash_map.Auto(String, Wasm.DataImportId) = .empty,
40/// Data aliases emitted after data symbols.
41data_exports: std.array_hash_map.Auto(String, DataExportSymbol) = .empty,
3842
3943indirect_function_table: std.array_hash_map.Auto(Wasm.OutputFunctionIndex, void) = .empty,
4044
......@@ -43,6 +47,9 @@ func_types: std.array_hash_map.Auto(Wasm.FunctionType.Index, void) = .empty,
4347
4448enum_tag_name_table: std.array_hash_map.Auto(InternPool.Index, u32) = .empty,
4549
50code_relocs: std.ArrayList(Relocation) = .empty,
51data_relocs: std.ArrayList(Relocation) = .empty,
52
4653/// For debug purposes only.
4754memory_layout_finished: bool = false,
4855
......@@ -55,6 +62,74 @@ pub const FuncTypeIndex = enum(u32) {
5562 }
5663};
5764
65/// Index into SYMTAB_FUNCTION.
66const FunctionSymbolIndex = enum(u32) {
67 _,
68
69 fn fromOutputFunctionIndex(i: Wasm.OutputFunctionIndex) FunctionSymbolIndex {
70 return @fromBackingInt(@backingInt(i));
71 }
72
73 fn fromObjectFunctionHandlingWeak(wasm: *const Wasm, index: Wasm.ObjectFunctionIndex) FunctionSymbolIndex {
74 return fromOutputFunctionIndex(.fromObjectFunctionHandlingWeak(wasm, index));
75 }
76
77 fn fromIpNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) FunctionSymbolIndex {
78 return fromOutputFunctionIndex(.fromIpNav(wasm, nav_index));
79 }
80
81 fn fromTagIndexType(wasm: *const Wasm, ip_index: InternPool.Index) FunctionSymbolIndex {
82 return fromOutputFunctionIndex(.fromTagIndexType(wasm, ip_index));
83 }
84
85 fn fromSymbolName(wasm: *const Wasm, name: String) FunctionSymbolIndex {
86 const f = &wasm.flush_buffer;
87 if (f.function_imports.getIndex(name)) |i| return @fromBackingInt(@intCast(i));
88 if (f.intrinsic_function_imports.getIndex(name)) |i| return @fromBackingInt(@intCast(
89 f.function_imports.entries.len + i,
90 ));
91 if (f.function_export_symbols.getIndex(name)) |i| return @fromBackingInt(@intCast(
92 f.function_imports.entries.len + f.intrinsic_function_imports.entries.len +
93 wasm.functions.entries.len + i,
94 ));
95 return fromOutputFunctionIndex(.fromSymbolName(wasm, name));
96 }
97};
98
99/// Index into SYMTAB_DATA.
100const DataSymbolIndex = enum(u32) {
101 _,
102
103 fn fromOutputDataIndex(i: Wasm.OutputDataIndex) DataSymbolIndex {
104 return @fromBackingInt(@backingInt(i));
105 }
106
107 fn fromResolution(wasm: *const Wasm, resolution: Wasm.ObjectDataImport.Resolution) DataSymbolIndex {
108 return fromOutputDataIndex(Wasm.OutputDataIndex.fromResolution(wasm, resolution).?);
109 }
110
111 fn fromObjectData(wasm: *const Wasm, index: Wasm.ObjectData.Index) DataSymbolIndex {
112 return fromOutputDataIndex(.fromObjectData(wasm, index));
113 }
114
115 fn fromUav(wasm: *const Wasm, ip_index: InternPool.Index) DataSymbolIndex {
116 return fromOutputDataIndex(.fromUav(wasm, ip_index));
117 }
118
119 fn fromNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) DataSymbolIndex {
120 return fromOutputDataIndex(.fromNav(wasm, nav_index));
121 }
122
123 fn fromSymbolName(wasm: *const Wasm, name: String) DataSymbolIndex {
124 const f = &wasm.flush_buffer;
125 if (f.data_imports.getIndex(name)) |i| return @fromBackingInt(@intCast(i));
126 if (f.data_exports.getIndex(name)) |i| return @fromBackingInt(@intCast(
127 f.data_imports.entries.len + wasm.datas.entries.len + i,
128 ));
129 return fromOutputDataIndex(.fromSymbolName(wasm, name));
130 }
131};
132
58133/// Index into `indirect_function_table`.
59134const IndirectFunctionTableIndex = enum(u32) {
60135 _,
......@@ -71,9 +146,8 @@ const IndirectFunctionTableIndex = enum(u32) {
71146 return @fromBackingInt(@intCast(f.indirect_function_table.getIndex(i).?));
72147 }
73148
74 fn fromZcuIndirectFunctionSetIndex(i: Wasm.ZcuIndirectFunctionSetIndex) IndirectFunctionTableIndex {
75 // These are the same since those are added to the table first.
76 return @fromBackingInt(@intCast(@backingInt(i)));
149 fn fromIpNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) IndirectFunctionTableIndex {
150 return fromOutputFunctionIndex(&wasm.flush_buffer, .fromIpNav(wasm, nav_index));
77151 }
78152
79153 fn toAbi(i: IndirectFunctionTableIndex) u32 {
......@@ -81,6 +155,39 @@ const IndirectFunctionTableIndex = enum(u32) {
81155 }
82156};
83157
158const SymbolTableOffsets = struct {
159 function: u32,
160 data: u32,
161 global: u32,
162 table: u32,
163};
164
165const FunctionExportSymbol = struct {
166 function_index: Wasm.FunctionIndex,
167 flags: Wasm.SymbolFlags,
168};
169
170const DataExportSymbol = struct {
171 resolution: Wasm.ObjectDataImport.Resolution,
172 flags: Wasm.SymbolFlags,
173};
174
175const Relocation = struct {
176 tag: Object.RelocationType,
177 offset: u32,
178 pointee: Pointee,
179 addend: i32,
180
181 const Pointee = union {
182 data: DataSymbolIndex,
183 type_index: FuncTypeIndex,
184 section: Wasm.ObjectSectionIndex,
185 function: FunctionSymbolIndex,
186 global: Wasm.GlobalIndex,
187 table: Wasm.TableIndex,
188 };
189};
190
84191const DataSegmentGroup = struct {
85192 first_segment: Wasm.DataSegmentId,
86193 end_addr: u32,
......@@ -90,9 +197,14 @@ pub fn clear(f: *Flush) void {
90197 f.data_segments.clearRetainingCapacity();
91198 f.data_segment_groups.clearRetainingCapacity();
92199 f.binary_bytes.clearRetainingCapacity();
200 f.intrinsic_function_imports.clearRetainingCapacity();
201 f.function_export_symbols.clearRetainingCapacity();
202 f.data_exports.clearRetainingCapacity();
93203 f.indirect_function_table.clearRetainingCapacity();
94204 f.func_types.clearRetainingCapacity();
95205 f.enum_tag_name_table.clearRetainingCapacity();
206 f.code_relocs.clearRetainingCapacity();
207 f.data_relocs.clearRetainingCapacity();
96208 f.memory_layout_finished = false;
97209}
98210
......@@ -102,11 +214,16 @@ pub fn deinit(f: *Flush, gpa: Allocator) void {
102214 f.binary_bytes.deinit(gpa);
103215 f.missing_exports.deinit(gpa);
104216 f.function_imports.deinit(gpa);
217 f.intrinsic_function_imports.deinit(gpa);
218 f.function_export_symbols.deinit(gpa);
105219 f.global_imports.deinit(gpa);
106220 f.data_imports.deinit(gpa);
221 f.data_exports.deinit(gpa);
107222 f.indirect_function_table.deinit(gpa);
108223 f.func_types.deinit(gpa);
109224 f.enum_tag_name_table.deinit(gpa);
225 f.code_relocs.deinit(gpa);
226 f.data_relocs.deinit(gpa);
110227 f.* = undefined;
111228}
112229
......@@ -134,48 +251,6 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
134251
135252 log.debug("total MIR instructions: {d}", .{wasm.mir_instructions.len});
136253
137 // Detect any intrinsics that were called; they need to have dependencies on the symbols marked.
138 // Likewise detect `@tagName` calls so those functions can be included in the output and synthesized.
139 for (wasm.mir_instructions.items(.tag), wasm.mir_instructions.items(.data)) |tag, *data| switch (tag) {
140 .call_intrinsic => {
141 const symbol_name = try wasm.internString(@tagName(data.intrinsic));
142 const i: Wasm.FunctionImport.Index = @fromBackingInt(@intCast(wasm.object_function_imports.getIndex(symbol_name) orelse {
143 return diags.fail("missing compiler runtime intrinsic '{t}' (undefined linker symbol)", .{
144 data.intrinsic,
145 });
146 }));
147 try wasm.markFunctionImport(symbol_name, i.value(wasm), i);
148 log.debug("markFunctionImport intrinsic {d}={t}", .{ i, data.intrinsic });
149 },
150 .call_tag_index => {
151 assert(ip.indexToKey(data.ip_index) == .enum_type);
152 const gop = try wasm.zcu_funcs.getOrPut(gpa, data.ip_index);
153 if (!gop.found_existing) {
154 const int_tag_ty = Zcu.Type.fromInterned(data.ip_index).backingIntType(zcu);
155 gop.value_ptr.* = .{ .tag_name = .{
156 .symbol_name = try wasm.internStringFmt("__zig_tag_index_{d}", .{data.ip_index}),
157 .type_index = try wasm.internFunctionType(.auto, &.{int_tag_ty.ip_index}, .u32, false, target),
158 } };
159 }
160 try wasm.functions.put(gpa, .fromZcuFunc(wasm, @fromBackingInt(@intCast(gop.index))), {});
161 },
162 .enum_tag_name_table_ref => {
163 assert(ip.indexToKey(data.ip_index) == .enum_type);
164 const gop = try f.enum_tag_name_table.getOrPut(gpa, data.ip_index);
165 if (!gop.found_existing) {
166 wasm.tag_name_table_ref_count += 1;
167 gop.value_ptr.* = @intCast(wasm.tag_name_offs.items.len);
168 const tag_names = ip.loadEnumType(data.ip_index).field_names;
169 for (tag_names.get(ip)) |tag_name| {
170 const slice = tag_name.toSlice(ip);
171 try wasm.tag_name_offs.append(gpa, @intCast(wasm.tag_name_bytes.items.len));
172 try wasm.tag_name_bytes.appendSlice(gpa, slice[0 .. slice.len + 1]);
173 }
174 }
175 },
176 else => continue,
177 };
178
179254 {
180255 var i = wasm.function_imports_len_prelink;
181256 while (i < f.function_imports.entries.len) {
......@@ -225,10 +300,24 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
225300 log.debug("flush export '{s}' nav={d}", .{ nav_export.name.slice(wasm), nav_export.nav_index });
226301 const function_index = Wasm.FunctionIndex.fromIpNav(wasm, nav_export.nav_index).?;
227302 const explicit = f.missing_exports.swapRemove(nav_export.name);
228 const is_hidden = !explicit and switch (export_index.ptr(zcu).opts.visibility) {
303 const opts = export_index.ptr(zcu).opts;
304 const is_hidden = !explicit and switch (opts.visibility) {
229305 .hidden => true,
230306 .default, .protected => false,
231307 };
308 if (is_obj) try f.function_export_symbols.put(gpa, nav_export.name, .{
309 .function_index = function_index,
310 .flags = .{
311 .binding = switch (opts.linkage) {
312 .internal => .local,
313 .strong => .strong,
314 .weak => .weak,
315 .link_once => @panic("TODO: COMDAT"),
316 },
317 .visibility_hidden = is_hidden,
318 .exported = !is_hidden,
319 },
320 });
232321 if (is_hidden) {
233322 try wasm.hidden_function_exports.put(gpa, nav_export.name, function_index);
234323 } else {
......@@ -239,17 +328,141 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
239328 if (nav_export.name.toOptional() == entry_name)
240329 wasm.entry_resolution = .fromIpNav(wasm, nav_export.nav_index);
241330 } else {
242 // This is a data export because Zcu currently has no way to
243 // export wasm globals.
244 _ = f.missing_exports.swapRemove(nav_export.name);
331 // data exports are linker symbols
332 // explicit exports become address globals
333 const explicit = f.missing_exports.swapRemove(nav_export.name);
334 const opts = export_index.ptr(zcu).opts;
335 try f.data_exports.put(gpa, nav_export.name, .{
336 .resolution = .fromIpNav(wasm, nav_export.nav_index),
337 .flags = if (is_obj) .{
338 .binding = switch (opts.linkage) {
339 .internal => .local,
340 .strong => .strong,
341 .weak => .weak,
342 .link_once => @panic("TODO: COMDAT"),
343 },
344 .visibility_hidden = !explicit and switch (opts.visibility) {
345 .default => false,
346 .hidden => true,
347 .protected => false,
348 },
349 .exported = explicit,
350 .tls = ip.getNav(nav_export.nav_index).resolved.?.@"threadlocal",
351 } else .{},
352 });
245353 _ = f.data_imports.swapRemove(nav_export.name);
246 if (!is_obj) {
247 diags.addError("unable to export data symbol '{s}'; not emitting a relocatable", .{
248 nav_export.name.slice(wasm),
354 if (explicit and !is_obj) {
355 const global_resolution: Wasm.GlobalImport.Resolution = .fromIpNav(
356 wasm,
357 nav_export.nav_index,
358 );
359 try wasm.globals.put(gpa, global_resolution, {});
360 try wasm.global_exports.append(gpa, .{
361 .name = nav_export.name,
362 .global_index = Wasm.GlobalIndex.fromResolution(wasm, global_resolution).?,
249363 });
250364 }
251365 }
252366 }
367 // handle exported values without navs
368 for (wasm.uav_exports.keys(), wasm.uav_exports.values()) |uav_export, export_index| {
369 assert(!ip.isFunctionType(ip.typeOf(uav_export.uav_index)));
370 const explicit = f.missing_exports.swapRemove(uav_export.name);
371 const opts = export_index.ptr(zcu).opts;
372 try f.data_exports.put(gpa, uav_export.name, .{
373 .resolution = .fromIpIndex(wasm, uav_export.uav_index),
374 .flags = if (is_obj) .{
375 .binding = switch (opts.linkage) {
376 .internal => .local,
377 .strong => .strong,
378 .weak => .weak,
379 .link_once => @panic("TODO: COMDAT"),
380 },
381 .visibility_hidden = !explicit and switch (opts.visibility) {
382 .default => false,
383 .hidden => true,
384 .protected => false,
385 },
386 .exported = explicit,
387 } else .{},
388 });
389 _ = f.data_imports.swapRemove(uav_export.name);
390 if (explicit and !is_obj) {
391 const global_resolution: Wasm.GlobalImport.Resolution = .fromIpIndex(
392 wasm,
393 uav_export.uav_index,
394 );
395 try wasm.globals.put(gpa, global_resolution, {});
396 try wasm.global_exports.append(gpa, .{
397 .name = uav_export.name,
398 .global_index = Wasm.GlobalIndex.fromResolution(wasm, global_resolution).?,
399 });
400 }
401 }
402
403 // Detect any intrinsics that were called; they need to have dependencies on the symbols marked.
404 // Likewise detect `@tagName` calls so those functions can be included in the output and synthesized.
405 for (wasm.mir_instructions.items(.tag), wasm.mir_instructions.items(.data)) |tag, *data| switch (tag) {
406 .call_intrinsic => {
407 const symbol_name = try wasm.internString(@tagName(data.intrinsic));
408 if (Wasm.FunctionIndex.fromSymbolName(wasm, symbol_name) == null and
409 !f.function_imports.contains(symbol_name))
410 {
411 if (wasm.object_function_imports.getIndex(symbol_name)) |object_import_index| {
412 const i: Wasm.FunctionImport.Index = @fromBackingInt(@intCast(object_import_index));
413 try wasm.markFunctionImport(symbol_name, i.value(wasm), i);
414 if (Wasm.FunctionIndex.fromSymbolName(wasm, symbol_name) == null) {
415 try f.function_imports.put(gpa, symbol_name, .fromObject(i, wasm));
416 }
417 } else if (is_obj) {
418 const gop = try f.intrinsic_function_imports.getOrPut(gpa, symbol_name);
419 if (!gop.found_existing) gop.value_ptr.* = try wasm.intrinsicFunctionType(data.intrinsic);
420 } else {
421 return diags.fail("missing compiler runtime intrinsic '{t}' (undefined linker symbol)", .{
422 data.intrinsic,
423 });
424 }
425 }
426 },
427 .call_indirect => {
428 const fn_info = zcu.typeToFunc(.fromInterned(data.ip_index)).?;
429 const type_index = wasm.getExistingFunctionType(
430 fn_info.cc,
431 fn_info.param_types.get(ip),
432 .fromInterned(fn_info.return_type),
433 fn_info.is_var_args,
434 target,
435 ).?;
436 try f.func_types.put(gpa, type_index, {});
437 },
438 .call_tag_index => {
439 assert(ip.indexToKey(data.ip_index) == .enum_type);
440 const gop = try wasm.zcu_funcs.getOrPut(gpa, data.ip_index);
441 if (!gop.found_existing) {
442 const int_tag_ty = Zcu.Type.fromInterned(data.ip_index).backingIntType(zcu);
443 gop.value_ptr.* = .{ .tag_name = .{
444 .symbol_name = try wasm.internStringFmt("__zig_tag_index_{d}", .{data.ip_index}),
445 .type_index = try wasm.internFunctionType(.auto, &.{int_tag_ty.ip_index}, .u32, false, target),
446 } };
447 }
448 try wasm.functions.put(gpa, .fromZcuFunc(wasm, @fromBackingInt(@intCast(gop.index))), {});
449 },
450 .enum_tag_name_table_ref => {
451 assert(ip.indexToKey(data.ip_index) == .enum_type);
452 const gop = try f.enum_tag_name_table.getOrPut(gpa, data.ip_index);
453 if (!gop.found_existing) {
454 wasm.tag_name_table_ref_count += 1;
455 gop.value_ptr.* = @intCast(wasm.tag_name_offs.items.len);
456 const tag_names = ip.loadEnumType(data.ip_index).field_names;
457 for (tag_names.get(ip)) |tag_name| {
458 const slice = tag_name.toSlice(ip);
459 try wasm.tag_name_offs.append(gpa, @intCast(wasm.tag_name_bytes.items.len));
460 try wasm.tag_name_bytes.appendSlice(gpa, slice[0 .. slice.len + 1]);
461 }
462 }
463 },
464 else => continue,
465 };
253466
254467 for (f.missing_exports.keys()) |exp_name| {
255468 diags.addError("manually specified export name '{s}' undefined", .{exp_name.slice(wasm)});
......@@ -300,7 +513,27 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
300513 if (wasm.object_init_funcs.items.len > 0) {
301514 // Zig has no constructors so these are only for object file inputs.
302515 mem.sortUnstable(Wasm.InitFunc, wasm.object_init_funcs.items, {}, Wasm.InitFunc.lessThan);
303 try wasm.functions.put(gpa, .__wasm_call_ctors, {});
516 if (!is_obj) try wasm.functions.put(gpa, .__wasm_call_ctors, {});
517 }
518
519 if (is_obj) {
520 try wasm.datas.ensureUnusedCapacity(gpa, wasm.uavs_obj.entries.len + wasm.navs_obj.entries.len + 4);
521 for (0..wasm.uavs_obj.entries.len) |i| wasm.datas.putAssumeCapacity(
522 .pack(wasm, .{ .uav_obj = @fromBackingInt(@intCast(i)) }),
523 {},
524 );
525 for (0..wasm.navs_obj.entries.len) |i| wasm.datas.putAssumeCapacity(
526 .pack(wasm, .{ .nav_obj = @fromBackingInt(@intCast(i)) }),
527 {},
528 );
529 if (wasm.error_name_table_ref_count > 0) {
530 wasm.datas.putAssumeCapacity(.__zig_error_names, {});
531 wasm.datas.putAssumeCapacity(.__zig_error_name_table, {});
532 }
533 if (wasm.tag_name_table_ref_count > 0) {
534 wasm.datas.putAssumeCapacity(.__zig_tag_names, {});
535 wasm.datas.putAssumeCapacity(.__zig_tag_name_table, {});
536 }
304537 }
305538
306539 // Merge and order the data segments. Depends on garbage collection so that
......@@ -341,14 +574,33 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
341574 // dropped in __wasm_init_memory, which is registered as the start function
342575 // We also initialize bss segments (using memory.fill) as part of this
343576 // function.
344 if (wasm.any_passive_inits) {
577 if (!is_obj and wasm.any_passive_inits) {
345578 try wasm.addFunction(.__wasm_init_memory, &.{}, &.{});
346579 }
347580
348581 try wasm.tables.ensureUnusedCapacity(gpa, 1);
349582
350583 if (f.indirect_function_table.entries.len > 0) {
351 wasm.tables.putAssumeCapacity(.__indirect_function_table, {});
584 if (is_obj) {
585 const name = wasm.preloaded_strings.__indirect_function_table;
586 const gop = try wasm.object_table_imports.getOrPut(gpa, name);
587 if (!gop.found_existing) gop.value_ptr.* = .{
588 .flags = .{
589 .undefined = true,
590 .no_strip = true,
591 },
592 .module_name = wasm.preloaded_strings.env,
593 .name = name,
594 .source_location = .zig_object_nofile,
595 .resolution = .unresolved,
596 .limits_min = 1,
597 .limits_max = 0,
598 };
599 const import_index: Wasm.TableImport.Index = @fromBackingInt(@intCast(gop.index));
600 try wasm.markTableImport(name, gop.value_ptr, import_index);
601 } else {
602 wasm.tables.putAssumeCapacity(.__indirect_function_table, {});
603 }
352604 }
353605
354606 // Sort order:
......@@ -449,7 +701,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
449701 const start_addr = alignment.forward(memory_ptr);
450702
451703 const want_new_segment = b: {
452 if (is_obj) break :b false;
704 if (is_obj) break :b i != 0;
453705 switch (seen_tls) {
454706 .before => switch (category) {
455707 .tls => {
......@@ -489,7 +741,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
489741 log.debug("0x{x} {d} {s}", .{ start_addr, @backingInt(segment_id), segment_id.name(wasm) });
490742 memory_ptr = start_addr + size;
491743 }
492 if (category != .zero) try f.data_segment_groups.append(gpa, .{
744 if (is_obj or category != .zero) try f.data_segment_groups.append(gpa, .{
493745 .first_segment = first_segment,
494746 .end_addr = @intCast(memory_ptr),
495747 });
......@@ -555,7 +807,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
555807
556808 // When we have TLS GOT entries and shared memory is enabled, we must
557809 // perform runtime relocations or else we don't create the function.
558 if (shared_memory and virtual_addrs.tls_base != null) {
810 if (!is_obj and shared_memory and virtual_addrs.tls_base != null) {
559811 // This logic that checks `any_tls_relocs` is missing the part where it
560812 // also notices threadlocal globals from Zcu code.
561813 if (wasm.any_tls_relocs) try wasm.addFunction(.__wasm_apply_global_tls_relocs, &.{}, &.{});
......@@ -582,6 +834,9 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
582834 for (f.function_imports.values()) |id| {
583835 try f.func_types.put(gpa, id.functionType(wasm), {});
584836 }
837 for (f.intrinsic_function_imports.values()) |type_index| {
838 try f.func_types.put(gpa, type_index, {});
839 }
585840 for (wasm.functions.keys()) |function| {
586841 try f.func_types.put(gpa, function.typeIndex(wasm), {});
587842 }
......@@ -617,7 +872,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
617872 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
618873
619874 for (f.function_imports.values()) |id| {
620 const module_name = id.moduleName(wasm).slice(wasm).?;
875 const module_name = (id.moduleName(wasm).unwrap() orelse wasm.preloaded_strings.env).slice(wasm);
621876 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(module_name.len)));
622877 try binary_bytes.appendSlice(gpa, module_name);
623878
......@@ -631,6 +886,20 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
631886 }
632887 total_imports += f.function_imports.entries.len;
633888
889 for (f.intrinsic_function_imports.keys(), f.intrinsic_function_imports.values()) |name_string, type_index| {
890 const module_name = wasm.preloaded_strings.env.slice(wasm);
891 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(module_name.len)));
892 try binary_bytes.appendSlice(gpa, module_name);
893
894 const name = name_string.slice(wasm);
895 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
896 try binary_bytes.appendSlice(gpa, name);
897
898 try binary_bytes.append(gpa, @backingInt(std.wasm.ExternalKind.function));
899 try appendLeb128(gpa, binary_bytes, @backingInt(FuncTypeIndex.fromTypeIndex(type_index, f)));
900 }
901 total_imports += f.intrinsic_function_imports.entries.len;
902
634903 for (wasm.table_imports.values()) |id| {
635904 const table_import = id.value(wasm);
636905 const module_name = table_import.module_name.slice(wasm);
......@@ -662,7 +931,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
662931 }
663932
664933 for (f.global_imports.values()) |id| {
665 const module_name = id.moduleName(wasm).slice(wasm).?;
934 const module_name = (id.moduleName(wasm).unwrap() orelse wasm.preloaded_strings.env).slice(wasm);
666935 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(module_name.len)));
667936 try binary_bytes.appendSlice(gpa, module_name);
668937
......@@ -726,12 +995,12 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
726995 for (wasm.globals.keys()) |global_resolution| {
727996 switch (global_resolution.unpack(wasm)) {
728997 .unresolved => unreachable,
729 .__heap_base => try appendGlobal(gpa, binary_bytes, 0, virtual_addrs.heap_base),
730 .__heap_end => try appendGlobal(gpa, binary_bytes, 0, virtual_addrs.heap_end),
731 .__stack_pointer => try appendGlobal(gpa, binary_bytes, 1, virtual_addrs.stack_pointer),
732 .__tls_align => try appendGlobal(gpa, binary_bytes, 0, @intCast(virtual_addrs.tls_align.toByteUnits().?)),
733 .__tls_base => try appendGlobal(gpa, binary_bytes, 1, virtual_addrs.tls_base.?),
734 .__tls_size => try appendGlobal(gpa, binary_bytes, 0, virtual_addrs.tls_size.?),
998 .__heap_base => try appendGlobal(gpa, binary_bytes, 0, virtual_addrs.heap_base, is64),
999 .__heap_end => try appendGlobal(gpa, binary_bytes, 0, virtual_addrs.heap_end, is64),
1000 .__stack_pointer => try appendGlobal(gpa, binary_bytes, 1, virtual_addrs.stack_pointer, is64),
1001 .__tls_align => try appendGlobal(gpa, binary_bytes, 0, @intCast(virtual_addrs.tls_align.toByteUnits().?), is64),
1002 .__tls_base => try appendGlobal(gpa, binary_bytes, 1, virtual_addrs.tls_base.?, is64),
1003 .__tls_size => try appendGlobal(gpa, binary_bytes, 0, virtual_addrs.tls_size.?, is64),
7351004 .object_global => |i| {
7361005 const global = i.ptr(wasm);
7371006 try binary_bytes.appendSlice(gpa, &.{
......@@ -740,8 +1009,9 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
7401009 });
7411010 try emitExpr(wasm, binary_bytes, global.expr);
7421011 },
743 .nav_exe => unreachable, // Zig source code currently cannot represent this.
744 .nav_obj => unreachable, // Zig source code currently cannot represent this.
1012 .uav_exe => |i| try appendGlobal(gpa, binary_bytes, 0, wasm.uavAddr(i.key(wasm).*), is64),
1013 .nav_exe => |i| try appendGlobal(gpa, binary_bytes, 0, wasm.navAddr(i.key(wasm).*), is64),
1014 .uav_obj, .nav_obj => unreachable,
7451015 }
7461016 }
7471017
......@@ -766,7 +1036,8 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
7661036
7671037 if (wasm.export_table and f.indirect_function_table.entries.len > 0) {
7681038 const name = "__indirect_function_table";
769 const index: u32 = @intCast(wasm.tables.getIndex(.__indirect_function_table).?);
1039 const index: u32 = @intCast(wasm.table_imports.entries.len +
1040 wasm.tables.getIndex(.__indirect_function_table).?);
7701041 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
7711042 try binary_bytes.appendSlice(gpa, name);
7721043 try binary_bytes.append(gpa, @backingInt(std.wasm.ExternalKind.table));
......@@ -803,8 +1074,10 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
8031074 // start section
8041075 if (wasm.functions.getIndex(.__wasm_init_memory)) |func_index| {
8051076 try emitStartSection(gpa, binary_bytes, .fromFunctionIndex(wasm, @fromBackingInt(@intCast(func_index))));
1077 section_index += 1;
8061078 } else if (Wasm.OutputFunctionIndex.fromResolution(wasm, wasm.entry_resolution)) |func_index| {
8071079 try emitStartSection(gpa, binary_bytes, func_index);
1080 section_index += 1;
8081081 }
8091082
8101083 // element section
......@@ -812,7 +1085,10 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
8121085 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
8131086
8141087 // indirect function table elements
815 const table_index: u32 = @intCast(wasm.tables.getIndex(.__indirect_function_table).?);
1088 const table_index: u32 = @intCast(
1089 wasm.table_imports.getIndex(wasm.preloaded_strings.__indirect_function_table) orelse
1090 wasm.table_imports.entries.len + wasm.tables.getIndex(.__indirect_function_table).?,
1091 );
8161092 // passive with implicit 0-index table or set table index manually
8171093 const flags: u32 = if (table_index == 0) 0x0 else 0x02;
8181094 try appendLeb128(gpa, binary_bytes, flags);
......@@ -841,11 +1117,13 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
8411117 if (f.data_segment_groups.items.len > 0) {
8421118 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
8431119 replaceVecSectionHeader(binary_bytes, header_offset, .data_count, @intCast(f.data_segment_groups.items.len));
1120 section_index += 1;
8441121 }
8451122
8461123 // Code section.
8471124 if (wasm.functions.count() != 0) {
8481125 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
1126 const section_offset = binary_bytes.items.len - uleb128size(@intCast(wasm.functions.count()));
8491127
8501128 for (wasm.functions.keys()) |resolution| switch (resolution.unpack(wasm)) {
8511129 .unresolved => unreachable,
......@@ -870,10 +1148,22 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
8701148 const code = ptr.code.slice(wasm);
8711149 try appendLeb128(gpa, binary_bytes, code.len);
8721150 const code_start = binary_bytes.items.len;
1151 const output_offset: u32 = @intCast(binary_bytes.items.len - section_offset);
8731152 try binary_bytes.appendSlice(gpa, code);
874 if (!is_obj) applyRelocs(binary_bytes.items[code_start..], ptr.offset, ptr.relocations(wasm), wasm);
1153 if (is_obj) {
1154 try processRelocs(
1155 wasm,
1156 &f.code_relocs,
1157 output_offset,
1158 ptr.offset,
1159 ptr.relocations(wasm),
1160 );
1161 } else {
1162 applyRelocs(binary_bytes.items[code_start..], ptr.offset, ptr.relocations(wasm), wasm);
1163 }
8751164 },
8761165 .zcu_func => |i| {
1166 const function_offset: u32 = @intCast(binary_bytes.items.len - section_offset);
8771167 const code_start = try reserveSize(gpa, binary_bytes);
8781168 defer replaceSize(binary_bytes, code_start);
8791169
......@@ -899,7 +1189,22 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
8991189 .func_tys = undefined,
9001190 .error_name_table_ref_count = undefined,
9011191 };
1192 const body_start: u32 = @intCast(binary_bytes.items.len);
1193 const relocs_start: u32 = @intCast(wasm.zcu_relocations.len);
1194 defer wasm.zcu_relocations.shrinkRetainingCapacity(relocs_start);
9021195 try mir.lower(wasm, binary_bytes);
1196 const relocs_len: u32 = @intCast(wasm.zcu_relocations.len - relocs_start);
1197 if (is_obj) {
1198 const body_len: u32 = @intCast(binary_bytes.items.len - @as(usize, body_start));
1199 const output_offset = function_offset + uleb128size(body_len);
1200 try processZcuRelocs(
1201 wasm,
1202 &f.code_relocs,
1203 output_offset,
1204 body_start,
1205 .{ .off = relocs_start, .len = relocs_len },
1206 );
1207 }
9031208 },
9041209 }
9051210 },
......@@ -921,8 +1226,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
9211226 }
9221227 }
9231228 for (wasm.nav_fixups.items) |nav_fixup| {
924 const ds_id: Wasm.DataSegmentId = .pack(wasm, .{ .nav_exe = nav_fixup.navs_exe_index });
925 const vaddr = f.data_segments.get(ds_id).? + nav_fixup.addend;
1229 const vaddr = wasm.navAddr(nav_fixup.nav_index) + nav_fixup.addend;
9261230 if (!is64) {
9271231 mem.writeInt(u32, wasm.string_bytes.items[nav_fixup.offset..][0..4], vaddr, .little);
9281232 } else {
......@@ -930,7 +1234,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
9301234 }
9311235 }
9321236 for (wasm.func_table_fixups.items) |fixup| {
933 const table_index: IndirectFunctionTableIndex = .fromZcuIndirectFunctionSetIndex(fixup.table_index);
1237 const table_index: IndirectFunctionTableIndex = .fromIpNav(wasm, fixup.nav_index);
9341238 if (!is64) {
9351239 mem.writeInt(u32, wasm.string_bytes.items[fixup.offset..][0..4], table_index.toAbi(), .little);
9361240 } else {
......@@ -942,6 +1246,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
9421246 // Data section.
9431247 if (f.data_segment_groups.items.len != 0) {
9441248 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
1249 const section_offset = binary_bytes.items.len - uleb128size(@intCast(f.data_segment_groups.items.len));
9451250
9461251 var group_index: u32 = 0;
9471252 var segment_offset: u32 = 0;
......@@ -976,7 +1281,11 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
9761281 try appendLeb128(gpa, binary_bytes, group_size);
9771282 }
9781283 if (segment_id.isEmpty(wasm)) {
979 // It counted for virtual memory but it does not go into the binary.
1284 if (is_obj) {
1285 const group_size = group_end_addr - group_start_addr;
1286 try binary_bytes.appendNTimes(gpa, 0, group_size - segment_offset);
1287 segment_offset = group_size;
1288 }
9801289 continue;
9811290 }
9821291
......@@ -986,6 +1295,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
9861295 segment_offset = needed_offset;
9871296
9881297 const code_start = binary_bytes.items.len;
1298 const output_offset: u32 = @intCast(binary_bytes.items.len - section_offset);
9891299 append: {
9901300 const code = switch (segment_id.unpack(wasm)) {
9911301 .__heap_base => {
......@@ -1001,12 +1311,19 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
10011311 break :append;
10021312 },
10031313 .__zig_error_name_table => {
1004 if (is_obj) @panic("TODO error name table reloc");
1005 const base = f.data_segments.get(.__zig_error_names).?;
1006 if (!is64) {
1007 try emitTagNameTable(gpa, binary_bytes, wasm.error_name_offs.items, wasm.error_name_bytes.items, base, u32);
1314 if (is_obj) {
1315 try emitRelocatableNameTable(
1316 wasm,
1317 binary_bytes,
1318 &f.data_relocs,
1319 output_offset,
1320 wasm.error_name_offs.items,
1321 wasm.error_name_bytes.items,
1322 .__zig_error_names,
1323 );
10081324 } else {
1009 try emitTagNameTable(gpa, binary_bytes, wasm.error_name_offs.items, wasm.error_name_bytes.items, base, u64);
1325 const base = f.data_segments.get(.__zig_error_names).?;
1326 try emitTagNameTable(wasm, binary_bytes, wasm.error_name_offs.items, wasm.error_name_bytes.items, base, is64);
10101327 }
10111328 break :append;
10121329 },
......@@ -1015,22 +1332,51 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
10151332 break :append;
10161333 },
10171334 .__zig_tag_name_table => {
1018 if (is_obj) @panic("TODO tag name table reloc");
1019 const base = f.data_segments.get(.__zig_tag_names).?;
1020 if (!is64) {
1021 try emitTagNameTable(gpa, binary_bytes, wasm.tag_name_offs.items, wasm.tag_name_bytes.items, base, u32);
1335 if (is_obj) {
1336 try emitRelocatableNameTable(
1337 wasm,
1338 binary_bytes,
1339 &f.data_relocs,
1340 output_offset,
1341 wasm.tag_name_offs.items,
1342 wasm.tag_name_bytes.items,
1343 .__zig_tag_names,
1344 );
10221345 } else {
1023 try emitTagNameTable(gpa, binary_bytes, wasm.tag_name_offs.items, wasm.tag_name_bytes.items, base, u64);
1346 const base = f.data_segments.get(.__zig_tag_names).?;
1347 try emitTagNameTable(wasm, binary_bytes, wasm.tag_name_offs.items, wasm.tag_name_bytes.items, base, is64);
10241348 }
10251349 break :append;
10261350 },
10271351 .object => |i| {
10281352 const ptr = i.ptr(wasm);
10291353 try binary_bytes.appendSlice(gpa, ptr.payload.slice(wasm));
1030 if (!is_obj) applyRelocs(binary_bytes.items[code_start..], ptr.offset, ptr.relocations(wasm), wasm);
1354 if (is_obj) {
1355 try processRelocs(
1356 wasm,
1357 &f.data_relocs,
1358 output_offset,
1359 ptr.offset,
1360 ptr.relocations(wasm),
1361 );
1362 } else {
1363 applyRelocs(binary_bytes.items[code_start..], ptr.offset, ptr.relocations(wasm), wasm);
1364 }
10311365 break :append;
10321366 },
1033 inline .uav_exe, .uav_obj, .nav_exe, .nav_obj => |i| i.value(wasm).code,
1367 inline .uav_obj, .nav_obj => |i| {
1368 const zcu_data = i.value(wasm);
1369 try binary_bytes.appendSlice(gpa, zcu_data.code.slice(wasm));
1370 try processZcuRelocs(
1371 wasm,
1372 &f.data_relocs,
1373 output_offset,
1374 zcu_data.code.off.unwrap().?,
1375 zcu_data.relocs,
1376 );
1377 break :append;
1378 },
1379 inline .uav_exe, .nav_exe => |i| i.value(wasm).code,
10341380 };
10351381 try binary_bytes.appendSlice(gpa, code.slice(wasm));
10361382 }
......@@ -1043,7 +1389,274 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
10431389 }
10441390
10451391 if (is_obj) {
1046 @panic("TODO emit link section for object file and emit modified relocations");
1392 var symbol_table_offsets: SymbolTableOffsets = undefined;
1393 {
1394 const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes);
1395 defer writeCustomSectionHeader(binary_bytes, header_offset);
1396
1397 const linking_name = "linking";
1398 try appendLeb128(gpa, binary_bytes, @as(u32, linking_name.len));
1399 try binary_bytes.appendSlice(gpa, linking_name);
1400
1401 try appendLeb128(gpa, binary_bytes, @as(u32, 2));
1402
1403 // WASM_SEGMENT_INFO
1404 {
1405 const sub_offset = try reserveCustomSectionHeader(gpa, binary_bytes);
1406 defer replaceHeader(binary_bytes, sub_offset, @backingInt(Object.SubsectionType.segment_info));
1407
1408 const total_data_segments: u32 = @intCast(f.data_segment_groups.items.len);
1409 try appendLeb128(gpa, binary_bytes, total_data_segments);
1410
1411 for (f.data_segment_groups.items) |group| {
1412 const segment = group.first_segment;
1413 const name, _ = splitSegmentName(segment.name(wasm));
1414 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
1415 try binary_bytes.appendSlice(gpa, name);
1416
1417 try appendLeb128(gpa, binary_bytes, @as(u32, segment.alignment(wasm).toLog2Units()));
1418
1419 var flags: u32 = 0;
1420 if (segment.isStrings(wasm)) flags |= 1;
1421 if (segment.isTls(wasm)) flags |= 2;
1422 if (segment.isRetain(wasm)) flags |= 4;
1423 try appendLeb128(gpa, binary_bytes, flags);
1424 }
1425 }
1426
1427 // WASM_SYMBOL_TABLE
1428 {
1429 const sub_offset = try reserveCustomSectionHeader(gpa, binary_bytes);
1430 defer replaceHeader(binary_bytes, sub_offset, @backingInt(Object.SubsectionType.symbol_table));
1431
1432 const total_symbols: u32 = @intCast(
1433 f.function_imports.entries.len + f.intrinsic_function_imports.entries.len +
1434 wasm.functions.entries.len +
1435 f.function_export_symbols.entries.len +
1436 f.data_imports.entries.len + wasm.datas.entries.len + f.data_exports.entries.len +
1437 f.global_imports.entries.len + wasm.globals.entries.len +
1438 wasm.table_imports.entries.len + wasm.tables.entries.len,
1439 );
1440 try appendLeb128(gpa, binary_bytes, total_symbols);
1441 var symbol_count: u32 = 0;
1442
1443 // SYMTAB_FUNCTION
1444 {
1445 symbol_table_offsets.function = symbol_count;
1446 for (f.function_imports.values(), 0..) |i, function_index| {
1447 try binary_bytes.append(gpa, @backingInt(Object.Symbol.Tag.function));
1448 const flags = i.flags(wasm);
1449 assert(flags.undefined);
1450 try appendLeb128(gpa, binary_bytes, flags.toAbiInteger());
1451 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(function_index)));
1452 if (flags.explicit_name) {
1453 unreachable; // never set
1454 }
1455 symbol_count += 1;
1456 }
1457 const intrinsic_flags: Wasm.SymbolFlags = .{ .undefined = true };
1458 for (f.intrinsic_function_imports.keys(), f.function_imports.entries.len..) |_, function_index| {
1459 try binary_bytes.append(gpa, @backingInt(Object.Symbol.Tag.function));
1460 try appendLeb128(gpa, binary_bytes, intrinsic_flags.toAbiInteger());
1461 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(function_index)));
1462 symbol_count += 1;
1463 }
1464 for (
1465 wasm.functions.keys(),
1466 f.function_imports.entries.len + f.intrinsic_function_imports.entries.len..,
1467 ) |resolution, function_index| {
1468 const name = resolution.name(wasm).?;
1469 const flags = resolution.flags(wasm);
1470 try binary_bytes.append(gpa, @backingInt(Object.Symbol.Tag.function));
1471 assert(!flags.undefined);
1472 try appendLeb128(gpa, binary_bytes, flags.toAbiInteger());
1473 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(function_index)));
1474 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
1475 try binary_bytes.appendSlice(gpa, name);
1476 symbol_count += 1;
1477 }
1478 for (
1479 f.function_export_symbols.keys(),
1480 f.function_export_symbols.values(),
1481 ) |name_string, symbol| {
1482 const name = name_string.slice(wasm);
1483 const function_index: Wasm.OutputFunctionIndex = .fromFunctionIndex(
1484 wasm,
1485 symbol.function_index,
1486 );
1487 try binary_bytes.append(gpa, @backingInt(Object.Symbol.Tag.function));
1488 try appendLeb128(gpa, binary_bytes, symbol.flags.toAbiInteger());
1489 try appendLeb128(gpa, binary_bytes, @backingInt(function_index));
1490 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
1491 try binary_bytes.appendSlice(gpa, name);
1492 symbol_count += 1;
1493 }
1494 }
1495
1496 // SYMTAB_DATA
1497 {
1498 symbol_table_offsets.data = symbol_count;
1499 for (f.data_imports.keys(), f.data_imports.values()) |name_string, data_index| {
1500 const name = name_string.slice(wasm);
1501 try binary_bytes.append(gpa, @backingInt(Object.Symbol.Tag.data));
1502 const flags = data_index.flags(wasm);
1503 assert(flags.undefined);
1504 try appendLeb128(gpa, binary_bytes, flags.toAbiInteger());
1505 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
1506 try binary_bytes.appendSlice(gpa, name);
1507 symbol_count += 1;
1508 }
1509 for (wasm.datas.keys()) |resolution| {
1510 var buf: [32]u8 = undefined;
1511 const name = resolution.name(wasm, &buf);
1512 try binary_bytes.append(gpa, @backingInt(Object.Symbol.Tag.data));
1513 const flags = resolution.flags(wasm);
1514 assert(!flags.undefined);
1515 try appendLeb128(gpa, binary_bytes, flags.toAbiInteger());
1516
1517 const data_loc = resolution.dataLoc(wasm);
1518 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
1519 try binary_bytes.appendSlice(gpa, name);
1520
1521 const segment_index = f.data_segments.getIndex(data_loc.segment).?;
1522 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(segment_index)));
1523 try appendLeb128(gpa, binary_bytes, data_loc.offset);
1524 try appendLeb128(gpa, binary_bytes, resolution.size(wasm));
1525 symbol_count += 1;
1526 }
1527 for (f.data_exports.keys(), f.data_exports.values()) |name_string, symbol| {
1528 const name = name_string.slice(wasm);
1529 try binary_bytes.append(gpa, @backingInt(Object.Symbol.Tag.data));
1530 try appendLeb128(gpa, binary_bytes, symbol.flags.toAbiInteger());
1531 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
1532 try binary_bytes.appendSlice(gpa, name);
1533
1534 const data_loc = symbol.resolution.dataLoc(wasm);
1535 const segment_index = f.data_segments.getIndex(data_loc.segment).?;
1536 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(segment_index)));
1537 try appendLeb128(gpa, binary_bytes, data_loc.offset);
1538 try appendLeb128(gpa, binary_bytes, symbol.resolution.size(wasm));
1539 symbol_count += 1;
1540 }
1541 }
1542
1543 // SYMTAB_GLOBAL
1544 {
1545 symbol_table_offsets.global = symbol_count;
1546 for (f.global_imports.values(), 0..) |i, global_index| {
1547 try binary_bytes.append(gpa, @backingInt(Object.Symbol.Tag.global));
1548 const flags = i.flags(wasm);
1549 assert(flags.undefined);
1550 try appendLeb128(gpa, binary_bytes, flags.toAbiInteger());
1551 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(global_index)));
1552 if (flags.explicit_name) {
1553 unreachable; // never set
1554 }
1555 symbol_count += 1;
1556 }
1557 for (wasm.globals.keys(), f.global_imports.entries.len..) |resolution, global_index| {
1558 var buf: [32]u8 = undefined;
1559 const name = resolution.name(wasm, &buf).?;
1560 try binary_bytes.append(gpa, @backingInt(Object.Symbol.Tag.global));
1561 const flags = resolution.flags(wasm);
1562 assert(!flags.undefined);
1563 try appendLeb128(gpa, binary_bytes, flags.toAbiInteger());
1564 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(global_index)));
1565 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
1566 try binary_bytes.appendSlice(gpa, name);
1567 symbol_count += 1;
1568 }
1569 }
1570
1571 // SYMTAB_EVENT
1572 {
1573 // TODO not parsed yet
1574 }
1575
1576 // SYMTAB_SECTION
1577 {
1578 // TODO not parsed correctly yet
1579 }
1580
1581 // SYMTAB_TABLE
1582 {
1583 symbol_table_offsets.table = symbol_count;
1584 for (wasm.table_imports.values(), 0..) |i, table_index| {
1585 try binary_bytes.append(gpa, @backingInt(Object.Symbol.Tag.table));
1586 const flags = i.value(wasm).flags;
1587 assert(flags.undefined);
1588 try appendLeb128(gpa, binary_bytes, flags.toAbiInteger());
1589 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(table_index)));
1590 if (flags.explicit_name) {
1591 unreachable; // never set
1592 }
1593 symbol_count += 1;
1594 }
1595 for (wasm.tables.keys(), wasm.table_imports.entries.len..) |resolution, table_index| {
1596 const name = resolution.name(wasm).?;
1597 try binary_bytes.append(gpa, @backingInt(Object.Symbol.Tag.table));
1598 const flags = resolution.flags(wasm);
1599 assert(!flags.undefined);
1600 try appendLeb128(gpa, binary_bytes, flags.toAbiInteger());
1601 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(table_index)));
1602 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
1603 try binary_bytes.appendSlice(gpa, name);
1604 symbol_count += 1;
1605 }
1606 }
1607 assert(symbol_count == total_symbols);
1608 }
1609
1610 // WASM_INIT_FUNCS
1611 {
1612 const sub_offset = try reserveCustomSectionHeader(gpa, binary_bytes);
1613 defer replaceHeader(binary_bytes, sub_offset, @backingInt(Object.SubsectionType.init_funcs));
1614
1615 const init_funcs = wasm.object_init_funcs.items;
1616 const total_functions: u32 = b: {
1617 var cnt: u32 = 0;
1618 for (init_funcs) |init_func| {
1619 const func = init_func.function_index.ptr(wasm);
1620 if (!func.object_index.ptr(wasm).is_included) continue;
1621 cnt += 1;
1622 }
1623 break :b cnt;
1624 };
1625 try appendLeb128(gpa, binary_bytes, total_functions);
1626
1627 for (init_funcs) |init_func| {
1628 const func = init_func.function_index.ptr(wasm);
1629 if (!func.object_index.ptr(wasm).is_included) continue;
1630
1631 try appendLeb128(gpa, binary_bytes, init_func.priority);
1632 const out_index: Wasm.OutputFunctionIndex = .fromObjectFunction(wasm, init_func.function_index);
1633 const symbol_index: u32 = symbol_table_offsets.function + @backingInt(out_index);
1634 try appendLeb128(gpa, binary_bytes, symbol_index);
1635 }
1636 }
1637
1638 // WASM_COMDAT_INFO
1639 {
1640 // TODO
1641 }
1642 }
1643
1644 if (f.code_relocs.items.len != 0) try emitRelocSection(
1645 wasm,
1646 binary_bytes,
1647 code_section_index.?,
1648 "reloc.CODE",
1649 f.code_relocs.items,
1650 symbol_table_offsets,
1651 );
1652 if (f.data_relocs.items.len != 0) try emitRelocSection(
1653 wasm,
1654 binary_bytes,
1655 data_section_index.?,
1656 "reloc.DATA",
1657 f.data_relocs.items,
1658 symbol_table_offsets,
1659 );
10471660 } else if (comp.config.debug_format != .strip) {
10481661 try emitNameSection(wasm, f.data_segment_groups.items, binary_bytes);
10491662 }
......@@ -1121,7 +1734,10 @@ fn emitNameSection(
11211734 const sub_offset = try reserveCustomSectionHeader(gpa, binary_bytes);
11221735 defer replaceHeader(binary_bytes, sub_offset, @backingInt(std.wasm.NameSubsection.function));
11231736
1124 const total_functions: u32 = @intCast(f.function_imports.entries.len + wasm.functions.entries.len);
1737 const total_functions: u32 = @intCast(
1738 f.function_imports.entries.len + f.intrinsic_function_imports.entries.len +
1739 wasm.functions.entries.len,
1740 );
11251741 try appendLeb128(gpa, binary_bytes, total_functions);
11261742
11271743 for (f.function_imports.keys(), 0..) |name_index, function_index| {
......@@ -1130,7 +1746,16 @@ fn emitNameSection(
11301746 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
11311747 try binary_bytes.appendSlice(gpa, name);
11321748 }
1133 for (wasm.functions.keys(), f.function_imports.entries.len..) |resolution, function_index| {
1749 for (f.intrinsic_function_imports.keys(), f.function_imports.entries.len..) |name_index, function_index| {
1750 const name = name_index.slice(wasm);
1751 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(function_index)));
1752 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
1753 try binary_bytes.appendSlice(gpa, name);
1754 }
1755 for (
1756 wasm.functions.keys(),
1757 f.function_imports.entries.len + f.intrinsic_function_imports.entries.len..,
1758 ) |resolution, function_index| {
11341759 const name = resolution.name(wasm).?;
11351760 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(function_index)));
11361761 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
......@@ -1152,7 +1777,8 @@ fn emitNameSection(
11521777 try binary_bytes.appendSlice(gpa, name);
11531778 }
11541779 for (wasm.globals.keys(), f.global_imports.entries.len..) |resolution, global_index| {
1155 const name = resolution.name(wasm).?;
1780 var buf: [32]u8 = undefined;
1781 const name = resolution.name(wasm, &buf).?;
11561782 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(global_index)));
11571783 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
11581784 try binary_bytes.appendSlice(gpa, name);
......@@ -1418,29 +2044,6 @@ pub fn emitExpr(wasm: *const Wasm, binary_bytes: *ArrayList(u8), expr: Wasm.Expr
14182044 try binary_bytes.appendSlice(gpa, slice[0 .. slice.len + 1]); // +1 to include end opcode
14192045}
14202046
1421fn emitSegmentInfo(wasm: *Wasm, binary_bytes: *std.array_list.Managed(u8)) !void {
1422 const gpa = wasm.base.comp.gpa;
1423 try appendLeb128(gpa, binary_bytes, @backingInt(Wasm.SubsectionType.segment_info));
1424 const segment_offset = binary_bytes.items.len;
1425
1426 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(wasm.segment_info.count())));
1427 for (wasm.segment_info.values()) |segment_info| {
1428 log.debug("Emit segment: {s} align({d}) flags({b})", .{
1429 segment_info.name,
1430 segment_info.alignment,
1431 segment_info.flags,
1432 });
1433 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(segment_info.name.len)));
1434 try binary_bytes.appendSlice(gpa, segment_info.name);
1435 try appendLeb128(gpa, binary_bytes, segment_info.alignment.toLog2Units());
1436 try appendLeb128(gpa, binary_bytes, segment_info.flags);
1437 }
1438
1439 var buf: [5]u8 = undefined;
1440 leb.writeUnsignedFixed(5, &buf, @as(u32, @intCast(binary_bytes.items.len - segment_offset)));
1441 try binary_bytes.insertSlice(segment_offset, &buf);
1442}
1443
14442047fn uleb128size(x: u32) u32 {
14452048 var value = x;
14462049 var size: u32 = 0;
......@@ -1449,22 +2052,395 @@ fn uleb128size(x: u32) u32 {
14492052}
14502053
14512054fn emitTagNameTable(
1452 gpa: Allocator,
2055 wasm: *const Wasm,
14532056 code: *ArrayList(u8),
14542057 tag_name_offs: []const u32,
14552058 tag_name_bytes: []const u8,
14562059 base: u32,
1457 comptime Int: type,
2060 is64: bool,
14582061) error{OutOfMemory}!void {
1459 const ptr_size_bytes = @divExact(@bitSizeOf(Int), 8);
2062 const gpa = wasm.base.comp.gpa;
2063 const ptr_size_bytes: usize = if (is64) 8 else 4;
14602064 try code.ensureUnusedCapacity(gpa, ptr_size_bytes * 2 * tag_name_offs.len);
14612065 for (tag_name_offs) |off| {
14622066 const name_len: u32 = @intCast(mem.indexOfScalar(u8, tag_name_bytes[off..], 0).?);
1463 mem.writeInt(Int, code.addManyAsArrayAssumeCapacity(ptr_size_bytes), base + off, .little);
1464 mem.writeInt(Int, code.addManyAsArrayAssumeCapacity(ptr_size_bytes), name_len, .little);
2067 if (is64) {
2068 mem.writeInt(u64, code.addManyAsArrayAssumeCapacity(8), base + off, .little);
2069 mem.writeInt(u64, code.addManyAsArrayAssumeCapacity(8), name_len, .little);
2070 } else {
2071 mem.writeInt(u32, code.addManyAsArrayAssumeCapacity(4), base + off, .little);
2072 mem.writeInt(u32, code.addManyAsArrayAssumeCapacity(4), name_len, .little);
2073 }
2074 }
2075}
2076
2077fn emitRelocatableNameTable(
2078 wasm: *const Wasm,
2079 code: *ArrayList(u8),
2080 relocs: *ArrayList(Relocation),
2081 output_offset: u32,
2082 name_offs: []const u32,
2083 name_bytes: []const u8,
2084 names_resolution: Wasm.ObjectDataImport.Resolution,
2085) error{OutOfMemory}!void {
2086 const gpa = wasm.base.comp.gpa;
2087 const ptr_size = @divExact(wasm.base.comp.root_mod.resolved_target.result.ptrBitWidth(), 8);
2088 const table_start = code.items.len;
2089 const data_index: DataSymbolIndex = .fromResolution(wasm, names_resolution);
2090 try code.ensureUnusedCapacity(gpa, @as(usize, ptr_size) * 2 * name_offs.len);
2091 try relocs.ensureUnusedCapacity(gpa, name_offs.len);
2092 for (name_offs) |off| {
2093 const name_len: u32 = @intCast(mem.indexOfScalar(u8, name_bytes[off..], 0).?);
2094 const reloc_offset = output_offset + @as(u32, @intCast(code.items.len - table_start));
2095 switch (ptr_size) {
2096 4 => {
2097 @memset(code.addManyAsArrayAssumeCapacity(4), 0);
2098 mem.writeInt(u32, code.addManyAsArrayAssumeCapacity(4), name_len, .little);
2099 },
2100 8 => {
2101 @memset(code.addManyAsArrayAssumeCapacity(8), 0);
2102 mem.writeInt(u64, code.addManyAsArrayAssumeCapacity(8), @intCast(name_len), .little);
2103 },
2104 else => unreachable,
2105 }
2106 relocs.appendAssumeCapacity(.{
2107 .tag = if (ptr_size == 4) .memory_addr_i32 else .memory_addr_i64,
2108 .offset = reloc_offset,
2109 .pointee = .{ .data = data_index },
2110 .addend = @intCast(off),
2111 });
14652112 }
14662113}
14672114
2115fn emitRelocSection(
2116 wasm: *const Wasm,
2117 binary_bytes: *ArrayList(u8),
2118 section_index: u32,
2119 reloc_name: []const u8,
2120 relocs: []const Relocation,
2121 symbol_table_offsets: SymbolTableOffsets,
2122) !void {
2123 const comp = wasm.base.comp;
2124 const gpa = comp.gpa;
2125
2126 const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes);
2127 defer writeCustomSectionHeader(binary_bytes, header_offset);
2128
2129 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(reloc_name.len)));
2130 try binary_bytes.appendSlice(gpa, reloc_name);
2131
2132 try appendLeb128(gpa, binary_bytes, section_index);
2133 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(relocs.len)));
2134
2135 for (relocs) |r| {
2136 try binary_bytes.append(gpa, @backingInt(r.tag));
2137 try appendLeb128(gpa, binary_bytes, r.offset);
2138 switch (r.tag) {
2139 .memory_addr_leb,
2140 .memory_addr_sleb,
2141 .memory_addr_i32,
2142 .memory_addr_rel_sleb,
2143 .memory_addr_leb64,
2144 .memory_addr_sleb64,
2145 .memory_addr_i64,
2146 .memory_addr_rel_sleb64,
2147 .memory_addr_tls_sleb,
2148 .memory_addr_locrel_i32,
2149 .memory_addr_tls_sleb64,
2150 => {
2151 const symbol_index: u32 = symbol_table_offsets.data + @backingInt(r.pointee.data);
2152 try appendLeb128(gpa, binary_bytes, symbol_index);
2153 },
2154 .section_offset_i32 => {
2155 @panic("TODO");
2156 },
2157 .type_index_leb => {
2158 try appendLeb128(gpa, binary_bytes, @backingInt(r.pointee.type_index));
2159 },
2160 .function_offset_i32,
2161 .function_offset_i64,
2162 .function_index_leb,
2163 .function_index_i32,
2164 .table_index_sleb,
2165 .table_index_i32,
2166 .table_index_sleb64,
2167 .table_index_i64,
2168 .table_index_rel_sleb,
2169 .table_index_rel_sleb64,
2170 => {
2171 const symbol_index: u32 = symbol_table_offsets.function + @backingInt(r.pointee.function);
2172 try appendLeb128(gpa, binary_bytes, symbol_index);
2173 },
2174 .global_index_leb, .global_index_i32 => {
2175 const symbol_index: u32 = symbol_table_offsets.global + @backingInt(r.pointee.global);
2176 try appendLeb128(gpa, binary_bytes, symbol_index);
2177 },
2178 .table_number_leb => {
2179 const symbol_index: u32 = symbol_table_offsets.table + @backingInt(r.pointee.table);
2180 try appendLeb128(gpa, binary_bytes, symbol_index);
2181 },
2182 .event_index_leb => @panic("TODO"),
2183 }
2184 switch (r.tag) {
2185 .memory_addr_leb,
2186 .memory_addr_sleb,
2187 .memory_addr_i32,
2188 .memory_addr_rel_sleb,
2189 .memory_addr_leb64,
2190 .memory_addr_sleb64,
2191 .memory_addr_i64,
2192 .memory_addr_rel_sleb64,
2193 .memory_addr_tls_sleb,
2194 .memory_addr_locrel_i32,
2195 .memory_addr_tls_sleb64,
2196 .function_offset_i32,
2197 .function_offset_i64,
2198 .section_offset_i32,
2199 => {
2200 try appendLeb128(gpa, binary_bytes, r.addend);
2201 },
2202 else => {},
2203 }
2204 }
2205}
2206
2207fn processZcuRelocs(
2208 wasm: *const Wasm,
2209 out: *ArrayList(Relocation),
2210 output_offset: u32,
2211 input_offset: u32,
2212 relocs: Wasm.ZcuRelocation.Slice,
2213) !void {
2214 const gpa = wasm.base.comp.gpa;
2215 for (
2216 relocs.tags(wasm),
2217 relocs.pointees(wasm),
2218 relocs.offsets(wasm),
2219 relocs.addends(wasm),
2220 ) |tag, pointee, offset, addend| {
2221 const output_pointee: Relocation.Pointee = switch (pointee) {
2222 .function_nav => |nav_index| .{ .function = .fromIpNav(wasm, nav_index) },
2223 .function_name => |name| .{ .function = .fromSymbolName(wasm, name) },
2224 .tag_function => |ip_index| .{ .function = .fromTagIndexType(wasm, ip_index) },
2225 .data_uav => |ip_index| .{ .data = .fromUav(wasm, ip_index) },
2226 .data_nav => |nav_index| .{ .data = .fromNav(wasm, nav_index) },
2227 .data_resolution => |resolution| .{ .data = .fromResolution(wasm, resolution) },
2228 .stack_pointer => .{ .global = .fromSymbolName(wasm, wasm.preloaded_strings.__stack_pointer) },
2229 .type_index => |type_index| .{ .type_index = .fromTypeIndex(type_index, &wasm.flush_buffer) },
2230 };
2231 try out.append(gpa, .{
2232 .tag = tag,
2233 .offset = output_offset + (offset - input_offset),
2234 .pointee = output_pointee,
2235 .addend = addend,
2236 });
2237 }
2238}
2239
2240fn processRelocs(
2241 wasm: *const Wasm,
2242 out: *ArrayList(Relocation),
2243 output_offset: u32,
2244 input_offset: u32,
2245 relocs: Wasm.ObjectRelocation.IterableSlice,
2246) !void {
2247 const gpa = wasm.base.comp.gpa;
2248 for (
2249 relocs.slice.tags(wasm),
2250 relocs.slice.pointees(wasm),
2251 relocs.slice.offsets(wasm),
2252 relocs.slice.addends(wasm),
2253 ) |tag, pointee, offset, addend| {
2254 if (offset >= relocs.end) break;
2255 const rebased_offset = output_offset + (offset - input_offset);
2256 try out.ensureUnusedCapacity(gpa, 1);
2257 switch (tag) {
2258 .function_index_i32 => out.appendAssumeCapacity(.{
2259 .tag = .function_index_i32,
2260 .offset = rebased_offset,
2261 .pointee = .{ .function = .fromObjectFunctionHandlingWeak(wasm, pointee.function) },
2262 .addend = addend,
2263 }),
2264 .function_index_leb => out.appendAssumeCapacity(.{
2265 .tag = .function_index_leb,
2266 .offset = rebased_offset,
2267 .pointee = .{ .function = .fromObjectFunctionHandlingWeak(wasm, pointee.function) },
2268 .addend = addend,
2269 }),
2270 .function_offset_i32 => @panic("TODO this value is not known yet"),
2271 .function_offset_i64 => @panic("TODO this value is not known yet"),
2272 .table_index_i32 => out.appendAssumeCapacity(.{
2273 .tag = .table_index_i32,
2274 .offset = rebased_offset,
2275 .pointee = .{ .function = .fromObjectFunctionHandlingWeak(wasm, pointee.function) },
2276 .addend = addend,
2277 }),
2278 .table_index_i64 => out.appendAssumeCapacity(.{
2279 .tag = .table_index_i64,
2280 .offset = rebased_offset,
2281 .pointee = .{ .function = .fromObjectFunctionHandlingWeak(wasm, pointee.function) },
2282 .addend = addend,
2283 }),
2284 .table_index_rel_sleb => @panic("TODO what does this reloc tag mean?"),
2285 .table_index_rel_sleb64 => @panic("TODO what does this reloc tag mean?"),
2286 .table_index_sleb => out.appendAssumeCapacity(.{
2287 .tag = .table_index_sleb,
2288 .offset = rebased_offset,
2289 .pointee = .{ .function = .fromObjectFunctionHandlingWeak(wasm, pointee.function) },
2290 .addend = addend,
2291 }),
2292 .table_index_sleb64 => out.appendAssumeCapacity(.{
2293 .tag = .table_index_sleb64,
2294 .offset = rebased_offset,
2295 .pointee = .{ .function = .fromObjectFunctionHandlingWeak(wasm, pointee.function) },
2296 .addend = addend,
2297 }),
2298
2299 .function_import_index_i32 => out.appendAssumeCapacity(.{
2300 .tag = .function_index_i32,
2301 .offset = rebased_offset,
2302 .pointee = .{ .function = .fromSymbolName(wasm, pointee.symbol_name) },
2303 .addend = addend,
2304 }),
2305 .function_import_index_leb => out.appendAssumeCapacity(.{
2306 .tag = .function_index_leb,
2307 .offset = rebased_offset,
2308 .pointee = .{ .function = .fromSymbolName(wasm, pointee.symbol_name) },
2309 .addend = addend,
2310 }),
2311 .function_import_offset_i32 => @panic("TODO this value is not known yet"),
2312 .function_import_offset_i64 => @panic("TODO this value is not known yet"),
2313 .table_import_index_i32 => out.appendAssumeCapacity(.{
2314 .tag = .table_index_i32,
2315 .offset = rebased_offset,
2316 .pointee = .{ .function = .fromSymbolName(wasm, pointee.symbol_name) },
2317 .addend = addend,
2318 }),
2319 .table_import_index_i64 => out.appendAssumeCapacity(.{
2320 .tag = .table_index_i64,
2321 .offset = rebased_offset,
2322 .pointee = .{ .function = .fromSymbolName(wasm, pointee.symbol_name) },
2323 .addend = addend,
2324 }),
2325 .table_import_index_rel_sleb => @panic("TODO what does this reloc tag mean?"),
2326 .table_import_index_rel_sleb64 => @panic("TODO what does this reloc tag mean?"),
2327 .table_import_index_sleb => out.appendAssumeCapacity(.{
2328 .tag = .table_index_sleb,
2329 .offset = rebased_offset,
2330 .pointee = .{ .function = .fromSymbolName(wasm, pointee.symbol_name) },
2331 .addend = addend,
2332 }),
2333 .table_import_index_sleb64 => out.appendAssumeCapacity(.{
2334 .tag = .table_index_sleb64,
2335 .offset = rebased_offset,
2336 .pointee = .{ .function = .fromSymbolName(wasm, pointee.symbol_name) },
2337 .addend = addend,
2338 }),
2339
2340 .global_index_i32 => out.appendAssumeCapacity(.{
2341 .tag = .global_index_i32,
2342 .offset = rebased_offset,
2343 .pointee = .{ .global = .fromObjectGlobalHandlingWeak(wasm, pointee.global) },
2344 .addend = addend,
2345 }),
2346 .global_index_leb => out.appendAssumeCapacity(.{
2347 .tag = .global_index_leb,
2348 .offset = rebased_offset,
2349 .pointee = .{ .global = .fromObjectGlobalHandlingWeak(wasm, pointee.global) },
2350 .addend = addend,
2351 }),
2352
2353 .global_import_index_i32 => out.appendAssumeCapacity(.{
2354 .tag = .global_index_i32,
2355 .offset = rebased_offset,
2356 .pointee = .{ .global = .fromSymbolName(wasm, pointee.symbol_name) },
2357 .addend = addend,
2358 }),
2359 .global_import_index_leb => out.appendAssumeCapacity(.{
2360 .tag = .global_index_leb,
2361 .offset = rebased_offset,
2362 .pointee = .{ .global = .fromSymbolName(wasm, pointee.symbol_name) },
2363 .addend = addend,
2364 }),
2365
2366 .memory_addr_i32,
2367 .memory_addr_i64,
2368 .memory_addr_leb,
2369 .memory_addr_leb64,
2370 .memory_addr_sleb,
2371 .memory_addr_sleb64,
2372 .memory_addr_tls_sleb,
2373 .memory_addr_tls_sleb64,
2374 => out.appendAssumeCapacity(.{
2375 .tag = memoryRelocationType(tag),
2376 .offset = rebased_offset,
2377 .pointee = .{ .data = .fromObjectData(wasm, pointee.data) },
2378 .addend = addend,
2379 }),
2380 .memory_addr_locrel_i32 => @panic("TODO implement relocation memory_addr_locrel_i32"),
2381 .memory_addr_rel_sleb => @panic("TODO implement relocation memory_addr_rel_sleb"),
2382 .memory_addr_rel_sleb64 => @panic("TODO implement relocation memory_addr_rel_sleb64"),
2383
2384 .memory_addr_import_i32,
2385 .memory_addr_import_i64,
2386 .memory_addr_import_leb,
2387 .memory_addr_import_leb64,
2388 .memory_addr_import_sleb,
2389 .memory_addr_import_sleb64,
2390 => out.appendAssumeCapacity(.{
2391 .tag = memoryRelocationType(tag),
2392 .offset = rebased_offset,
2393 .pointee = .{ .data = .fromSymbolName(wasm, pointee.symbol_name) },
2394 .addend = addend,
2395 }),
2396 .memory_addr_import_locrel_i32 => @panic("TODO implement relocation memory_addr_import_locrel_i32"),
2397 .memory_addr_import_rel_sleb => @panic("TODO implement relocation memory_addr_import_rel_sleb"),
2398 .memory_addr_import_rel_sleb64 => @panic("TODO implement memory_addr_import_rel_sleb64"),
2399 .memory_addr_import_tls_sleb => @panic("TODO"),
2400 .memory_addr_import_tls_sleb64 => @panic("TODO"),
2401
2402 .section_offset_i32 => @panic("TODO this value is not known yet"),
2403
2404 .table_number_leb => out.appendAssumeCapacity(.{
2405 .tag = .table_number_leb,
2406 .offset = rebased_offset,
2407 .pointee = .{ .table = .fromObjectTable(wasm, pointee.table) },
2408 .addend = addend,
2409 }),
2410 .table_import_number_leb => out.appendAssumeCapacity(.{
2411 .tag = .table_number_leb,
2412 .offset = rebased_offset,
2413 .pointee = .{ .table = .fromSymbolName(wasm, pointee.symbol_name) },
2414 .addend = addend,
2415 }),
2416
2417 .type_index_leb => out.appendAssumeCapacity(.{
2418 .tag = .type_index_leb,
2419 .offset = rebased_offset,
2420 .pointee = .{ .type_index = .fromTypeIndex(pointee.type_index, &wasm.flush_buffer) },
2421 .addend = addend,
2422 }),
2423 }
2424 }
2425}
2426
2427fn memoryRelocationType(tag: Wasm.ObjectRelocation.Tag) Object.RelocationType {
2428 return switch (tag) {
2429 .memory_addr_i32, .memory_addr_import_i32 => .memory_addr_i32,
2430 .memory_addr_i64, .memory_addr_import_i64 => .memory_addr_i64,
2431 .memory_addr_leb, .memory_addr_import_leb => .memory_addr_leb,
2432 .memory_addr_leb64, .memory_addr_import_leb64 => .memory_addr_leb64,
2433 .memory_addr_locrel_i32, .memory_addr_import_locrel_i32 => .memory_addr_locrel_i32,
2434 .memory_addr_rel_sleb, .memory_addr_import_rel_sleb => .memory_addr_rel_sleb,
2435 .memory_addr_rel_sleb64, .memory_addr_import_rel_sleb64 => .memory_addr_rel_sleb64,
2436 .memory_addr_sleb, .memory_addr_import_sleb => .memory_addr_sleb,
2437 .memory_addr_sleb64, .memory_addr_import_sleb64 => .memory_addr_sleb64,
2438 .memory_addr_tls_sleb, .memory_addr_import_tls_sleb => .memory_addr_tls_sleb,
2439 .memory_addr_tls_sleb64, .memory_addr_import_tls_sleb64 => .memory_addr_tls_sleb64,
2440 else => unreachable,
2441 };
2442}
2443
14682444fn applyRelocs(code: []u8, code_offset: u32, relocs: Wasm.ObjectRelocation.IterableSlice, wasm: *const Wasm) void {
14692445 for (
14702446 relocs.slice.tags(wasm),
......@@ -1579,12 +2555,17 @@ const RelocAddr = struct {
15792555 fn fromSymbolName(wasm: *const Wasm, name: String, addend: i32) RelocAddr {
15802556 const flush = &wasm.flush_buffer;
15812557 if (wasm.object_data_imports.getPtr(name)) |import| {
1582 return fromDataLoc(flush, import.resolution.dataLoc(wasm), addend);
1583 } else if (wasm.data_imports.get(name)) |id| {
2558 if (import.resolution != .unresolved) {
2559 return fromDataLoc(flush, import.resolution.dataLoc(wasm), addend);
2560 }
2561 }
2562 if (flush.data_exports.get(name)) |symbol| {
2563 return fromDataLoc(flush, symbol.resolution.dataLoc(wasm), addend);
2564 }
2565 if (wasm.data_imports.get(name)) |id| {
15842566 return fromDataLoc(flush, .fromDataImportId(wasm, id), addend);
1585 } else {
1586 unreachable;
15872567 }
2568 unreachable;
15882569 }
15892570
15902571 fn fromDataLoc(flush: *const Flush, data_loc: Wasm.DataLoc, addend: i32) RelocAddr {
......@@ -1702,13 +2683,11 @@ fn emitInitMemoryFunction(
17022683 }
17032684
17042685 const segment_groups = wasm.flush_buffer.data_segment_groups.items;
1705 var prev_end: u32 = 0;
17062686 for (segment_groups, 0..) |group, segment_index| {
1707 defer prev_end = group.end_addr;
17082687 const segment = group.first_segment;
17092688 if (!segment.isPassive(wasm)) continue;
17102689
1711 const start_addr: u32 = @intCast(segment.alignment(wasm).forward(prev_end));
2690 const start_addr = wasm.flush_buffer.data_segments.get(segment).?;
17122691 const segment_size: u32 = group.end_addr - start_addr;
17132692
17142693 try binary_bytes.ensureUnusedCapacity(gpa, 6 + 6 + 1 + 5 + 6 + 6 + 1 + 6 * 2 + 1 + 1);
......@@ -2028,11 +3007,15 @@ fn appendReservedUleb32(bytes: *ArrayList(u8), val: u32) void {
20283007 };
20293008}
20303009
2031fn appendGlobal(gpa: Allocator, bytes: *ArrayList(u8), mutable: u8, val: u32) Allocator.Error!void {
2032 try bytes.ensureUnusedCapacity(gpa, 9);
2033 bytes.appendAssumeCapacity(@backingInt(std.wasm.Valtype.i32));
3010fn appendGlobal(gpa: Allocator, bytes: *ArrayList(u8), mutable: u8, val: u64, is64: bool) Allocator.Error!void {
3011 try bytes.ensureUnusedCapacity(gpa, if (is64) 14 else 9);
3012 bytes.appendAssumeCapacity(@backingInt(@as(std.wasm.Valtype, if (is64) .i64 else .i32)));
20343013 bytes.appendAssumeCapacity(mutable);
2035 appendReservedI32Const(bytes, val);
3014 if (is64) {
3015 appendReservedI64Const(bytes, val);
3016 } else {
3017 appendReservedI32Const(bytes, @intCast(val));
3018 }
20363019 bytes.appendAssumeCapacity(@backingInt(std.wasm.Opcode.end));
20373020}
20383021
src/link/Wasm/Object.zig+1-1
......@@ -146,7 +146,7 @@ pub const Symbol = struct {
146146 pointee: Pointee,
147147
148148 /// https://github.com/WebAssembly/tool-conventions/blob/df8d737539eb8a8f446ba5eab9dc670c40dfb81e/Linking.md#symbol-table-subsection
149 const Tag = enum(u8) {
149 pub const Tag = enum(u8) {
150150 function,
151151 data,
152152 global,
src/target.zig+1-1
......@@ -437,7 +437,7 @@ pub fn canBuildLibCompilerRt(target: *const std.Target) enum { no, yes, llvm_onl
437437 else => {},
438438 }
439439 return switch (zigBackend(target, false)) {
440 .stage2_aarch64, .stage2_x86_64 => .yes,
440 .stage2_aarch64, .stage2_wasm, .stage2_x86_64 => .yes,
441441 else => .llvm_only,
442442 };
443443}
test/behavior/basic.zig-1
......@@ -797,7 +797,6 @@ test "auto created variables have correct alignment" {
797797}
798798
799799test "extern variable with non-pointer opaque type" {
800 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
801800 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
802801 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
803802 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
test/behavior/builtin_functions_returning_void_or_noreturn.zig-1
......@@ -6,7 +6,6 @@ var x: u8 = 1;
66
77// This excludes builtin functions that return void or noreturn that cannot be tested.
88test {
9 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1110 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1211 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/call.zig-1
......@@ -21,7 +21,6 @@ test "super basic invocations" {
2121
2222test "basic invocations" {
2323 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
24 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2524 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2625 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2726 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/export_builtin.zig-15
......@@ -5,11 +5,6 @@ const expect = std.testing.expect;
55test "exporting enum value" {
66 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
77
8 if (builtin.cpu.arch.isWasm()) {
9 // https://github.com/ziglang/zig/issues/4866
10 return error.SkipZigTest;
11 }
12
138 const S = struct {
149 const E = enum(c_int) { one, two };
1510 const e: E = .two;
......@@ -35,11 +30,6 @@ test "exporting with internal linkage" {
3530test "exporting using namespace access" {
3631 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3732
38 if (builtin.cpu.arch.isWasm()) {
39 // https://github.com/ziglang/zig/issues/4866
40 return error.SkipZigTest;
41 }
42
4333 const S = struct {
4434 const Inner = struct {
4535 const x: u32 = 5;
......@@ -57,11 +47,6 @@ test "exporting comptime-known value" {
5747 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
5848 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
5949
60 if (builtin.cpu.arch.isWasm()) {
61 // https://github.com/ziglang/zig/issues/4866
62 return error.SkipZigTest;
63 }
64
6550 const x: u32 = 10;
6651 @export(&x, .{ .name = "exporting_comptime_known_value_foo" });
6752 const S = struct {
test/behavior/fn.zig-1
......@@ -418,7 +418,6 @@ test "import passed byref to function in return type" {
418418
419419test "implicit cast function to function ptr" {
420420 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
421 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
422421 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
423422
424423 const S1 = struct {
test/tests.zig-1
......@@ -1568,7 +1568,6 @@ const module_test_targets = blk: {
15681568 .os_tag = .wasi,
15691569 .abi = .none,
15701570 },
1571 .skip_modules = &.{"compiler-rt"},
15721571 .use_llvm = false,
15731572 .use_lld = false,
15741573 },