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 {...@@ -3675,11 +3675,11 @@ pub fn saveState(comp: *Compilation) !void {
3675 addBuf(&bufs, @ptrCast(wasm.object_relocations_table.values()));3675 addBuf(&bufs, @ptrCast(wasm.object_relocations_table.values()));
3676 addBuf(&bufs, @ptrCast(wasm.object_comdat_symbols.items(.kind)));3676 addBuf(&bufs, @ptrCast(wasm.object_comdat_symbols.items(.kind)));
3677 addBuf(&bufs, @ptrCast(wasm.object_comdat_symbols.items(.index)));3677 addBuf(&bufs, @ptrCast(wasm.object_comdat_symbols.items(.index)));
3678 addBuf(&bufs, @ptrCast(wasm.out_relocs.items(.tag)));3678 addBuf(&bufs, @ptrCast(wasm.zcu_relocations.items(.tag)));
3679 addBuf(&bufs, @ptrCast(wasm.out_relocs.items(.offset)));3679 addBuf(&bufs, @ptrCast(wasm.zcu_relocations.items(.offset)));
3680 // TODO handle the union safety field3680 // TODO handle the union safety field
3681 //addBuf(&bufs, @ptrCast(wasm.out_relocs.items(.pointee)));3681 //addBuf(&bufs, @ptrCast(wasm.zcu_relocations.items(.pointee)));
3682 addBuf(&bufs, @ptrCast(wasm.out_relocs.items(.addend)));3682 addBuf(&bufs, @ptrCast(wasm.zcu_relocations.items(.addend)));
3683 addBuf(&bufs, @ptrCast(wasm.uav_fixups.items));3683 addBuf(&bufs, @ptrCast(wasm.uav_fixups.items));
3684 addBuf(&bufs, @ptrCast(wasm.nav_fixups.items));3684 addBuf(&bufs, @ptrCast(wasm.nav_fixups.items));
3685 addBuf(&bufs, @ptrCast(wasm.func_table_fixups.items));3685 addBuf(&bufs, @ptrCast(wasm.func_table_fixups.items));
src/codegen.zig+1-30
...@@ -767,11 +767,9 @@ fn lowerNavRef(...@@ -767,11 +767,9 @@ fn lowerNavRef(
767 offset: u64,767 offset: u64,
768) (Error || std.Io.Writer.Error)!void {768) (Error || std.Io.Writer.Error)!void {
769 const zcu = pt.zcu;769 const zcu = pt.zcu;
770 const gpa = zcu.gpa;
771 const ip = &zcu.intern_pool;770 const ip = &zcu.intern_pool;
772 const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result;771 const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result;
773 const ptr_width_bytes = @divExact(target.ptrBitWidth(), 8);772 const ptr_width_bytes = @divExact(target.ptrBitWidth(), 8);
774 const is_obj = lf.comp.config.output_mode == .Obj;
775 const nav_ty = Type.fromInterned(ip.getNav(nav_index).resolved.?.type);773 const nav_ty = Type.fromInterned(ip.getNav(nav_index).resolved.?.type);
776774
777 if (!nav_ty.isRuntimeFnOrHasRuntimeBits(zcu) and ip.getNav(nav_index).getExtern(ip) == null) {775 if (!nav_ty.isRuntimeFnOrHasRuntimeBits(zcu) and ip.getNav(nav_index).getExtern(ip) == null) {
...@@ -786,34 +784,7 @@ fn lowerNavRef(...@@ -786,34 +784,7 @@ fn lowerNavRef(
786 dev.check(link.File.Tag.wasm.devFeature());784 dev.check(link.File.Tag.wasm.devFeature());
787 const wasm = lf.cast(.wasm).?;785 const wasm = lf.cast(.wasm).?;
788 assert(reloc_parent == .none);786 assert(reloc_parent == .none);
789 if (nav_ty.zigTypeTag(zcu) == .@"fn") {787 try wasm.addNavReloc(w.end, nav_index, nav_ty, @intCast(offset));
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 }
817 try w.splatByteAll(0, ptr_width_bytes);788 try w.splatByteAll(0, ptr_width_bytes);
818 return;789 return;
819 },790 },
src/codegen/wasm/CodeGen.zig+4-1
...@@ -4923,7 +4923,8 @@ fn lowerPtr(cg: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerErro...@@ -4923,7 +4923,8 @@ fn lowerPtr(cg: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerErro
4923 const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr;4923 const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr;
4924 const offset: u64 = prev_offset + ptr.byte_offset;4924 const offset: u64 = prev_offset + ptr.byte_offset;
4925 return switch (ptr.base_addr) {4925 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))
4927 .{ .nav_ref = .{ .nav_index = nav, .offset = @intCast(offset) } }4928 .{ .nav_ref = .{ .nav_index = nav, .offset = @intCast(offset) } }
4928 else4929 else
4929 .{ .imm32 = @intCast(zcu.navAlignment(nav).forward(@as(u32, 0xaaaaaaaa))) },4930 .{ .imm32 = @intCast(zcu.navAlignment(nav).forward(@as(u32, 0xaaaaaaaa))) },
...@@ -5607,6 +5608,8 @@ fn bitcastClass(cg: *CodeGen, ty: Type) BitcastClass {...@@ -5607,6 +5608,8 @@ fn bitcastClass(cg: *CodeGen, ty: Type) BitcastClass {
5607}5608}
56085609
5609fn bitcast(cg: *CodeGen, dest_ty: Type, src_ty: Type, operand: WValue) InnerError!?WValue {5610fn bitcast(cg: *CodeGen, dest_ty: Type, src_ty: Type, operand: WValue) InnerError!?WValue {
5611 if (dest_ty.eql(src_ty)) return null;
5612
5610 const zcu = cg.pt.zcu;5613 const zcu = cg.pt.zcu;
5611 const src_class = cg.bitcastClass(src_ty);5614 const src_class = cg.bitcastClass(src_ty);
5612 const dest_class = cg.bitcastClass(dest_ty);5615 const dest_class = cg.bitcastClass(dest_ty);
src/codegen/wasm/Emit.zig+123-47
...@@ -21,7 +21,7 @@ pub const Error = error{...@@ -21,7 +21,7 @@ pub const Error = error{
21 OutOfMemory,21 OutOfMemory,
22};22};
2323
24pub fn lowerToCode(emit: *Emit) Error!void {24pub fn lower(emit: *Emit) Error!void {
25 const mir = &emit.mir;25 const mir = &emit.mir;
26 const code = emit.code;26 const code = emit.code;
27 const wasm = emit.wasm;27 const wasm = emit.wasm;
...@@ -31,6 +31,47 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -31,6 +31,47 @@ pub fn lowerToCode(emit: *Emit) Error!void {
31 const target = &comp.root_mod.resolved_target.result;31 const target = &comp.root_mod.resolved_target.result;
32 const is_wasm32 = target.cpu.arch == .wasm32;32 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
34 const tags = mir.instructions.items(.tag);75 const tags = mir.instructions.items(.tag);
35 const datas = mir.instructions.items(.data);76 const datas = mir.instructions.items(.data);
36 var inst: u32 = 0;77 var inst: u32 = 0;
...@@ -78,14 +119,21 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -78,14 +119,21 @@ pub fn lowerToCode(emit: *Emit) Error!void {
78 continue :loop tags[inst];119 continue :loop tags[inst];
79 },120 },
80 .func_ref => {121 .func_ref => {
81 const indirect_func_idx: Wasm.ZcuIndirectFunctionSetIndex = @fromBackingInt(@intCast(122 try code.ensureUnusedCapacity(gpa, 11);
82 wasm.zcu_indirect_function_set.getIndex(datas[inst].nav_index).?,123 const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const;
83 ));124 code.appendAssumeCapacity(@backingInt(opcode));
84 code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.i32_const));
85 if (is_obj) {125 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);
87 } else {133 } 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);
89 }137 }
90 inst += 1;138 inst += 1;
91 continue :loop tags[inst];139 continue :loop tags[inst];
...@@ -105,18 +153,17 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -105,18 +153,17 @@ pub fn lowerToCode(emit: *Emit) Error!void {
105 continue :loop tags[inst];153 continue :loop tags[inst];
106 },154 },
107 .error_name_table_ref => {155 .error_name_table_ref => {
108 wasm.error_name_table_ref_count += 1;
109 try code.ensureUnusedCapacity(gpa, 11);156 try code.ensureUnusedCapacity(gpa, 11);
110 const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const;157 const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const;
111 code.appendAssumeCapacity(@backingInt(opcode));158 code.appendAssumeCapacity(@backingInt(opcode));
112 if (is_obj) {159 if (is_obj) {
113 try wasm.out_relocs.append(gpa, .{160 try wasm.zcu_relocations.append(gpa, .{
114 .offset = @intCast(code.items.len),161 .offset = @intCast(code.items.len),
115 .pointee = .{ .symbol_index = try wasm.errorNameTableSymbolIndex() },162 .pointee = .{ .data_resolution = .__zig_error_name_table },
116 .tag = if (is_wasm32) .memory_addr_leb else .memory_addr_leb64,163 .tag = if (is_wasm32) .memory_addr_sleb else .memory_addr_sleb64,
117 .addend = 0,164 .addend = 0,
118 });165 });
119 code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10);166 appendSlebRelocPlaceholder(code, is_wasm32);
120167
121 inst += 1;168 inst += 1;
122 continue :loop tags[inst];169 continue :loop tags[inst];
...@@ -164,13 +211,13 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -164,13 +211,13 @@ pub fn lowerToCode(emit: *Emit) Error!void {
164 try code.ensureUnusedCapacity(gpa, 6);211 try code.ensureUnusedCapacity(gpa, 6);
165 code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.call));212 code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.call));
166 if (is_obj) {213 if (is_obj) {
167 try wasm.out_relocs.append(gpa, .{214 try wasm.zcu_relocations.append(gpa, .{
168 .offset = @intCast(code.items.len),215 .offset = @intCast(code.items.len),
169 .pointee = .{ .symbol_index = try wasm.navSymbolIndex(datas[inst].nav_index) },216 .pointee = .{ .function_nav = datas[inst].nav_index },
170 .tag = .function_index_leb,217 .tag = .function_index_leb,
171 .addend = 0,218 .addend = 0,
172 });219 });
173 code.appendNTimesAssumeCapacity(0, 5);220 appendUlebRelocPlaceholder(code);
174 } else {221 } else {
175 appendOutputFunctionIndex(code, .fromIpNav(wasm, datas[inst].nav_index));222 appendOutputFunctionIndex(code, .fromIpNav(wasm, datas[inst].nav_index));
176 }223 }
...@@ -191,13 +238,13 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -191,13 +238,13 @@ pub fn lowerToCode(emit: *Emit) Error!void {
191 ).?;238 ).?;
192 if (is_obj) {239 if (is_obj) {
193 code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.call_indirect));240 code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.call_indirect));
194 try wasm.out_relocs.append(gpa, .{241 try wasm.zcu_relocations.append(gpa, .{
195 .offset = @intCast(code.items.len),242 .offset = @intCast(code.items.len),
196 .pointee = .{ .type_index = func_ty_index },243 .pointee = .{ .type_index = func_ty_index },
197 .tag = .type_index_leb,244 .tag = .type_index_leb,
198 .addend = 0,245 .addend = 0,
199 });246 });
200 code.appendNTimesAssumeCapacity(0, 5);247 appendUlebRelocPlaceholder(code);
201 } else {248 } else {
202 const index: Wasm.Flush.FuncTypeIndex = @fromBackingInt(@intCast(wasm.flush_buffer.func_types.getIndex(func_ty_index) orelse {249 const index: Wasm.Flush.FuncTypeIndex = @fromBackingInt(@intCast(wasm.flush_buffer.func_types.getIndex(func_ty_index) orelse {
203 // In this case we tried to call a function pointer for250 // In this case we tried to call a function pointer for
...@@ -224,13 +271,13 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -224,13 +271,13 @@ pub fn lowerToCode(emit: *Emit) Error!void {
224 try code.ensureUnusedCapacity(gpa, 6);271 try code.ensureUnusedCapacity(gpa, 6);
225 code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.call));272 code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.call));
226 if (is_obj) {273 if (is_obj) {
227 try wasm.out_relocs.append(gpa, .{274 try wasm.zcu_relocations.append(gpa, .{
228 .offset = @intCast(code.items.len),275 .offset = @intCast(code.items.len),
229 .pointee = .{ .symbol_index = try wasm.tagTableIndexSymbolIndex(datas[inst].ip_index) },276 .pointee = .{ .tag_function = datas[inst].ip_index },
230 .tag = .function_index_leb,277 .tag = .function_index_leb,
231 .addend = 0,278 .addend = 0,
232 });279 });
233 code.appendNTimesAssumeCapacity(0, 5);280 appendUlebRelocPlaceholder(code);
234 } else {281 } else {
235 appendOutputFunctionIndex(code, .fromTagIndexType(wasm, datas[inst].ip_index));282 appendOutputFunctionIndex(code, .fromTagIndexType(wasm, datas[inst].ip_index));
236 }283 }
...@@ -244,14 +291,20 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -244,14 +291,20 @@ pub fn lowerToCode(emit: *Emit) Error!void {
244 const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const;291 const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const;
245 code.appendAssumeCapacity(@backingInt(opcode));292 code.appendAssumeCapacity(@backingInt(opcode));
246 if (is_obj) {293 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);
248 } else {301 } else {
249 const addr: u32 = wasm.tagIndexTableAddr(datas[inst].ip_index);302 const addr: u32 = wasm.tagIndexTableAddr(datas[inst].ip_index);
250 writeSleb128(code, addr);303 writeSleb128(code, addr);
251
252 inst += 1;
253 continue :loop tags[inst];
254 }304 }
305
306 inst += 1;
307 continue :loop tags[inst];
255 },308 },
256309
257 .call_intrinsic => {310 .call_intrinsic => {
...@@ -263,13 +316,13 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -263,13 +316,13 @@ pub fn lowerToCode(emit: *Emit) Error!void {
263 try code.ensureUnusedCapacity(gpa, 6);316 try code.ensureUnusedCapacity(gpa, 6);
264 code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.call));317 code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.call));
265 if (is_obj) {318 if (is_obj) {
266 try wasm.out_relocs.append(gpa, .{319 try wasm.zcu_relocations.append(gpa, .{
267 .offset = @intCast(code.items.len),320 .offset = @intCast(code.items.len),
268 .pointee = .{ .symbol_index = try wasm.symbolNameIndex(symbol_name) },321 .pointee = .{ .function_name = symbol_name },
269 .tag = .function_index_leb,322 .tag = .function_index_leb,
270 .addend = 0,323 .addend = 0,
271 });324 });
272 code.appendNTimesAssumeCapacity(0, 5);325 appendUlebRelocPlaceholder(code);
273 } else {326 } else {
274 appendOutputFunctionIndex(code, .fromSymbolName(wasm, symbol_name));327 appendOutputFunctionIndex(code, .fromSymbolName(wasm, symbol_name));
275 }328 }
...@@ -281,18 +334,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -281,18 +334,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
281 .global_set_sp => {334 .global_set_sp => {
282 try code.ensureUnusedCapacity(gpa, 6);335 try code.ensureUnusedCapacity(gpa, 6);
283 code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.global_set));336 code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.global_set));
284 if (is_obj) {337 try appendStackPointerGlobalIndex(wasm, code, 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 }
296338
297 inst += 1;339 inst += 1;
298 continue :loop tags[inst];340 continue :loop tags[inst];
...@@ -960,13 +1002,13 @@ fn uavRefObj(wasm: *Wasm, code: *ArrayList(u8), value: InternPool.Index, offset:...@@ -960,13 +1002,13 @@ fn uavRefObj(wasm: *Wasm, code: *ArrayList(u8), value: InternPool.Index, offset:
960 try code.ensureUnusedCapacity(gpa, 11);1002 try code.ensureUnusedCapacity(gpa, 11);
961 code.appendAssumeCapacity(@backingInt(opcode));1003 code.appendAssumeCapacity(@backingInt(opcode));
9621004
963 try wasm.out_relocs.append(gpa, .{1005 try wasm.zcu_relocations.append(gpa, .{
964 .offset = @intCast(code.items.len),1006 .offset = @intCast(code.items.len),
965 .pointee = .{ .symbol_index = try wasm.uavSymbolIndex(value) },1007 .pointee = .{ .data_uav = value },
966 .tag = if (is_wasm32) .memory_addr_leb else .memory_addr_leb64,1008 .tag = if (is_wasm32) .memory_addr_sleb else .memory_addr_sleb64,
967 .addend = offset,1009 .addend = offset,
968 });1010 });
969 code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10);1011 appendSlebRelocPlaceholder(code, is_wasm32);
970}1012}
9711013
972fn uavRefExe(wasm: *Wasm, code: *ArrayList(u8), value: InternPool.Index, offset: i32, is_wasm32: bool) !void {1014fn 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:...@@ -995,13 +1037,13 @@ fn navRefOff(wasm: *Wasm, code: *ArrayList(u8), data: Mir.NavRefOff, is_wasm32:
995 const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const;1037 const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const;
996 code.appendAssumeCapacity(@backingInt(opcode));1038 code.appendAssumeCapacity(@backingInt(opcode));
997 if (is_obj) {1039 if (is_obj) {
998 try wasm.out_relocs.append(gpa, .{1040 try wasm.zcu_relocations.append(gpa, .{
999 .offset = @intCast(code.items.len),1041 .offset = @intCast(code.items.len),
1000 .pointee = .{ .symbol_index = try wasm.navSymbolIndex(data.nav_index) },1042 .pointee = .{ .data_nav = data.nav_index },
1001 .tag = if (is_wasm32) .memory_addr_leb else .memory_addr_leb64,1043 .tag = if (is_wasm32) .memory_addr_sleb else .memory_addr_sleb64,
1002 .addend = data.offset,1044 .addend = data.offset,
1003 });1045 });
1004 code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10);1046 appendSlebRelocPlaceholder(code, is_wasm32);
1005 } else {1047 } else {
1006 const addr = wasm.navAddr(data.nav_index);1048 const addr = wasm.navAddr(data.nav_index);
1007 writeSleb128(code, @as(u32, @intCast(@as(i64, addr) + data.offset)));1049 writeSleb128(code, @as(u32, @intCast(@as(i64, addr) + data.offset)));
...@@ -1012,6 +1054,40 @@ fn appendOutputFunctionIndex(code: *ArrayList(u8), i: Wasm.OutputFunctionIndex)...@@ -1012,6 +1054,40 @@ fn appendOutputFunctionIndex(code: *ArrayList(u8), i: Wasm.OutputFunctionIndex)
1012 writeUleb128(code, @backingInt(i));1054 writeUleb128(code, @backingInt(i));
1013}1055}
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
1015fn writeUleb128(code: *ArrayList(u8), arg: anytype) void {1091fn writeUleb128(code: *ArrayList(u8), arg: anytype) void {
1016 var w: std.Io.Writer = .fixed(code.unusedCapacitySlice());1092 var w: std.Io.Writer = .fixed(code.unusedCapacitySlice());
1017 w.writeUleb128(arg) catch unreachable;1093 w.writeUleb128(arg) catch unreachable;
src/codegen/wasm/Mir.zig+2-50
...@@ -114,7 +114,7 @@ pub const Inst = struct {...@@ -114,7 +114,7 @@ pub const Inst = struct {
114 ///114 ///
115 /// Uses `payload` pointing to a `NavRefOff`.115 /// Uses `payload` pointing to a `NavRefOff`.
116 nav_ref_off,116 nav_ref_off,
117 /// Lowers to an i32_const which is the index of the function in the117 /// Lowers to an iNN_const which is the index of the function in the
118 /// table section.118 /// table section.
119 ///119 ///
120 /// Uses `nav_index`.120 /// Uses `nav_index`.
...@@ -679,60 +679,12 @@ pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {...@@ -679,60 +679,12 @@ pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {
679}679}
680680
681pub fn lower(mir: *const Mir, wasm: *Wasm, code: *std.ArrayList(u8)) std.mem.Allocator.Error!void {681pub 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
730 var emit: Emit = .{682 var emit: Emit = .{
731 .mir = mir.*,683 .mir = mir.*,
732 .wasm = wasm,684 .wasm = wasm,
733 .code = code,685 .code = code,
734 };686 };
735 try emit.lowerToCode();687 try emit.lower();
736}688}
737689
738pub fn extraData(self: *const Mir, comptime T: type, index: usize) struct { data: T, end: usize } {690pub 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,...@@ -133,25 +133,21 @@ object_total_sections: u32 = 0,
133/// All comdat symbols from all objects concatenated.133/// All comdat symbols from all objects concatenated.
134object_comdat_symbols: std.MultiArrayList(Comdat.Symbol) = .empty,134object_comdat_symbols: std.MultiArrayList(Comdat.Symbol) = .empty,
135135
136/// Relocations to be emitted into an object file. Remains empty when not136/// Relocations produced by Zig code and data lowering. These retain semantic
137/// emitting an object file.137/// targets until `flush`, where final output indexes are known.
138out_relocs: std.MultiArrayList(OutReloc) = .empty,138zcu_relocations: std.MultiArrayList(ZcuRelocation) = .empty,
139/// List of locations within `string_bytes` that must be patched with the virtual139/// List of locations within `string_bytes` that must be patched with the virtual
140/// memory address of a Uav during `flush`.140/// 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.
142uav_fixups: std.ArrayList(UavFixup) = .empty,142uav_fixups: std.ArrayList(UavFixup) = .empty,
143/// List of locations within `string_bytes` that must be patched with the virtual143/// List of locations within `string_bytes` that must be patched with the virtual
144/// memory address of a Nav during `flush`.144/// 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.
146/// No functions here only global variables.146/// No functions here only global variables.
147nav_fixups: std.ArrayList(NavFixup) = .empty,147nav_fixups: std.ArrayList(NavFixup) = .empty,
148/// When a nav reference is a function pointer, this tracks the required function148/// When a nav reference is a function pointer, this tracks the required function
149/// table entry index that needs to overwrite the code in the final output.149/// table entry index that needs to overwrite the code in the final output.
150func_table_fixups: std.ArrayList(FuncTableFixup) = .empty,150func_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
155/// When importing objects from the host environment, a name must be supplied.151/// When importing objects from the host environment, a name must be supplied.
156/// LLVM uses "env" by default when none is given.152/// LLVM uses "env" by default when none is given.
157/// This value is passed to object files since wasm tooling conventions provides153/// 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,...@@ -244,7 +240,9 @@ function_imports: std.array_hash_map.Auto(String, FunctionImportId) = .empty,
244/// remove elements from the table, and the remainder are either undefined240/// remove elements from the table, and the remainder are either undefined
245/// symbol errors, or symbol table entries depending on the output mode.241/// symbol errors, or symbol table entries depending on the output mode.
246data_imports: std.array_hash_map.Auto(String, DataImportId) = .empty,242data_imports: std.array_hash_map.Auto(String, DataImportId) = .empty,
247/// Set of data symbols that will appear in the final binary. Used to populate243/// 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
248/// `Flush.data_segments` before sorting.246/// `Flush.data_segments` before sorting.
249data_segments: std.array_hash_map.Auto(DataSegmentId, void) = .empty,247data_segments: std.array_hash_map.Auto(DataSegmentId, void) = .empty,
250248
...@@ -302,11 +300,6 @@ pub const TagNameOff = extern struct {...@@ -302,11 +300,6 @@ pub const TagNameOff = extern struct {
302 len: u32,300 len: u32,
303};301};
304302
305/// Index into `Wasm.zcu_indirect_function_set`.
306pub const ZcuIndirectFunctionSetIndex = enum(u32) {
307 _,
308};
309
310pub const UavFixup = extern struct {303pub const UavFixup = extern struct {
311 uavs_exe_index: UavsExeIndex,304 uavs_exe_index: UavsExeIndex,
312 /// Index into `string_bytes`.305 /// Index into `string_bytes`.
...@@ -315,14 +308,14 @@ pub const UavFixup = extern struct {...@@ -315,14 +308,14 @@ pub const UavFixup = extern struct {
315};308};
316309
317pub const NavFixup = extern struct {310pub const NavFixup = extern struct {
318 navs_exe_index: NavsExeIndex,311 nav_index: InternPool.Nav.Index,
319 /// Index into `string_bytes`.312 /// Index into `string_bytes`.
320 offset: u32,313 offset: u32,
321 addend: u32,314 addend: u32,
322};315};
323316
324pub const FuncTableFixup = extern struct {317pub const FuncTableFixup = extern struct {
325 table_index: ZcuIndirectFunctionSetIndex,318 nav_index: InternPool.Nav.Index,
326 /// Index into `string_bytes`.319 /// Index into `string_bytes`.
327 offset: u32,320 offset: u32,
328};321};
...@@ -355,7 +348,9 @@ pub const FunctionIndex = enum(u32) {...@@ -355,7 +348,9 @@ pub const FunctionIndex = enum(u32) {
355348
356 pub fn fromSymbolName(wasm: *const Wasm, name: String) ?FunctionIndex {349 pub fn fromSymbolName(wasm: *const Wasm, name: String) ?FunctionIndex {
357 if (wasm.object_function_imports.getPtr(name)) |import| {350 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 }
359 }354 }
360 if (wasm.function_exports.get(name)) |index| return index;355 if (wasm.function_exports.get(name)) |index| return index;
361 if (wasm.hidden_function_exports.get(name)) |index| return index;356 if (wasm.hidden_function_exports.get(name)) |index| return index;
...@@ -374,7 +369,8 @@ pub const GlobalExport = extern struct {...@@ -374,7 +369,8 @@ pub const GlobalExport = extern struct {
374};369};
375370
376/// 0. Index into `Flush.function_imports`371/// 0. Index into `Flush.function_imports`
377/// 1. Index into `functions`.372/// 1. Index into `Flush.intrinsic_function_imports`
373/// 2. Index into `functions`.
378///374///
379/// Note that function_imports indexes are subject to swap removals during375/// Note that function_imports indexes are subject to swap removals during
380/// `flush`.376/// `flush`.
...@@ -386,7 +382,11 @@ pub const OutputFunctionIndex = enum(u32) {...@@ -386,7 +382,11 @@ pub const OutputFunctionIndex = enum(u32) {
386 }382 }
387383
388 pub fn fromFunctionIndex(wasm: *const Wasm, index: FunctionIndex) OutputFunctionIndex {384 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 ));
390 }390 }
391391
392 pub fn fromObjectFunction(wasm: *const Wasm, index: ObjectFunctionIndex) OutputFunctionIndex {392 pub fn fromObjectFunction(wasm: *const Wasm, index: ObjectFunctionIndex) OutputFunctionIndex {
...@@ -429,6 +429,9 @@ pub const OutputFunctionIndex = enum(u32) {...@@ -429,6 +429,9 @@ pub const OutputFunctionIndex = enum(u32) {
429429
430 pub fn fromSymbolName(wasm: *const Wasm, name: String) OutputFunctionIndex {430 pub fn fromSymbolName(wasm: *const Wasm, name: String) OutputFunctionIndex {
431 if (wasm.flush_buffer.function_imports.getIndex(name)) |i| return @fromBackingInt(@intCast(i));431 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 ));
432 return fromFunctionIndex(wasm, FunctionIndex.fromSymbolName(wasm, name) orelse {435 return fromFunctionIndex(wasm, FunctionIndex.fromSymbolName(wasm, name) orelse {
433 if (std.debug.runtime_safety) {436 if (std.debug.runtime_safety) {
434 std.debug.panic("function index for symbol not found: {s}", .{name.slice(wasm)});437 std.debug.panic("function index for symbol not found: {s}", .{name.slice(wasm)});
...@@ -437,6 +440,56 @@ pub const OutputFunctionIndex = enum(u32) {...@@ -437,6 +440,56 @@ pub const OutputFunctionIndex = enum(u32) {
437 }440 }
438};441};
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
440/// Index into `Wasm.globals`.493/// Index into `Wasm.globals`.
441pub const GlobalIndex = enum(u32) {494pub const GlobalIndex = enum(u32) {
442 _,495 _,
...@@ -452,17 +505,17 @@ pub const GlobalIndex = enum(u32) {...@@ -452,17 +505,17 @@ pub const GlobalIndex = enum(u32) {
452 return .stack_pointer;505 return .stack_pointer;
453 }506 }
454507
455 pub fn ptr(index: GlobalIndex, f: *const Flush) *Wasm.GlobalImport.Resolution {508 pub fn fromResolution(wasm: *const Wasm, resolution: GlobalImport.Resolution) ?GlobalIndex {
456 return &f.globals.items[@backingInt(index)];509 const i = wasm.globals.getIndex(resolution) orelse return null;
510 return @fromBackingInt(@intCast(wasm.flush_buffer.global_imports.entries.len + i));
457 }511 }
458512
459 pub fn fromIpNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) ?GlobalIndex {513 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;514 return fromResolution(wasm, .fromIpNav(wasm, nav_index));
461 return @fromBackingInt(@intCast(i));
462 }515 }
463516
464 pub fn fromObjectGlobal(wasm: *const Wasm, i: ObjectGlobalIndex) GlobalIndex {517 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)).?;
466 }519 }
467520
468 pub fn fromObjectGlobalHandlingWeak(wasm: *const Wasm, index: ObjectGlobalIndex) GlobalIndex {521 pub fn fromObjectGlobalHandlingWeak(wasm: *const Wasm, index: ObjectGlobalIndex) GlobalIndex {
...@@ -474,8 +527,9 @@ pub const GlobalIndex = enum(u32) {...@@ -474,8 +527,9 @@ pub const GlobalIndex = enum(u32) {
474 }527 }
475528
476 pub fn fromSymbolName(wasm: *const Wasm, name: String) GlobalIndex {529 pub fn fromSymbolName(wasm: *const Wasm, name: String) GlobalIndex {
530 if (wasm.flush_buffer.global_imports.getIndex(name)) |i| return @fromBackingInt(@intCast(i));
477 const import = wasm.object_global_imports.getPtr(name).?;531 const import = wasm.object_global_imports.getPtr(name).?;
478 return @fromBackingInt(@intCast(wasm.globals.getIndex(import.resolution).?));532 return fromResolution(wasm, import.resolution).?;
479 }533 }
480};534};
481535
...@@ -483,10 +537,6 @@ pub const GlobalIndex = enum(u32) {...@@ -483,10 +537,6 @@ pub const GlobalIndex = enum(u32) {
483pub const TableIndex = enum(u32) {537pub const TableIndex = enum(u32) {
484 _,538 _,
485539
486 pub fn ptr(index: TableIndex, f: *const Flush) *Wasm.TableImport.Resolution {
487 return &f.tables.items[@backingInt(index)];
488 }
489
490 pub fn fromObjectTable(wasm: *const Wasm, i: ObjectTableIndex) TableIndex {540 pub fn fromObjectTable(wasm: *const Wasm, i: ObjectTableIndex) TableIndex {
491 return @fromBackingInt(@intCast(wasm.tables.getIndex(.fromObjectTable(i)).?));541 return @fromBackingInt(@intCast(wasm.tables.getIndex(.fromObjectTable(i)).?));
492 }542 }
...@@ -668,9 +718,10 @@ pub const SymbolFlags = packed struct(u32) {...@@ -668,9 +718,10 @@ pub const SymbolFlags = packed struct(u32) {
668 flags.ref_type = .funcref;718 flags.ref_type = .funcref;
669 }719 }
670720
671 pub fn isIncluded(flags: SymbolFlags, is_dynamic: bool) bool {721 pub fn isIncluded(flags: SymbolFlags, is_dynamic: bool, is_obj: bool) bool {
672 return flags.exported or722 return flags.exported or
673 (is_dynamic and !flags.visibility_hidden) or723 (is_dynamic and !flags.visibility_hidden) or
724 (is_obj and flags.binding != .local) or
674 (flags.no_strip and flags.must_link);725 (flags.no_strip and flags.must_link);
675 }726 }
676727
...@@ -696,8 +747,8 @@ pub const SymbolFlags = packed struct(u32) {...@@ -696,8 +747,8 @@ pub const SymbolFlags = packed struct(u32) {
696 /// Masks off the Zig-specific stuff.747 /// Masks off the Zig-specific stuff.
697 pub fn toAbiInteger(flags: SymbolFlags) u32 {748 pub fn toAbiInteger(flags: SymbolFlags) u32 {
698 var copy = flags;749 var copy = flags;
699 copy.initZigSpecific(false, false);750 copy.initZigSpecific(false, flags.no_strip);
700 return @bitCast(copy);751 return @backingInt(copy);
701 }752 }
702};753};
703754
...@@ -812,7 +863,7 @@ pub const UavsExeIndex = enum(u32) {...@@ -812,7 +863,7 @@ pub const UavsExeIndex = enum(u32) {
812/// Used when emitting a relocatable object.863/// Used when emitting a relocatable object.
813pub const ZcuDataObj = extern struct {864pub const ZcuDataObj = extern struct {
814 code: DataPayload,865 code: DataPayload,
815 relocs: OutReloc.Slice,866 relocs: ZcuRelocation.Slice,
816};867};
817868
818/// Used when not emitting a relocatable object.869/// Used when not emitting a relocatable object.
...@@ -855,7 +906,9 @@ const ZcuDataStarts = struct {...@@ -855,7 +906,9 @@ const ZcuDataStarts = struct {
855 var uavs_i = zds.uavs_i;906 var uavs_i = zds.uavs_i;
856 while (uavs_i < wasm.uavs_obj.entries.len) : (uavs_i += 1) {907 while (uavs_i < wasm.uavs_obj.entries.len) : (uavs_i += 1) {
857 // Call to `lowerZcuData` here possibly creates more entries in these tables.908 // 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;
859 }912 }
860 }913 }
861914
...@@ -906,6 +959,51 @@ pub const ZcuFunc = union {...@@ -906,6 +959,51 @@ pub const ZcuFunc = union {
906 return &wasm.zcu_funcs.values()[@backingInt(i)];959 return &wasm.zcu_funcs.values()[@backingInt(i)];
907 }960 }
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
909 pub fn name(i: @This(), wasm: *const Wasm) [:0]const u8 {1007 pub fn name(i: @This(), wasm: *const Wasm) [:0]const u8 {
910 const zcu = wasm.base.comp.zcu.?;1008 const zcu = wasm.base.comp.zcu.?;
911 const ip = &zcu.intern_pool;1009 const ip = &zcu.intern_pool;
...@@ -1034,6 +1132,15 @@ pub const FunctionImport = extern struct {...@@ -1034,6 +1132,15 @@ pub const FunctionImport = extern struct {
1034 return pack(wasm, .{ .object_function = object_function });1132 return pack(wasm, .{ .object_function = object_function });
1035 }1133 }
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
1037 pub fn isNavOrUnresolved(r: Resolution, wasm: *const Wasm) bool {1144 pub fn isNavOrUnresolved(r: Resolution, wasm: *const Wasm) bool {
1038 return switch (r.unpack(wasm)) {1145 return switch (r.unpack(wasm)) {
1039 .unresolved, .zcu_func => true,1146 .unresolved, .zcu_func => true,
...@@ -1136,6 +1243,7 @@ pub const GlobalImport = extern struct {...@@ -1136,6 +1243,7 @@ pub const GlobalImport = extern struct {
1136 __tls_base,1243 __tls_base,
1137 __tls_size,1244 __tls_size,
1138 // Next, index into `object_globals`.1245 // Next, index into `object_globals`.
1246 // Next, index into `uavs_obj` or `uavs_exe` depending on whether emitting an object.
1139 // Next, index into `navs_obj` or `navs_exe` depending on whether emitting an object.1247 // Next, index into `navs_obj` or `navs_exe` depending on whether emitting an object.
1140 _,1248 _,
11411249
...@@ -1150,6 +1258,8 @@ pub const GlobalImport = extern struct {...@@ -1150,6 +1258,8 @@ pub const GlobalImport = extern struct {
1150 __tls_base,1258 __tls_base,
1151 __tls_size,1259 __tls_size,
1152 object_global: ObjectGlobalIndex,1260 object_global: ObjectGlobalIndex,
1261 uav_exe: UavsExeIndex,
1262 uav_obj: UavsObjIndex,
1153 nav_exe: NavsExeIndex,1263 nav_exe: NavsExeIndex,
1154 nav_obj: NavsObjIndex,1264 nav_obj: NavsObjIndex,
1155 };1265 };
...@@ -1170,12 +1280,22 @@ pub const GlobalImport = extern struct {...@@ -1170,12 +1280,22 @@ pub const GlobalImport = extern struct {
1170 return .{ .object_global = @fromBackingInt(@intCast(object_global_index)) };1280 return .{ .object_global = @fromBackingInt(@intCast(object_global_index)) };
1171 const comp = wasm.base.comp;1281 const comp = wasm.base.comp;
1172 const is_obj = comp.config.output_mode == .Obj;1282 const is_obj = comp.config.output_mode == .Obj;
1173 const nav_index = object_global_index - wasm.object_globals.items.len;1283 const uav_index = object_global_index - wasm.object_globals.items.len;
1174 return if (is_obj) .{1284 if (is_obj) {
1175 .nav_obj = @fromBackingInt(@intCast(nav_index)),1285 if (uav_index < wasm.uavs_obj.entries.len) {
1176 } else .{1286 return .{ .uav_obj = @fromBackingInt(@intCast(uav_index)) };
1177 .nav_exe = @fromBackingInt(@intCast(nav_index)),1287 }
1178 };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 }
1179 },1299 },
1180 };1300 };
1181 }1301 }
...@@ -1190,11 +1310,29 @@ pub const GlobalImport = extern struct {...@@ -1190,11 +1310,29 @@ pub const GlobalImport = extern struct {
1190 .__tls_base => .__tls_base,1310 .__tls_base => .__tls_base,
1191 .__tls_size => .__tls_size,1311 .__tls_size => .__tls_size,
1192 .object_global => |i| @fromBackingInt(@intCast(first_object_global + @backingInt(i))),1312 .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))),1313 inline .uav_obj, .uav_exe => |i| @fromBackingInt(@intCast(
1194 .nav_exe => |i| @fromBackingInt(@intCast(first_object_global + wasm.object_globals.items.len + @backingInt(i))),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 )),
1195 };1324 };
1196 }1325 }
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
1198 pub fn fromIpNav(wasm: *const Wasm, ip_nav: InternPool.Nav.Index) Resolution {1336 pub fn fromIpNav(wasm: *const Wasm, ip_nav: InternPool.Nav.Index) Resolution {
1199 const comp = wasm.base.comp;1337 const comp = wasm.base.comp;
1200 const is_obj = comp.config.output_mode == .Obj;1338 const is_obj = comp.config.output_mode == .Obj;
...@@ -1209,7 +1347,22 @@ pub const GlobalImport = extern struct {...@@ -1209,7 +1347,22 @@ pub const GlobalImport = extern struct {
1209 return pack(wasm, .{ .object_global = object_global });1347 return pack(wasm, .{ .object_global = object_global });
1210 }1348 }
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 {
1213 return switch (unpack(r, wasm)) {1366 return switch (unpack(r, wasm)) {
1214 .unresolved => unreachable,1367 .unresolved => unreachable,
1215 .__heap_base => @tagName(Unpacked.__heap_base),1368 .__heap_base => @tagName(Unpacked.__heap_base),
...@@ -1219,6 +1372,11 @@ pub const GlobalImport = extern struct {...@@ -1219,6 +1372,11 @@ pub const GlobalImport = extern struct {
1219 .__tls_base => @tagName(Unpacked.__tls_base),1372 .__tls_base => @tagName(Unpacked.__tls_base),
1220 .__tls_size => @tagName(Unpacked.__tls_size),1373 .__tls_size => @tagName(Unpacked.__tls_size),
1221 .object_global => |i| i.name(wasm).slice(wasm),1374 .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,
1222 .nav_obj => |i| i.name(wasm),1380 .nav_obj => |i| i.name(wasm),
1223 .nav_exe => |i| i.name(wasm),1381 .nav_exe => |i| i.name(wasm),
1224 };1382 };
...@@ -1349,6 +1507,22 @@ pub const TableImport = extern struct {...@@ -1349,6 +1507,22 @@ pub const TableImport = extern struct {
1349 return pack(.{ .object_table = object_table });1507 return pack(.{ .object_table = object_table });
1350 }1508 }
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
1352 pub fn refType(r: Resolution, wasm: *const Wasm) std.wasm.RefType {1526 pub fn refType(r: Resolution, wasm: *const Wasm) std.wasm.RefType {
1353 return switch (unpack(r)) {1527 return switch (unpack(r)) {
1354 .unresolved => unreachable,1528 .unresolved => unreachable,
...@@ -1602,6 +1776,8 @@ pub const ObjectDataImport = extern struct {...@@ -1602,6 +1776,8 @@ pub const ObjectDataImport = extern struct {
1602 unresolved,1776 unresolved,
1603 __zig_error_names,1777 __zig_error_names,
1604 __zig_error_name_table,1778 __zig_error_name_table,
1779 __zig_tag_names,
1780 __zig_tag_name_table,
1605 __heap_base,1781 __heap_base,
1606 __heap_end,1782 __heap_end,
1607 /// Next, an `ObjectData.Index`.1783 /// Next, an `ObjectData.Index`.
...@@ -1615,6 +1791,8 @@ pub const ObjectDataImport = extern struct {...@@ -1615,6 +1791,8 @@ pub const ObjectDataImport = extern struct {
1615 unresolved,1791 unresolved,
1616 __zig_error_names,1792 __zig_error_names,
1617 __zig_error_name_table,1793 __zig_error_name_table,
1794 __zig_tag_names,
1795 __zig_tag_name_table,
1618 __heap_base,1796 __heap_base,
1619 __heap_end,1797 __heap_end,
1620 object: ObjectData.Index,1798 object: ObjectData.Index,
...@@ -1629,6 +1807,8 @@ pub const ObjectDataImport = extern struct {...@@ -1629,6 +1807,8 @@ pub const ObjectDataImport = extern struct {
1629 .unresolved => .unresolved,1807 .unresolved => .unresolved,
1630 .__zig_error_names => .__zig_error_names,1808 .__zig_error_names => .__zig_error_names,
1631 .__zig_error_name_table => .__zig_error_name_table,1809 .__zig_error_name_table => .__zig_error_name_table,
1810 .__zig_tag_names => .__zig_tag_names,
1811 .__zig_tag_name_table => .__zig_tag_name_table,
1632 .__heap_base => .__heap_base,1812 .__heap_base => .__heap_base,
1633 .__heap_end => .__heap_end,1813 .__heap_end => .__heap_end,
1634 _ => {1814 _ => {
...@@ -1665,6 +1845,8 @@ pub const ObjectDataImport = extern struct {...@@ -1665,6 +1845,8 @@ pub const ObjectDataImport = extern struct {
1665 .unresolved => .unresolved,1845 .unresolved => .unresolved,
1666 .__zig_error_names => .__zig_error_names,1846 .__zig_error_names => .__zig_error_names,
1667 .__zig_error_name_table => .__zig_error_name_table,1847 .__zig_error_name_table => .__zig_error_name_table,
1848 .__zig_tag_names => .__zig_tag_names,
1849 .__zig_tag_name_table => .__zig_tag_name_table,
1668 .__heap_base => .__heap_base,1850 .__heap_base => .__heap_base,
1669 .__heap_end => .__heap_end,1851 .__heap_end => .__heap_end,
1670 .object => |i| @fromBackingInt(@intCast(first_object + @backingInt(i))),1852 .object => |i| @fromBackingInt(@intCast(first_object + @backingInt(i))),
...@@ -1678,12 +1860,32 @@ pub const ObjectDataImport = extern struct {...@@ -1678,12 +1860,32 @@ pub const ObjectDataImport = extern struct {
1678 return pack(wasm, .{ .object = object_data_index });1860 return pack(wasm, .{ .object = object_data_index });
1679 }1861 }
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
1681 pub fn objectDataSegment(r: Resolution, wasm: *const Wasm) ?ObjectDataSegment.Index {1881 pub fn objectDataSegment(r: Resolution, wasm: *const Wasm) ?ObjectDataSegment.Index {
1682 return switch (unpack(r, wasm)) {1882 return switch (unpack(r, wasm)) {
1683 .unresolved => unreachable,1883 .unresolved => unreachable,
1684 .object => |i| i.ptr(wasm).segment,1884 .object => |i| i.ptr(wasm).segment,
1685 .__zig_error_names,1885 .__zig_error_names,
1686 .__zig_error_name_table,1886 .__zig_error_name_table,
1887 .__zig_tag_names,
1888 .__zig_tag_name_table,
1687 .__heap_base,1889 .__heap_base,
1688 .__heap_end,1890 .__heap_end,
1689 .uav_exe,1891 .uav_exe,
...@@ -1706,12 +1908,107 @@ pub const ObjectDataImport = extern struct {...@@ -1706,12 +1908,107 @@ pub const ObjectDataImport = extern struct {
1706 },1908 },
1707 .__zig_error_names => .{ .segment = .__zig_error_names, .offset = 0 },1909 .__zig_error_names => .{ .segment = .__zig_error_names, .offset = 0 },
1708 .__zig_error_name_table => .{ .segment = .__zig_error_name_table, .offset = 0 },1910 .__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 },
1709 .__heap_base => .{ .segment = .__heap_base, .offset = 0 },1913 .__heap_base => .{ .segment = .__heap_base, .offset = 0 },
1710 .__heap_end => .{ .segment = .__heap_end, .offset = 0 },1914 .__heap_end => .{ .segment = .__heap_end, .offset = 0 },
1711 .uav_exe => @panic("TODO"),1915 .uav_exe => |i| .{ .segment = .pack(wasm, .{ .uav_exe = i }), .offset = 0 },
1712 .uav_obj => @panic("TODO"),1916 .uav_obj => |i| .{ .segment = .pack(wasm, .{ .uav_obj = i }), .offset = 0 },
1713 .nav_exe => @panic("TODO"),1917 .nav_exe => |i| .{ .segment = .pack(wasm, .{ .nav_exe = i }), .offset = 0 },
1714 .nav_obj => @panic("TODO"),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,
1715 };2012 };
1716 }2013 }
1717 };2014 };
...@@ -1910,6 +2207,38 @@ pub const DataSegmentId = enum(u32) {...@@ -1910,6 +2207,38 @@ pub const DataSegmentId = enum(u32) {
1910 };2207 };
1911 }2208 }
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
1913 pub fn isBss(id: DataSegmentId, wasm: *const Wasm) bool {2242 pub fn isBss(id: DataSegmentId, wasm: *const Wasm) bool {
1914 return id.category(wasm) == .zero;2243 return id.category(wasm) == .zero;
1915 }2244 }
...@@ -2181,6 +2510,7 @@ const PreloadedStrings = struct {...@@ -2181,6 +2510,7 @@ const PreloadedStrings = struct {
2181 _initialize: String,2510 _initialize: String,
2182 _start: String,2511 _start: String,
2183 memory: String,2512 memory: String,
2513 env: String,
2184};2514};
21852515
2186/// Index into string_bytes2516/// Index into string_bytes
...@@ -2262,6 +2592,34 @@ pub const ZcuImportIndex = enum(u32) {...@@ -2262,6 +2592,34 @@ pub const ZcuImportIndex = enum(u32) {
2262 return &wasm.imports.keys()[@backingInt(index)];2592 return &wasm.imports.keys()[@backingInt(index)];
2263 }2593 }
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
2265 pub fn importName(index: ZcuImportIndex, wasm: *const Wasm) String {2623 pub fn importName(index: ZcuImportIndex, wasm: *const Wasm) String {
2266 const zcu = wasm.base.comp.zcu.?;2624 const zcu = wasm.base.comp.zcu.?;
2267 const ip = &zcu.intern_pool;2625 const ip = &zcu.intern_pool;
...@@ -2348,6 +2706,13 @@ pub const FunctionImportId = enum(u32) {...@@ -2348,6 +2706,13 @@ pub const FunctionImportId = enum(u32) {
2348 }2706 }
2349 }2707 }
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
2351 pub fn importName(id: FunctionImportId, wasm: *const Wasm) String {2716 pub fn importName(id: FunctionImportId, wasm: *const Wasm) String {
2352 return switch (unpack(id, wasm)) {2717 return switch (unpack(id, wasm)) {
2353 inline .object_function_import, .zcu_import => |i| i.importName(wasm),2718 inline .object_function_import, .zcu_import => |i| i.importName(wasm),
...@@ -2385,38 +2750,61 @@ pub const FunctionImportId = enum(u32) {...@@ -2385,38 +2750,61 @@ pub const FunctionImportId = enum(u32) {
2385 }2750 }
2386};2751};
23872752
2388/// 0. Index into `object_global_imports`.2753/// 0. `__stack_pointer`.
2389/// 1. Index into `imports`.2754/// 1. Index into `object_global_imports`.
2755/// 2. Index into `imports`.
2390pub const GlobalImportId = enum(u32) {2756pub const GlobalImportId = enum(u32) {
2757 __stack_pointer,
2391 _,2758 _,
23922759
2393 pub const Unpacked = union(enum) {2760 pub const Unpacked = union(enum) {
2761 __stack_pointer,
2394 object_global_import: GlobalImport.Index,2762 object_global_import: GlobalImport.Index,
2395 zcu_import: ZcuImportIndex,2763 zcu_import: ZcuImportIndex,
2396 };2764 };
23972765
2398 pub fn pack(unpacked: Unpacked, wasm: *const Wasm) GlobalImportId {2766 pub fn pack(unpacked: Unpacked, wasm: *const Wasm) GlobalImportId {
2399 return switch (unpacked) {2767 return switch (unpacked) {
2400 .object_global_import => |i| @fromBackingInt(@intCast(@backingInt(i))),2768 .__stack_pointer => .__stack_pointer,
2401 .zcu_import => |i| @fromBackingInt(@intCast(@backingInt(i) + wasm.object_global_imports.entries.len)),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)),
2402 };2771 };
2403 }2772 }
24042773
2405 pub fn unpack(id: GlobalImportId, wasm: *const Wasm) Unpacked {2774 pub fn unpack(id: GlobalImportId, wasm: *const Wasm) Unpacked {
2406 const i = @backingInt(id);2775 return switch (id) {
2407 if (i < wasm.object_global_imports.entries.len) return .{ .object_global_import = @fromBackingInt(@intCast(i)) };2776 .__stack_pointer => .__stack_pointer,
2408 const zcu_import_i = i - wasm.object_global_imports.entries.len;2777 _ => {
2409 return .{ .zcu_import = @fromBackingInt(@intCast(zcu_import_i)) };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 };
2410 }2786 }
24112787
2412 pub fn fromObject(object_global_import: GlobalImport.Index, wasm: *const Wasm) GlobalImportId {2788 pub fn fromObject(object_global_import: GlobalImport.Index, wasm: *const Wasm) GlobalImportId {
2413 return pack(.{ .object_global_import = object_global_import }, wasm);2789 return pack(.{ .object_global_import = object_global_import }, wasm);
2414 }2790 }
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
2416 /// This function is allowed O(N) lookup because it is only called during2803 /// This function is allowed O(N) lookup because it is only called during
2417 /// diagnostic generation.2804 /// diagnostic generation.
2418 pub fn sourceLocation(id: GlobalImportId, wasm: *const Wasm) SourceLocation {2805 pub fn sourceLocation(id: GlobalImportId, wasm: *const Wasm) SourceLocation {
2419 switch (id.unpack(wasm)) {2806 switch (id.unpack(wasm)) {
2807 .__stack_pointer => return .zig_object_nofile,
2420 .object_global_import => |obj_global_index| {2808 .object_global_import => |obj_global_index| {
2421 // TODO binary search2809 // TODO binary search
2422 for (wasm.objects.items, 0..) |o, i| {2810 for (wasm.objects.items, 0..) |o, i| {
...@@ -2433,18 +2821,28 @@ pub const GlobalImportId = enum(u32) {...@@ -2433,18 +2821,28 @@ pub const GlobalImportId = enum(u32) {
24332821
2434 pub fn importName(id: GlobalImportId, wasm: *const Wasm) String {2822 pub fn importName(id: GlobalImportId, wasm: *const Wasm) String {
2435 return switch (unpack(id, wasm)) {2823 return switch (unpack(id, wasm)) {
2824 .__stack_pointer => wasm.preloaded_strings.__stack_pointer,
2436 inline .object_global_import, .zcu_import => |i| i.importName(wasm),2825 inline .object_global_import, .zcu_import => |i| i.importName(wasm),
2437 };2826 };
2438 }2827 }
24392828
2440 pub fn moduleName(id: GlobalImportId, wasm: *const Wasm) OptionalString {2829 pub fn moduleName(id: GlobalImportId, wasm: *const Wasm) OptionalString {
2441 return switch (unpack(id, wasm)) {2830 return switch (unpack(id, wasm)) {
2831 .__stack_pointer => wasm.preloaded_strings.env.toOptional(),
2442 inline .object_global_import, .zcu_import => |i| i.moduleName(wasm),2832 inline .object_global_import, .zcu_import => |i| i.moduleName(wasm),
2443 };2833 };
2444 }2834 }
24452835
2446 pub fn globalType(id: GlobalImportId, wasm: *Wasm) ObjectGlobal.Type {2836 pub fn globalType(id: GlobalImportId, wasm: *Wasm) ObjectGlobal.Type {
2447 return switch (unpack(id, wasm)) {2837 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 },
2448 inline .object_global_import, .zcu_import => |i| i.globalType(wasm),2846 inline .object_global_import, .zcu_import => |i| i.globalType(wasm),
2449 };2847 };
2450 }2848 }
...@@ -2482,6 +2880,13 @@ pub const DataImportId = enum(u32) {...@@ -2482,6 +2880,13 @@ pub const DataImportId = enum(u32) {
2482 return pack(.{ .object_data_import = object_data_import }, wasm);2880 return pack(.{ .object_data_import = object_data_import }, wasm);
2483 }2881 }
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
2485 pub fn sourceLocation(id: DataImportId, wasm: *const Wasm) SourceLocation {2890 pub fn sourceLocation(id: DataImportId, wasm: *const Wasm) SourceLocation {
2486 switch (id.unpack(wasm)) {2891 switch (id.unpack(wasm)) {
2487 .object_data_import => |obj_data_index| {2892 .object_data_import => |obj_data_index| {
...@@ -2499,33 +2904,42 @@ pub const DataImportId = enum(u32) {...@@ -2499,33 +2904,42 @@ pub const DataImportId = enum(u32) {
2499 }2904 }
2500};2905};
25012906
2502/// Index into `Wasm.symbol_table`.2907pub const ZcuRelocation = struct {
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 {
2512 tag: Object.RelocationType,2908 tag: Object.RelocationType,
2513 offset: u32,2909 offset: u32,
2514 pointee: Pointee,2910 pointee: Pointee,
2515 addend: i32,2911 addend: i32,
25162912
2517 pub const Pointee = union {2913 pub const Pointee = union(enum) {
2518 symbol_index: SymbolTableIndex,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,
2519 type_index: FunctionType.Index,2921 type_index: FunctionType.Index,
2520 };2922 };
25212923
2522 pub const Slice = extern struct {2924 pub const Slice = extern struct {
2523 /// Index into `out_relocs`.2925 /// Index into `zcu_relocations`.
2524 off: u32,2926 off: u32,
2525 len: u32,2927 len: u32,
25262928
2527 pub fn slice(s: Slice, wasm: *const Wasm) []OutReloc {2929 pub fn tags(s: Slice, wasm: *const Wasm) []const Object.RelocationType {
2528 return wasm.relocations.items[s.off..][0..s.len];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];
2529 }2943 }
2530 };2944 };
2531};2945};
...@@ -3137,9 +3551,9 @@ pub fn deinit(wasm: *Wasm) void {...@@ -3137,9 +3551,9 @@ pub fn deinit(wasm: *Wasm) void {
3137 wasm.table_imports.deinit(gpa);3551 wasm.table_imports.deinit(gpa);
3138 wasm.tables.deinit(gpa);3552 wasm.tables.deinit(gpa);
3139 wasm.data_imports.deinit(gpa);3553 wasm.data_imports.deinit(gpa);
3554 wasm.datas.deinit(gpa);
3140 wasm.data_segments.deinit(gpa);3555 wasm.data_segments.deinit(gpa);
3141 wasm.symbol_table.deinit(gpa);3556 wasm.zcu_relocations.deinit(gpa);
3142 wasm.out_relocs.deinit(gpa);
3143 wasm.uav_fixups.deinit(gpa);3557 wasm.uav_fixups.deinit(gpa);
3144 wasm.nav_fixups.deinit(gpa);3558 wasm.nav_fixups.deinit(gpa);
3145 wasm.func_table_fixups.deinit(gpa);3559 wasm.func_table_fixups.deinit(gpa);
...@@ -3351,6 +3765,25 @@ pub fn updateExports(...@@ -3351,6 +3765,25 @@ pub fn updateExports(
3351 const zcu = pt.zcu;3765 const zcu = pt.zcu;
3352 const gpa = zcu.gpa;3766 const gpa = zcu.gpa;
3353 const ip = &zcu.intern_pool;3767 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 }
3354 for (export_indices) |export_idx| {3787 for (export_indices) |export_idx| {
3355 const exp = export_idx.ptr(zcu);3788 const exp = export_idx.ptr(zcu);
3356 const name_slice = exp.opts.name.toSlice(ip);3789 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 {...@@ -3443,7 +3876,11 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.Error!void {
3443 // Zig always depends on a stack pointer global.3876 // Zig always depends on a stack pointer global.
3444 // If emitting an object, it's an import. Otherwise, the linker synthesizes it.3877 // If emitting an object, it's an import. Otherwise, the linker synthesizes it.
3445 if (is_obj) {3878 if (is_obj) {
3446 @panic("TODO");3879 try wasm.global_imports.putNoClobber(
3880 gpa,
3881 wasm.preloaded_strings.__stack_pointer,
3882 .__stack_pointer,
3883 );
3447 } else {3884 } else {
3448 try wasm.globals.put(gpa, .__stack_pointer, {});3885 try wasm.globals.put(gpa, .__stack_pointer, {});
3449 assert(wasm.globals.entries.len - 1 == @backingInt(GlobalIndex.stack_pointer));3886 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 {...@@ -3453,7 +3890,7 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.Error!void {
3453 // These loops do both recursive marking of alive symbols well as checking for undefined symbols.3890 // These loops do both recursive marking of alive symbols well as checking for undefined symbols.
3454 // At the end, output functions and globals will be populated.3891 // At the end, output functions and globals will be populated.
3455 for (wasm.object_function_imports.keys(), wasm.object_function_imports.values(), 0..) |name, *import, i| {3892 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)) {
3457 try markFunctionImport(wasm, name, import, @fromBackingInt(@intCast(i)));3894 try markFunctionImport(wasm, name, import, @fromBackingInt(@intCast(i)));
3458 }3895 }
3459 }3896 }
...@@ -3467,7 +3904,7 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.Error!void {...@@ -3467,7 +3904,7 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.Error!void {
3467 wasm.functions_end_prelink = @intCast(wasm.functions.entries.len);3904 wasm.functions_end_prelink = @intCast(wasm.functions.entries.len);
34683905
3469 for (wasm.object_global_imports.keys(), wasm.object_global_imports.values(), 0..) |name, *import, i| {3906 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)) {
3471 try markGlobalImport(wasm, name, import, @fromBackingInt(@intCast(i)));3908 try markGlobalImport(wasm, name, import, @fromBackingInt(@intCast(i)));
3472 }3909 }
3473 }3910 }
...@@ -3475,13 +3912,13 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.Error!void {...@@ -3475,13 +3912,13 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.Error!void {
3475 wasm.global_exports_len = @intCast(wasm.global_exports.items.len);3912 wasm.global_exports_len = @intCast(wasm.global_exports.items.len);
34763913
3477 for (wasm.object_table_imports.keys(), wasm.object_table_imports.values(), 0..) |name, *import, i| {3914 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)) {
3479 try markTableImport(wasm, name, import, @fromBackingInt(@intCast(i)));3916 try markTableImport(wasm, name, import, @fromBackingInt(@intCast(i)));
3480 }3917 }
3481 }3918 }
34823919
3483 for (wasm.object_data_imports.keys(), wasm.object_data_imports.values(), 0..) |name, *import, i| {3920 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)) {
3485 try markDataImport(wasm, name, import, @fromBackingInt(@intCast(i)));3922 try markDataImport(wasm, name, import, @fromBackingInt(@intCast(i)));
3486 }3923 }
3487 }3924 }
...@@ -3512,18 +3949,23 @@ pub fn markFunctionImport(...@@ -3512,18 +3949,23 @@ pub fn markFunctionImport(
35123949
3513 const comp = wasm.base.comp;3950 const comp = wasm.base.comp;
3514 const gpa = comp.gpa;3951 const gpa = comp.gpa;
3952 const is_obj = comp.config.output_mode == .Obj;
35153953
3516 try wasm.functions.ensureUnusedCapacity(gpa, 1);3954 try wasm.functions.ensureUnusedCapacity(gpa, 1);
35173955
3518 if (import.resolution == .unresolved) {3956 if (import.resolution == .unresolved) {
3519 if (name == wasm.preloaded_strings.__wasm_init_memory) {3957 if (!is_obj) {
3520 try wasm.resolveFunctionSynthetic(import, .__wasm_init_memory, &.{}, &.{});3958 if (name == wasm.preloaded_strings.__wasm_init_memory) {
3521 } else if (name == wasm.preloaded_strings.__wasm_apply_global_tls_relocs) {3959 try wasm.resolveFunctionSynthetic(import, .__wasm_init_memory, &.{}, &.{});
3522 try wasm.resolveFunctionSynthetic(import, .__wasm_apply_global_tls_relocs, &.{}, &.{});3960 } else if (name == wasm.preloaded_strings.__wasm_apply_global_tls_relocs) {
3523 } else if (name == wasm.preloaded_strings.__wasm_call_ctors) {3961 try wasm.resolveFunctionSynthetic(import, .__wasm_apply_global_tls_relocs, &.{}, &.{});
3524 try wasm.resolveFunctionSynthetic(import, .__wasm_call_ctors, &.{}, &.{});3962 } else if (name == wasm.preloaded_strings.__wasm_call_ctors) {
3525 } else if (name == wasm.preloaded_strings.__wasm_init_tls) {3963 try wasm.resolveFunctionSynthetic(import, .__wasm_call_ctors, &.{}, &.{});
3526 try wasm.resolveFunctionSynthetic(import, .__wasm_init_tls, &.{.i32}, &.{});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 }
3527 } else {3969 } else {
3528 try wasm.function_imports.put(gpa, name, .fromObject(func_index, wasm));3970 try wasm.function_imports.put(gpa, name, .fromObject(func_index, wasm));
3529 }3971 }
...@@ -3576,28 +4018,33 @@ fn markGlobalImport(...@@ -3576,28 +4018,33 @@ fn markGlobalImport(
35764018
3577 const comp = wasm.base.comp;4019 const comp = wasm.base.comp;
3578 const gpa = comp.gpa;4020 const gpa = comp.gpa;
4021 const is_obj = comp.config.output_mode == .Obj;
35794022
3580 try wasm.globals.ensureUnusedCapacity(gpa, 1);4023 try wasm.globals.ensureUnusedCapacity(gpa, 1);
35814024
3582 if (import.resolution == .unresolved) {4025 if (import.resolution == .unresolved) {
3583 if (name == wasm.preloaded_strings.__heap_base) {4026 if (!is_obj) {
3584 import.resolution = .__heap_base;4027 if (name == wasm.preloaded_strings.__heap_base) {
3585 wasm.globals.putAssumeCapacity(.__heap_base, {});4028 import.resolution = .__heap_base;
3586 } else if (name == wasm.preloaded_strings.__heap_end) {4029 wasm.globals.putAssumeCapacity(.__heap_base, {});
3587 import.resolution = .__heap_end;4030 } else if (name == wasm.preloaded_strings.__heap_end) {
3588 wasm.globals.putAssumeCapacity(.__heap_end, {});4031 import.resolution = .__heap_end;
3589 } else if (name == wasm.preloaded_strings.__stack_pointer) {4032 wasm.globals.putAssumeCapacity(.__heap_end, {});
3590 import.resolution = .__stack_pointer;4033 } else if (name == wasm.preloaded_strings.__stack_pointer) {
3591 wasm.globals.putAssumeCapacity(.__stack_pointer, {});4034 import.resolution = .__stack_pointer;
3592 } else if (name == wasm.preloaded_strings.__tls_align) {4035 wasm.globals.putAssumeCapacity(.__stack_pointer, {});
3593 import.resolution = .__tls_align;4036 } else if (name == wasm.preloaded_strings.__tls_align) {
3594 wasm.globals.putAssumeCapacity(.__tls_align, {});4037 import.resolution = .__tls_align;
3595 } else if (name == wasm.preloaded_strings.__tls_base) {4038 wasm.globals.putAssumeCapacity(.__tls_align, {});
3596 import.resolution = .__tls_base;4039 } else if (name == wasm.preloaded_strings.__tls_base) {
3597 wasm.globals.putAssumeCapacity(.__tls_base, {});4040 import.resolution = .__tls_base;
3598 } else if (name == wasm.preloaded_strings.__tls_size) {4041 wasm.globals.putAssumeCapacity(.__tls_base, {});
3599 import.resolution = .__tls_size;4042 } else if (name == wasm.preloaded_strings.__tls_size) {
3600 wasm.globals.putAssumeCapacity(.__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 }
3601 } else {4048 } else {
3602 try wasm.global_imports.put(gpa, name, .fromObject(global_index, wasm));4049 try wasm.global_imports.put(gpa, name, .fromObject(global_index, wasm));
3603 }4050 }
...@@ -3625,7 +4072,7 @@ fn markGlobal(wasm: *Wasm, i: ObjectGlobalIndex, override_export: bool) link.Err...@@ -3625,7 +4072,7 @@ fn markGlobal(wasm: *Wasm, i: ObjectGlobalIndex, override_export: bool) link.Err
3625 try wasm.markRelocations(global.relocations(wasm));4072 try wasm.markRelocations(global.relocations(wasm));
3626}4073}
36274074
3628fn markTableImport(4075pub fn markTableImport(
3629 wasm: *Wasm,4076 wasm: *Wasm,
3630 name: String,4077 name: String,
3631 import: *TableImport,4078 import: *TableImport,
...@@ -3636,13 +4083,18 @@ fn markTableImport(...@@ -3636,13 +4083,18 @@ fn markTableImport(
36364083
3637 const comp = wasm.base.comp;4084 const comp = wasm.base.comp;
3638 const gpa = comp.gpa;4085 const gpa = comp.gpa;
4086 const is_obj = comp.config.output_mode == .Obj;
36394087
3640 try wasm.tables.ensureUnusedCapacity(gpa, 1);4088 try wasm.tables.ensureUnusedCapacity(gpa, 1);
36414089
3642 if (import.resolution == .unresolved) {4090 if (import.resolution == .unresolved) {
3643 if (name == wasm.preloaded_strings.__indirect_function_table) {4091 if (!is_obj) {
3644 import.resolution = .__indirect_function_table;4092 if (name == wasm.preloaded_strings.__indirect_function_table) {
3645 wasm.tables.putAssumeCapacity(.__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 }
3646 } else {4098 } else {
3647 try wasm.table_imports.put(gpa, name, table_index);4099 try wasm.table_imports.put(gpa, name, table_index);
3648 }4100 }
...@@ -3676,22 +4128,38 @@ pub fn markDataImport(...@@ -3676,22 +4128,38 @@ pub fn markDataImport(
36764128
3677 const comp = wasm.base.comp;4129 const comp = wasm.base.comp;
3678 const gpa = comp.gpa;4130 const gpa = comp.gpa;
4131 const is_obj = comp.config.output_mode == .Obj;
4132
4133 try wasm.data_segments.ensureUnusedCapacity(gpa, 1);
36794134
3680 if (import.resolution == .unresolved) {4135 if (import.resolution == .unresolved) {
3681 if (name == wasm.preloaded_strings.__heap_base) {4136 if (!is_obj) {
3682 import.resolution = .__heap_base;4137 if (name == wasm.preloaded_strings.__heap_base) {
3683 wasm.data_segments.putAssumeCapacity(.__heap_base, {});4138 import.resolution = .__heap_base;
3684 } else if (name == wasm.preloaded_strings.__heap_end) {4139 wasm.data_segments.putAssumeCapacity(.__heap_base, {});
3685 import.resolution = .__heap_end;4140 } else if (name == wasm.preloaded_strings.__heap_end) {
3686 wasm.data_segments.putAssumeCapacity(.__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 }
3687 } else {4146 } else {
3688 try wasm.data_imports.put(gpa, name, .fromObject(data_index, wasm));4147 try wasm.data_imports.put(gpa, name, .fromObject(data_index, wasm));
3689 }4148 }
3690 } else if (import.resolution.objectDataSegment(wasm)) |segment_index| {4149 } else switch (import.resolution.unpack(wasm)) {
3691 try markDataSegment(wasm, segment_index);4150 .object => |object_data_index| try markData(wasm, object_data_index),
4151 else => {},
3692 }4152 }
3693}4153}
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
3695fn markRelocations(wasm: *Wasm, relocs: ObjectRelocation.IterableSlice) link.Error!void {4163fn markRelocations(wasm: *Wasm, relocs: ObjectRelocation.IterableSlice) link.Error!void {
3696 const gpa = wasm.base.comp.gpa;4164 const gpa = wasm.base.comp.gpa;
3697 for (relocs.slice.tags(wasm), relocs.slice.pointees(wasm), relocs.slice.offsets(wasm)) |tag, pointee, offset| {4165 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...@@ -3782,7 +4250,7 @@ fn markRelocations(wasm: *Wasm, relocs: ObjectRelocation.IterableSlice) link.Err
3782 .memory_addr_tls_sleb,4250 .memory_addr_tls_sleb,
3783 .memory_addr_locrel_i32,4251 .memory_addr_locrel_i32,
3784 .memory_addr_tls_sleb64,4252 .memory_addr_tls_sleb64,
3785 => try markDataSegment(wasm, pointee.data.ptr(wasm).segment),4253 => try markData(wasm, pointee.data),
37864254
3787 .type_index_leb => continue,4255 .type_index_leb => continue,
3788 }4256 }
...@@ -3829,7 +4297,13 @@ pub fn flush(...@@ -3829,7 +4297,13 @@ pub fn flush(
3829 const hidden_function_exports_end_zcu: u32 = @intCast(wasm.hidden_function_exports.entries.len);4297 const hidden_function_exports_end_zcu: u32 = @intCast(wasm.hidden_function_exports.entries.len);
3830 defer wasm.hidden_function_exports.shrinkRetainingCapacity(hidden_function_exports_end_zcu);4298 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
3832 wasm.flush_buffer.clear();4303 wasm.flush_buffer.clear();
4304 wasm.tag_name_bytes.clearRetainingCapacity();
4305 wasm.tag_name_offs.clearRetainingCapacity();
4306 wasm.tag_name_table_ref_count = 0;
3833 try wasm.flush_buffer.missing_exports.reinit(gpa, wasm.missing_exports.keys(), &.{});4307 try wasm.flush_buffer.missing_exports.reinit(gpa, wasm.missing_exports.keys(), &.{});
3834 try wasm.flush_buffer.function_imports.reinit(gpa, wasm.function_imports.keys(), wasm.function_imports.values());4308 try wasm.flush_buffer.function_imports.reinit(gpa, wasm.function_imports.keys(), wasm.function_imports.values());
3835 try wasm.flush_buffer.global_imports.reinit(gpa, wasm.global_imports.keys(), wasm.global_imports.values());4309 try wasm.flush_buffer.global_imports.reinit(gpa, wasm.global_imports.keys(), wasm.global_imports.values());
...@@ -3953,6 +4427,255 @@ pub fn getExistingFunctionType(...@@ -3953,6 +4427,255 @@ pub fn getExistingFunctionType(
3953 });4427 });
3954}4428}
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
3956pub fn addExpr(wasm: *Wasm, bytes: []const u8) Allocator.Error!Expr {4679pub fn addExpr(wasm: *Wasm, bytes: []const u8) Allocator.Error!Expr {
3957 const gpa = wasm.base.comp.gpa;4680 const gpa = wasm.base.comp.gpa;
3958 // We can't use string table deduplication here since these expressions can4681 // 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...@@ -3972,64 +4695,63 @@ pub fn addRelocatableDataPayload(wasm: *Wasm, bytes: []const u8) Allocator.Error
3972 };4695 };
3973}4696}
39744697
3975pub fn uavSymbolIndex(wasm: *Wasm, ip_index: InternPool.Index) Allocator.Error!SymbolTableIndex {4698pub fn addNavReloc(
3976 const comp = wasm.base.comp;4699 wasm: *Wasm,
3977 assert(comp.config.output_mode == .Obj);4700 reloc_offset: usize,
3978 const gpa = comp.gpa;4701 nav_index: InternPool.Nav.Index,
3979 const name = try wasm.internStringFmt("__anon_{d}", .{@backingInt(ip_index)});4702 nav_ty: Zcu.Type,
3980 const gop = try wasm.symbol_table.getOrPut(gpa, name);4703 addend: u32,
3981 gop.value_ptr.* = {};4704) !void {
3982 return @fromBackingInt(@intCast(gop.index));
3983}
3984
3985pub fn navSymbolIndex(wasm: *Wasm, nav_index: InternPool.Nav.Index) Allocator.Error!SymbolTableIndex {
3986 const comp = wasm.base.comp;4705 const comp = wasm.base.comp;
3987 assert(comp.config.output_mode == .Obj);
3988 const zcu = comp.zcu.?;4706 const zcu = comp.zcu.?;
3989 const ip = &zcu.intern_pool;4707 const ip = &zcu.intern_pool;
3990 const gpa = comp.gpa;4708 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 {4710 const is_obj = comp.config.output_mode == .Obj;
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}
40254711
4026pub fn symbolNameIndex(wasm: *Wasm, name: String) Allocator.Error!SymbolTableIndex {4712 if (nav_ty.zigTypeTag(zcu) == .@"fn") {
4027 const comp = wasm.base.comp;4713 const gop = try wasm.zcu_indirect_function_set.getOrPut(gpa, nav_index);
4028 assert(comp.config.output_mode == .Obj);4714 if (!gop.found_existing) gop.value_ptr.* = {};
4029 const gpa = comp.gpa;4715 if (is_obj) {
4030 const gop = try wasm.symbol_table.getOrPut(gpa, name);4716 assert(addend == 0);
4031 gop.value_ptr.* = {};4717 try wasm.zcu_relocations.append(gpa, .{
4032 return @fromBackingInt(@intCast(gop.index));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 }
4033}4755}
40344756
4035pub fn addUavReloc(4757pub fn addUavReloc(
...@@ -4057,12 +4779,12 @@ pub fn addUavReloc(...@@ -4057,12 +4779,12 @@ pub fn addUavReloc(
4057 if (comp.config.output_mode == .Obj) {4779 if (comp.config.output_mode == .Obj) {
4058 const gop = try wasm.uavs_obj.getOrPut(gpa, uav_val);4780 const gop = try wasm.uavs_obj.getOrPut(gpa, uav_val);
4059 if (!gop.found_existing) gop.value_ptr.* = undefined; // to avoid recursion, `ZcuDataStarts` will lower the value later4781 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, .{
4061 .offset = @intCast(reloc_offset),4783 .offset = @intCast(reloc_offset),
4062 .pointee = .{ .symbol_index = try wasm.uavSymbolIndex(uav_val) },4784 .pointee = .{ .data_uav = uav_val },
4063 .tag = switch (wasm.pointerSize()) {4785 .tag = switch (wasm.pointerSize()) {
4064 32 => .memory_addr_i32,4786 4 => .memory_addr_i32,
4065 64 => .memory_addr_i64,4787 8 => .memory_addr_i64,
4066 else => unreachable,4788 else => unreachable,
4067 },4789 },
4068 .addend = @intCast(addend),4790 .addend = @intCast(addend),
...@@ -4085,7 +4807,7 @@ pub fn addUavReloc(...@@ -4085,7 +4807,7 @@ pub fn addUavReloc(
4085pub fn refNavObj(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsObjIndex {4807pub fn refNavObj(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsObjIndex {
4086 const comp = wasm.base.comp;4808 const comp = wasm.base.comp;
4087 const gpa = comp.gpa;4809 const gpa = comp.gpa;
4088 assert(comp.config.output_mode != .Obj);4810 assert(comp.config.output_mode == .Obj);
4089 const gop = try wasm.navs_obj.getOrPut(gpa, nav_index);4811 const gop = try wasm.navs_obj.getOrPut(gpa, nav_index);
4090 if (!gop.found_existing) gop.value_ptr.* = .{4812 if (!gop.found_existing) gop.value_ptr.* = .{
4091 // Lowering the value is delayed to avoid recursion.4813 // Lowering the value is delayed to avoid recursion.
...@@ -4113,7 +4835,7 @@ pub fn refNavExe(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsExeIndex {...@@ -4113,7 +4835,7 @@ pub fn refNavExe(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsExeIndex {
4113}4835}
41144836
4115/// Asserts it is called after `Flush.data_segments` is fully populated and sorted.4837/// 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 {
4117 assert(wasm.flush_buffer.memory_layout_finished);4839 assert(wasm.flush_buffer.memory_layout_finished);
4118 const comp = wasm.base.comp;4840 const comp = wasm.base.comp;
4119 assert(comp.config.output_mode != .Obj);4841 assert(comp.config.output_mode != .Obj);
...@@ -4123,7 +4845,7 @@ pub fn uavAddr(wasm: *Wasm, ip_index: InternPool.Index) u32 {...@@ -4123,7 +4845,7 @@ pub fn uavAddr(wasm: *Wasm, ip_index: InternPool.Index) u32 {
4123}4845}
41244846
4125/// Asserts it is called after `Flush.data_segments` is fully populated and sorted.4847/// 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 {
4127 assert(wasm.flush_buffer.memory_layout_finished);4849 assert(wasm.flush_buffer.memory_layout_finished);
4128 const comp = wasm.base.comp;4850 const comp = wasm.base.comp;
4129 assert(comp.config.output_mode != .Obj);4851 assert(comp.config.output_mode != .Obj);
...@@ -4139,23 +4861,34 @@ pub fn navAddr(wasm: *Wasm, nav_index: InternPool.Nav.Index) u32 {...@@ -4139,23 +4861,34 @@ pub fn navAddr(wasm: *Wasm, nav_index: InternPool.Nav.Index) u32 {
4139 .@"extern" => |ext| if (wasm.getExistingString(ext.name.toSlice(ip))) |symbol_name| {4861 .@"extern" => |ext| if (wasm.getExistingString(ext.name.toSlice(ip))) |symbol_name| {
4140 if (wasm.object_data_imports.getPtr(symbol_name)) |import| {4862 if (wasm.object_data_imports.getPtr(symbol_name)) |import| {
4141 switch (import.resolution.unpack(wasm)) {4863 switch (import.resolution.unpack(wasm)) {
4142 .unresolved => unreachable,4864 .unresolved => {},
4143 .object => |object_data_index| {4865 .object => |object_data_index| {
4144 const object_data = object_data_index.ptr(wasm);4866 const object_data = object_data_index.ptr(wasm);
4145 const ds_id: DataSegmentId = .fromObjectDataSegment(wasm, object_data.segment);4867 const ds_id: DataSegmentId = .fromObjectDataSegment(wasm, object_data.segment);
4146 const segment_base_addr = wasm.flush_buffer.data_segments.get(ds_id).?;4868 const segment_base_addr = wasm.flush_buffer.data_segments.get(ds_id).?;
4147 return segment_base_addr + object_data.offset;4869 return segment_base_addr + object_data.offset;
4148 },4870 },
4149 .__zig_error_names => @panic("TODO"),4871 .__heap_base,
4150 .__zig_error_name_table => @panic("TODO"),4872 .__heap_end,
4151 .__heap_base => @panic("TODO"),4873 .uav_exe,
4152 .__heap_end => @panic("TODO"),4874 .nav_exe,
4153 .uav_exe => @panic("TODO"),4875 => {
4154 .uav_obj => @panic("TODO"),4876 const data_loc = import.resolution.dataLoc(wasm);
4155 .nav_exe => @panic("TODO"),4877 return wasm.flush_buffer.data_segments.get(data_loc.segment).? + data_loc.offset;
4156 .nav_obj => @panic("TODO"),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,
4157 }4886 }
4158 }4887 }
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 }
4159 },4892 },
4160 else => {},4893 else => {},
4161 }4894 }
...@@ -4177,8 +4910,12 @@ pub fn tagIndexTableAddr(wasm: *Wasm, ip_index: InternPool.Index) u32 {...@@ -4177,8 +4910,12 @@ pub fn tagIndexTableAddr(wasm: *Wasm, ip_index: InternPool.Index) u32 {
4177 assert(comp.config.output_mode != .Obj);4910 assert(comp.config.output_mode != .Obj);
4178 const f = &wasm.flush_buffer;4911 const f = &wasm.flush_buffer;
4179 const table_base_addr = f.data_segments.get(.__zig_tag_name_table).?;4912 const table_base_addr = f.data_segments.get(.__zig_tag_name_table).?;
4180 const table_index = f.enum_tag_name_table.get(ip_index).?;4913 return table_base_addr + wasm.tagIndexTableOffset(ip_index);
4181 return table_base_addr + table_index * 8;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;
4182}4919}
41834920
4184fn convertZcuFnType(4921fn convertZcuFnType(
...@@ -4255,7 +4992,7 @@ pub fn isBss(wasm: *const Wasm, optional_name: OptionalString) bool {...@@ -4255,7 +4992,7 @@ pub fn isBss(wasm: *const Wasm, optional_name: OptionalString) bool {
4255/// those entries.4992/// those entries.
4256fn lowerZcuData(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !ZcuDataObj {4993fn lowerZcuData(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !ZcuDataObj {
4257 const code_start: u32 = @intCast(wasm.string_bytes.items.len);4994 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);
4259 const uav_fixups_start: u32 = @intCast(wasm.uav_fixups.items.len);4996 const uav_fixups_start: u32 = @intCast(wasm.uav_fixups.items.len);
4260 const nav_fixups_start: u32 = @intCast(wasm.nav_fixups.items.len);4997 const nav_fixups_start: u32 = @intCast(wasm.nav_fixups.items.len);
4261 const func_table_fixups_start: u32 = @intCast(wasm.func_table_fixups.items.len);4998 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...@@ -4271,8 +5008,9 @@ fn lowerZcuData(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !Zcu
4271 }5008 }
42725009
4273 const code_len: u32 = @intCast(wasm.string_bytes.items.len - code_start);5010 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);
4275 const any_fixups =5012 const any_fixups =
5013 relocs_len != 0 or
4276 uav_fixups_start != wasm.uav_fixups.items.len or5014 uav_fixups_start != wasm.uav_fixups.items.len or
4277 nav_fixups_start != wasm.nav_fixups.items.len or5015 nav_fixups_start != wasm.nav_fixups.items.len or
4278 func_table_fixups_start != wasm.func_table_fixups.items.len;5016 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");...@@ -7,7 +7,6 @@ const Object = @import("Object.zig");
7const Zcu = @import("../../Zcu.zig");7const Zcu = @import("../../Zcu.zig");
8const Alignment = Wasm.Alignment;8const Alignment = Wasm.Alignment;
9const String = Wasm.String;9const String = Wasm.String;
10const Relocation = Wasm.Relocation;
11const InternPool = @import("../../InternPool.zig");10const InternPool = @import("../../InternPool.zig");
12const Mir = @import("../../codegen/wasm/Mir.zig");11const Mir = @import("../../codegen/wasm/Mir.zig");
1312
...@@ -33,8 +32,13 @@ data_segment_groups: ArrayList(DataSegmentGroup) = .empty,...@@ -33,8 +32,13 @@ data_segment_groups: ArrayList(DataSegmentGroup) = .empty,
33binary_bytes: ArrayList(u8) = .empty,32binary_bytes: ArrayList(u8) = .empty,
34missing_exports: std.array_hash_map.Auto(String, void) = .empty,33missing_exports: std.array_hash_map.Auto(String, void) = .empty,
35function_imports: std.array_hash_map.Auto(String, Wasm.FunctionImportId) = .empty,34function_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,
36global_imports: std.array_hash_map.Auto(String, Wasm.GlobalImportId) = .empty,38global_imports: std.array_hash_map.Auto(String, Wasm.GlobalImportId) = .empty,
37data_imports: std.array_hash_map.Auto(String, Wasm.DataImportId) = .empty,39data_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
39indirect_function_table: std.array_hash_map.Auto(Wasm.OutputFunctionIndex, void) = .empty,43indirect_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,...@@ -43,6 +47,9 @@ func_types: std.array_hash_map.Auto(Wasm.FunctionType.Index, void) = .empty,
4347
44enum_tag_name_table: std.array_hash_map.Auto(InternPool.Index, u32) = .empty,48enum_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
46/// For debug purposes only.53/// For debug purposes only.
47memory_layout_finished: bool = false,54memory_layout_finished: bool = false,
4855
...@@ -55,6 +62,74 @@ pub const FuncTypeIndex = enum(u32) {...@@ -55,6 +62,74 @@ pub const FuncTypeIndex = enum(u32) {
55 }62 }
56};63};
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
58/// Index into `indirect_function_table`.133/// Index into `indirect_function_table`.
59const IndirectFunctionTableIndex = enum(u32) {134const IndirectFunctionTableIndex = enum(u32) {
60 _,135 _,
...@@ -71,9 +146,8 @@ const IndirectFunctionTableIndex = enum(u32) {...@@ -71,9 +146,8 @@ const IndirectFunctionTableIndex = enum(u32) {
71 return @fromBackingInt(@intCast(f.indirect_function_table.getIndex(i).?));146 return @fromBackingInt(@intCast(f.indirect_function_table.getIndex(i).?));
72 }147 }
73148
74 fn fromZcuIndirectFunctionSetIndex(i: Wasm.ZcuIndirectFunctionSetIndex) IndirectFunctionTableIndex {149 fn fromIpNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) IndirectFunctionTableIndex {
75 // These are the same since those are added to the table first.150 return fromOutputFunctionIndex(&wasm.flush_buffer, .fromIpNav(wasm, nav_index));
76 return @fromBackingInt(@intCast(@backingInt(i)));
77 }151 }
78152
79 fn toAbi(i: IndirectFunctionTableIndex) u32 {153 fn toAbi(i: IndirectFunctionTableIndex) u32 {
...@@ -81,6 +155,39 @@ const IndirectFunctionTableIndex = enum(u32) {...@@ -81,6 +155,39 @@ const IndirectFunctionTableIndex = enum(u32) {
81 }155 }
82};156};
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
84const DataSegmentGroup = struct {191const DataSegmentGroup = struct {
85 first_segment: Wasm.DataSegmentId,192 first_segment: Wasm.DataSegmentId,
86 end_addr: u32,193 end_addr: u32,
...@@ -90,9 +197,14 @@ pub fn clear(f: *Flush) void {...@@ -90,9 +197,14 @@ pub fn clear(f: *Flush) void {
90 f.data_segments.clearRetainingCapacity();197 f.data_segments.clearRetainingCapacity();
91 f.data_segment_groups.clearRetainingCapacity();198 f.data_segment_groups.clearRetainingCapacity();
92 f.binary_bytes.clearRetainingCapacity();199 f.binary_bytes.clearRetainingCapacity();
200 f.intrinsic_function_imports.clearRetainingCapacity();
201 f.function_export_symbols.clearRetainingCapacity();
202 f.data_exports.clearRetainingCapacity();
93 f.indirect_function_table.clearRetainingCapacity();203 f.indirect_function_table.clearRetainingCapacity();
94 f.func_types.clearRetainingCapacity();204 f.func_types.clearRetainingCapacity();
95 f.enum_tag_name_table.clearRetainingCapacity();205 f.enum_tag_name_table.clearRetainingCapacity();
206 f.code_relocs.clearRetainingCapacity();
207 f.data_relocs.clearRetainingCapacity();
96 f.memory_layout_finished = false;208 f.memory_layout_finished = false;
97}209}
98210
...@@ -102,11 +214,16 @@ pub fn deinit(f: *Flush, gpa: Allocator) void {...@@ -102,11 +214,16 @@ pub fn deinit(f: *Flush, gpa: Allocator) void {
102 f.binary_bytes.deinit(gpa);214 f.binary_bytes.deinit(gpa);
103 f.missing_exports.deinit(gpa);215 f.missing_exports.deinit(gpa);
104 f.function_imports.deinit(gpa);216 f.function_imports.deinit(gpa);
217 f.intrinsic_function_imports.deinit(gpa);
218 f.function_export_symbols.deinit(gpa);
105 f.global_imports.deinit(gpa);219 f.global_imports.deinit(gpa);
106 f.data_imports.deinit(gpa);220 f.data_imports.deinit(gpa);
221 f.data_exports.deinit(gpa);
107 f.indirect_function_table.deinit(gpa);222 f.indirect_function_table.deinit(gpa);
108 f.func_types.deinit(gpa);223 f.func_types.deinit(gpa);
109 f.enum_tag_name_table.deinit(gpa);224 f.enum_tag_name_table.deinit(gpa);
225 f.code_relocs.deinit(gpa);
226 f.data_relocs.deinit(gpa);
110 f.* = undefined;227 f.* = undefined;
111}228}
112229
...@@ -134,48 +251,6 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -134,48 +251,6 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
134251
135 log.debug("total MIR instructions: {d}", .{wasm.mir_instructions.len});252 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
179 {254 {
180 var i = wasm.function_imports_len_prelink;255 var i = wasm.function_imports_len_prelink;
181 while (i < f.function_imports.entries.len) {256 while (i < f.function_imports.entries.len) {
...@@ -225,10 +300,24 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -225,10 +300,24 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
225 log.debug("flush export '{s}' nav={d}", .{ nav_export.name.slice(wasm), nav_export.nav_index });300 log.debug("flush export '{s}' nav={d}", .{ nav_export.name.slice(wasm), nav_export.nav_index });
226 const function_index = Wasm.FunctionIndex.fromIpNav(wasm, nav_export.nav_index).?;301 const function_index = Wasm.FunctionIndex.fromIpNav(wasm, nav_export.nav_index).?;
227 const explicit = f.missing_exports.swapRemove(nav_export.name);302 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) {
229 .hidden => true,305 .hidden => true,
230 .default, .protected => false,306 .default, .protected => false,
231 };307 };
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 });
232 if (is_hidden) {321 if (is_hidden) {
233 try wasm.hidden_function_exports.put(gpa, nav_export.name, function_index);322 try wasm.hidden_function_exports.put(gpa, nav_export.name, function_index);
234 } else {323 } else {
...@@ -239,17 +328,141 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -239,17 +328,141 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
239 if (nav_export.name.toOptional() == entry_name)328 if (nav_export.name.toOptional() == entry_name)
240 wasm.entry_resolution = .fromIpNav(wasm, nav_export.nav_index);329 wasm.entry_resolution = .fromIpNav(wasm, nav_export.nav_index);
241 } else {330 } else {
242 // This is a data export because Zcu currently has no way to331 // data exports are linker symbols
243 // export wasm globals.332 // explicit exports become address globals
244 _ = f.missing_exports.swapRemove(nav_export.name);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 });
245 _ = f.data_imports.swapRemove(nav_export.name);353 _ = f.data_imports.swapRemove(nav_export.name);
246 if (!is_obj) {354 if (explicit and !is_obj) {
247 diags.addError("unable to export data symbol '{s}'; not emitting a relocatable", .{355 const global_resolution: Wasm.GlobalImport.Resolution = .fromIpNav(
248 nav_export.name.slice(wasm),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).?,
249 });363 });
250 }364 }
251 }365 }
252 }366 }
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
254 for (f.missing_exports.keys()) |exp_name| {467 for (f.missing_exports.keys()) |exp_name| {
255 diags.addError("manually specified export name '{s}' undefined", .{exp_name.slice(wasm)});468 diags.addError("manually specified export name '{s}' undefined", .{exp_name.slice(wasm)});
...@@ -300,7 +513,27 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -300,7 +513,27 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
300 if (wasm.object_init_funcs.items.len > 0) {513 if (wasm.object_init_funcs.items.len > 0) {
301 // Zig has no constructors so these are only for object file inputs.514 // Zig has no constructors so these are only for object file inputs.
302 mem.sortUnstable(Wasm.InitFunc, wasm.object_init_funcs.items, {}, Wasm.InitFunc.lessThan);515 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 }
304 }537 }
305538
306 // Merge and order the data segments. Depends on garbage collection so that539 // Merge and order the data segments. Depends on garbage collection so that
...@@ -341,14 +574,33 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -341,14 +574,33 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
341 // dropped in __wasm_init_memory, which is registered as the start function574 // dropped in __wasm_init_memory, which is registered as the start function
342 // We also initialize bss segments (using memory.fill) as part of this575 // We also initialize bss segments (using memory.fill) as part of this
343 // function.576 // function.
344 if (wasm.any_passive_inits) {577 if (!is_obj and wasm.any_passive_inits) {
345 try wasm.addFunction(.__wasm_init_memory, &.{}, &.{});578 try wasm.addFunction(.__wasm_init_memory, &.{}, &.{});
346 }579 }
347580
348 try wasm.tables.ensureUnusedCapacity(gpa, 1);581 try wasm.tables.ensureUnusedCapacity(gpa, 1);
349582
350 if (f.indirect_function_table.entries.len > 0) {583 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 }
352 }604 }
353605
354 // Sort order:606 // Sort order:
...@@ -449,7 +701,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -449,7 +701,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
449 const start_addr = alignment.forward(memory_ptr);701 const start_addr = alignment.forward(memory_ptr);
450702
451 const want_new_segment = b: {703 const want_new_segment = b: {
452 if (is_obj) break :b false;704 if (is_obj) break :b i != 0;
453 switch (seen_tls) {705 switch (seen_tls) {
454 .before => switch (category) {706 .before => switch (category) {
455 .tls => {707 .tls => {
...@@ -489,7 +741,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -489,7 +741,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
489 log.debug("0x{x} {d} {s}", .{ start_addr, @backingInt(segment_id), segment_id.name(wasm) });741 log.debug("0x{x} {d} {s}", .{ start_addr, @backingInt(segment_id), segment_id.name(wasm) });
490 memory_ptr = start_addr + size;742 memory_ptr = start_addr + size;
491 }743 }
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, .{
493 .first_segment = first_segment,745 .first_segment = first_segment,
494 .end_addr = @intCast(memory_ptr),746 .end_addr = @intCast(memory_ptr),
495 });747 });
...@@ -555,7 +807,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -555,7 +807,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
555807
556 // When we have TLS GOT entries and shared memory is enabled, we must808 // When we have TLS GOT entries and shared memory is enabled, we must
557 // perform runtime relocations or else we don't create the function.809 // 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) {
559 // This logic that checks `any_tls_relocs` is missing the part where it811 // This logic that checks `any_tls_relocs` is missing the part where it
560 // also notices threadlocal globals from Zcu code.812 // also notices threadlocal globals from Zcu code.
561 if (wasm.any_tls_relocs) try wasm.addFunction(.__wasm_apply_global_tls_relocs, &.{}, &.{});813 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 {...@@ -582,6 +834,9 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
582 for (f.function_imports.values()) |id| {834 for (f.function_imports.values()) |id| {
583 try f.func_types.put(gpa, id.functionType(wasm), {});835 try f.func_types.put(gpa, id.functionType(wasm), {});
584 }836 }
837 for (f.intrinsic_function_imports.values()) |type_index| {
838 try f.func_types.put(gpa, type_index, {});
839 }
585 for (wasm.functions.keys()) |function| {840 for (wasm.functions.keys()) |function| {
586 try f.func_types.put(gpa, function.typeIndex(wasm), {});841 try f.func_types.put(gpa, function.typeIndex(wasm), {});
587 }842 }
...@@ -617,7 +872,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -617,7 +872,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
617 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);872 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
618873
619 for (f.function_imports.values()) |id| {874 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);
621 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(module_name.len)));876 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(module_name.len)));
622 try binary_bytes.appendSlice(gpa, module_name);877 try binary_bytes.appendSlice(gpa, module_name);
623878
...@@ -631,6 +886,20 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -631,6 +886,20 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
631 }886 }
632 total_imports += f.function_imports.entries.len;887 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
634 for (wasm.table_imports.values()) |id| {903 for (wasm.table_imports.values()) |id| {
635 const table_import = id.value(wasm);904 const table_import = id.value(wasm);
636 const module_name = table_import.module_name.slice(wasm);905 const module_name = table_import.module_name.slice(wasm);
...@@ -662,7 +931,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -662,7 +931,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
662 }931 }
663932
664 for (f.global_imports.values()) |id| {933 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);
666 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(module_name.len)));935 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(module_name.len)));
667 try binary_bytes.appendSlice(gpa, module_name);936 try binary_bytes.appendSlice(gpa, module_name);
668937
...@@ -726,12 +995,12 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -726,12 +995,12 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
726 for (wasm.globals.keys()) |global_resolution| {995 for (wasm.globals.keys()) |global_resolution| {
727 switch (global_resolution.unpack(wasm)) {996 switch (global_resolution.unpack(wasm)) {
728 .unresolved => unreachable,997 .unresolved => unreachable,
729 .__heap_base => try appendGlobal(gpa, binary_bytes, 0, virtual_addrs.heap_base),998 .__heap_base => try appendGlobal(gpa, binary_bytes, 0, virtual_addrs.heap_base, is64),
730 .__heap_end => try appendGlobal(gpa, binary_bytes, 0, virtual_addrs.heap_end),999 .__heap_end => try appendGlobal(gpa, binary_bytes, 0, virtual_addrs.heap_end, is64),
731 .__stack_pointer => try appendGlobal(gpa, binary_bytes, 1, virtual_addrs.stack_pointer),1000 .__stack_pointer => try appendGlobal(gpa, binary_bytes, 1, virtual_addrs.stack_pointer, is64),
732 .__tls_align => try appendGlobal(gpa, binary_bytes, 0, @intCast(virtual_addrs.tls_align.toByteUnits().?)),1001 .__tls_align => try appendGlobal(gpa, binary_bytes, 0, @intCast(virtual_addrs.tls_align.toByteUnits().?), is64),
733 .__tls_base => try appendGlobal(gpa, binary_bytes, 1, virtual_addrs.tls_base.?),1002 .__tls_base => try appendGlobal(gpa, binary_bytes, 1, virtual_addrs.tls_base.?, is64),
734 .__tls_size => try appendGlobal(gpa, binary_bytes, 0, virtual_addrs.tls_size.?),1003 .__tls_size => try appendGlobal(gpa, binary_bytes, 0, virtual_addrs.tls_size.?, is64),
735 .object_global => |i| {1004 .object_global => |i| {
736 const global = i.ptr(wasm);1005 const global = i.ptr(wasm);
737 try binary_bytes.appendSlice(gpa, &.{1006 try binary_bytes.appendSlice(gpa, &.{
...@@ -740,8 +1009,9 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -740,8 +1009,9 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
740 });1009 });
741 try emitExpr(wasm, binary_bytes, global.expr);1010 try emitExpr(wasm, binary_bytes, global.expr);
742 },1011 },
743 .nav_exe => unreachable, // Zig source code currently cannot represent this.1012 .uav_exe => |i| try appendGlobal(gpa, binary_bytes, 0, wasm.uavAddr(i.key(wasm).*), is64),
744 .nav_obj => unreachable, // Zig source code currently cannot represent this.1013 .nav_exe => |i| try appendGlobal(gpa, binary_bytes, 0, wasm.navAddr(i.key(wasm).*), is64),
1014 .uav_obj, .nav_obj => unreachable,
745 }1015 }
746 }1016 }
7471017
...@@ -766,7 +1036,8 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -766,7 +1036,8 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
7661036
767 if (wasm.export_table and f.indirect_function_table.entries.len > 0) {1037 if (wasm.export_table and f.indirect_function_table.entries.len > 0) {
768 const name = "__indirect_function_table";1038 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).?);
770 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));1041 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
771 try binary_bytes.appendSlice(gpa, name);1042 try binary_bytes.appendSlice(gpa, name);
772 try binary_bytes.append(gpa, @backingInt(std.wasm.ExternalKind.table));1043 try binary_bytes.append(gpa, @backingInt(std.wasm.ExternalKind.table));
...@@ -803,8 +1074,10 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -803,8 +1074,10 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
803 // start section1074 // start section
804 if (wasm.functions.getIndex(.__wasm_init_memory)) |func_index| {1075 if (wasm.functions.getIndex(.__wasm_init_memory)) |func_index| {
805 try emitStartSection(gpa, binary_bytes, .fromFunctionIndex(wasm, @fromBackingInt(@intCast(func_index))));1076 try emitStartSection(gpa, binary_bytes, .fromFunctionIndex(wasm, @fromBackingInt(@intCast(func_index))));
1077 section_index += 1;
806 } else if (Wasm.OutputFunctionIndex.fromResolution(wasm, wasm.entry_resolution)) |func_index| {1078 } else if (Wasm.OutputFunctionIndex.fromResolution(wasm, wasm.entry_resolution)) |func_index| {
807 try emitStartSection(gpa, binary_bytes, func_index);1079 try emitStartSection(gpa, binary_bytes, func_index);
1080 section_index += 1;
808 }1081 }
8091082
810 // element section1083 // element section
...@@ -812,7 +1085,10 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -812,7 +1085,10 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
812 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);1085 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
8131086
814 // indirect function table elements1087 // 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 );
816 // passive with implicit 0-index table or set table index manually1092 // passive with implicit 0-index table or set table index manually
817 const flags: u32 = if (table_index == 0) 0x0 else 0x02;1093 const flags: u32 = if (table_index == 0) 0x0 else 0x02;
818 try appendLeb128(gpa, binary_bytes, flags);1094 try appendLeb128(gpa, binary_bytes, flags);
...@@ -841,11 +1117,13 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -841,11 +1117,13 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
841 if (f.data_segment_groups.items.len > 0) {1117 if (f.data_segment_groups.items.len > 0) {
842 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);1118 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
843 replaceVecSectionHeader(binary_bytes, header_offset, .data_count, @intCast(f.data_segment_groups.items.len));1119 replaceVecSectionHeader(binary_bytes, header_offset, .data_count, @intCast(f.data_segment_groups.items.len));
1120 section_index += 1;
844 }1121 }
8451122
846 // Code section.1123 // Code section.
847 if (wasm.functions.count() != 0) {1124 if (wasm.functions.count() != 0) {
848 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);1125 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
1126 const section_offset = binary_bytes.items.len - uleb128size(@intCast(wasm.functions.count()));
8491127
850 for (wasm.functions.keys()) |resolution| switch (resolution.unpack(wasm)) {1128 for (wasm.functions.keys()) |resolution| switch (resolution.unpack(wasm)) {
851 .unresolved => unreachable,1129 .unresolved => unreachable,
...@@ -870,10 +1148,22 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -870,10 +1148,22 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
870 const code = ptr.code.slice(wasm);1148 const code = ptr.code.slice(wasm);
871 try appendLeb128(gpa, binary_bytes, code.len);1149 try appendLeb128(gpa, binary_bytes, code.len);
872 const code_start = binary_bytes.items.len;1150 const code_start = binary_bytes.items.len;
1151 const output_offset: u32 = @intCast(binary_bytes.items.len - section_offset);
873 try binary_bytes.appendSlice(gpa, code);1152 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 }
875 },1164 },
876 .zcu_func => |i| {1165 .zcu_func => |i| {
1166 const function_offset: u32 = @intCast(binary_bytes.items.len - section_offset);
877 const code_start = try reserveSize(gpa, binary_bytes);1167 const code_start = try reserveSize(gpa, binary_bytes);
878 defer replaceSize(binary_bytes, code_start);1168 defer replaceSize(binary_bytes, code_start);
8791169
...@@ -899,7 +1189,22 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -899,7 +1189,22 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
899 .func_tys = undefined,1189 .func_tys = undefined,
900 .error_name_table_ref_count = undefined,1190 .error_name_table_ref_count = undefined,
901 };1191 };
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);
902 try mir.lower(wasm, binary_bytes);1195 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 }
903 },1208 },
904 }1209 }
905 },1210 },
...@@ -921,8 +1226,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -921,8 +1226,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
921 }1226 }
922 }1227 }
923 for (wasm.nav_fixups.items) |nav_fixup| {1228 for (wasm.nav_fixups.items) |nav_fixup| {
924 const ds_id: Wasm.DataSegmentId = .pack(wasm, .{ .nav_exe = nav_fixup.navs_exe_index });1229 const vaddr = wasm.navAddr(nav_fixup.nav_index) + nav_fixup.addend;
925 const vaddr = f.data_segments.get(ds_id).? + nav_fixup.addend;
926 if (!is64) {1230 if (!is64) {
927 mem.writeInt(u32, wasm.string_bytes.items[nav_fixup.offset..][0..4], vaddr, .little);1231 mem.writeInt(u32, wasm.string_bytes.items[nav_fixup.offset..][0..4], vaddr, .little);
928 } else {1232 } else {
...@@ -930,7 +1234,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -930,7 +1234,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
930 }1234 }
931 }1235 }
932 for (wasm.func_table_fixups.items) |fixup| {1236 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);
934 if (!is64) {1238 if (!is64) {
935 mem.writeInt(u32, wasm.string_bytes.items[fixup.offset..][0..4], table_index.toAbi(), .little);1239 mem.writeInt(u32, wasm.string_bytes.items[fixup.offset..][0..4], table_index.toAbi(), .little);
936 } else {1240 } else {
...@@ -942,6 +1246,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -942,6 +1246,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
942 // Data section.1246 // Data section.
943 if (f.data_segment_groups.items.len != 0) {1247 if (f.data_segment_groups.items.len != 0) {
944 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);1248 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
946 var group_index: u32 = 0;1251 var group_index: u32 = 0;
947 var segment_offset: u32 = 0;1252 var segment_offset: u32 = 0;
...@@ -976,7 +1281,11 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -976,7 +1281,11 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
976 try appendLeb128(gpa, binary_bytes, group_size);1281 try appendLeb128(gpa, binary_bytes, group_size);
977 }1282 }
978 if (segment_id.isEmpty(wasm)) {1283 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 }
980 continue;1289 continue;
981 }1290 }
9821291
...@@ -986,6 +1295,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -986,6 +1295,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
986 segment_offset = needed_offset;1295 segment_offset = needed_offset;
9871296
988 const code_start = binary_bytes.items.len;1297 const code_start = binary_bytes.items.len;
1298 const output_offset: u32 = @intCast(binary_bytes.items.len - section_offset);
989 append: {1299 append: {
990 const code = switch (segment_id.unpack(wasm)) {1300 const code = switch (segment_id.unpack(wasm)) {
991 .__heap_base => {1301 .__heap_base => {
...@@ -1001,12 +1311,19 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -1001,12 +1311,19 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
1001 break :append;1311 break :append;
1002 },1312 },
1003 .__zig_error_name_table => {1313 .__zig_error_name_table => {
1004 if (is_obj) @panic("TODO error name table reloc");1314 if (is_obj) {
1005 const base = f.data_segments.get(.__zig_error_names).?;1315 try emitRelocatableNameTable(
1006 if (!is64) {1316 wasm,
1007 try emitTagNameTable(gpa, binary_bytes, wasm.error_name_offs.items, wasm.error_name_bytes.items, base, u32);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 );
1008 } else {1324 } 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);
1010 }1327 }
1011 break :append;1328 break :append;
1012 },1329 },
...@@ -1015,22 +1332,51 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -1015,22 +1332,51 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
1015 break :append;1332 break :append;
1016 },1333 },
1017 .__zig_tag_name_table => {1334 .__zig_tag_name_table => {
1018 if (is_obj) @panic("TODO tag name table reloc");1335 if (is_obj) {
1019 const base = f.data_segments.get(.__zig_tag_names).?;1336 try emitRelocatableNameTable(
1020 if (!is64) {1337 wasm,
1021 try emitTagNameTable(gpa, binary_bytes, wasm.tag_name_offs.items, wasm.tag_name_bytes.items, base, u32);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 );
1022 } else {1345 } 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);
1024 }1348 }
1025 break :append;1349 break :append;
1026 },1350 },
1027 .object => |i| {1351 .object => |i| {
1028 const ptr = i.ptr(wasm);1352 const ptr = i.ptr(wasm);
1029 try binary_bytes.appendSlice(gpa, ptr.payload.slice(wasm));1353 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 }
1031 break :append;1365 break :append;
1032 },1366 },
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,
1034 };1380 };
1035 try binary_bytes.appendSlice(gpa, code.slice(wasm));1381 try binary_bytes.appendSlice(gpa, code.slice(wasm));
1036 }1382 }
...@@ -1043,7 +1389,274 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -1043,7 +1389,274 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
1043 }1389 }
10441390
1045 if (is_obj) {1391 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 );
1047 } else if (comp.config.debug_format != .strip) {1660 } else if (comp.config.debug_format != .strip) {
1048 try emitNameSection(wasm, f.data_segment_groups.items, binary_bytes);1661 try emitNameSection(wasm, f.data_segment_groups.items, binary_bytes);
1049 }1662 }
...@@ -1121,7 +1734,10 @@ fn emitNameSection(...@@ -1121,7 +1734,10 @@ fn emitNameSection(
1121 const sub_offset = try reserveCustomSectionHeader(gpa, binary_bytes);1734 const sub_offset = try reserveCustomSectionHeader(gpa, binary_bytes);
1122 defer replaceHeader(binary_bytes, sub_offset, @backingInt(std.wasm.NameSubsection.function));1735 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 );
1125 try appendLeb128(gpa, binary_bytes, total_functions);1741 try appendLeb128(gpa, binary_bytes, total_functions);
11261742
1127 for (f.function_imports.keys(), 0..) |name_index, function_index| {1743 for (f.function_imports.keys(), 0..) |name_index, function_index| {
...@@ -1130,7 +1746,16 @@ fn emitNameSection(...@@ -1130,7 +1746,16 @@ fn emitNameSection(
1130 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));1746 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
1131 try binary_bytes.appendSlice(gpa, name);1747 try binary_bytes.appendSlice(gpa, name);
1132 }1748 }
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| {
1134 const name = resolution.name(wasm).?;1759 const name = resolution.name(wasm).?;
1135 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(function_index)));1760 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(function_index)));
1136 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));1761 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
...@@ -1152,7 +1777,8 @@ fn emitNameSection(...@@ -1152,7 +1777,8 @@ fn emitNameSection(
1152 try binary_bytes.appendSlice(gpa, name);1777 try binary_bytes.appendSlice(gpa, name);
1153 }1778 }
1154 for (wasm.globals.keys(), f.global_imports.entries.len..) |resolution, global_index| {1779 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).?;
1156 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(global_index)));1782 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(global_index)));
1157 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));1783 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
1158 try binary_bytes.appendSlice(gpa, name);1784 try binary_bytes.appendSlice(gpa, name);
...@@ -1418,29 +2044,6 @@ pub fn emitExpr(wasm: *const Wasm, binary_bytes: *ArrayList(u8), expr: Wasm.Expr...@@ -1418,29 +2044,6 @@ pub fn emitExpr(wasm: *const Wasm, binary_bytes: *ArrayList(u8), expr: Wasm.Expr
1418 try binary_bytes.appendSlice(gpa, slice[0 .. slice.len + 1]); // +1 to include end opcode2044 try binary_bytes.appendSlice(gpa, slice[0 .. slice.len + 1]); // +1 to include end opcode
1419}2045}
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
1444fn uleb128size(x: u32) u32 {2047fn uleb128size(x: u32) u32 {
1445 var value = x;2048 var value = x;
1446 var size: u32 = 0;2049 var size: u32 = 0;
...@@ -1449,22 +2052,395 @@ fn uleb128size(x: u32) u32 {...@@ -1449,22 +2052,395 @@ fn uleb128size(x: u32) u32 {
1449}2052}
14502053
1451fn emitTagNameTable(2054fn emitTagNameTable(
1452 gpa: Allocator,2055 wasm: *const Wasm,
1453 code: *ArrayList(u8),2056 code: *ArrayList(u8),
1454 tag_name_offs: []const u32,2057 tag_name_offs: []const u32,
1455 tag_name_bytes: []const u8,2058 tag_name_bytes: []const u8,
1456 base: u32,2059 base: u32,
1457 comptime Int: type,2060 is64: bool,
1458) error{OutOfMemory}!void {2061) 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;
1460 try code.ensureUnusedCapacity(gpa, ptr_size_bytes * 2 * tag_name_offs.len);2064 try code.ensureUnusedCapacity(gpa, ptr_size_bytes * 2 * tag_name_offs.len);
1461 for (tag_name_offs) |off| {2065 for (tag_name_offs) |off| {
1462 const name_len: u32 = @intCast(mem.indexOfScalar(u8, tag_name_bytes[off..], 0).?);2066 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);2067 if (is64) {
1464 mem.writeInt(Int, code.addManyAsArrayAssumeCapacity(ptr_size_bytes), name_len, .little);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 });
1465 }2112 }
1466}2113}
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
1468fn applyRelocs(code: []u8, code_offset: u32, relocs: Wasm.ObjectRelocation.IterableSlice, wasm: *const Wasm) void {2444fn applyRelocs(code: []u8, code_offset: u32, relocs: Wasm.ObjectRelocation.IterableSlice, wasm: *const Wasm) void {
1469 for (2445 for (
1470 relocs.slice.tags(wasm),2446 relocs.slice.tags(wasm),
...@@ -1579,12 +2555,17 @@ const RelocAddr = struct {...@@ -1579,12 +2555,17 @@ const RelocAddr = struct {
1579 fn fromSymbolName(wasm: *const Wasm, name: String, addend: i32) RelocAddr {2555 fn fromSymbolName(wasm: *const Wasm, name: String, addend: i32) RelocAddr {
1580 const flush = &wasm.flush_buffer;2556 const flush = &wasm.flush_buffer;
1581 if (wasm.object_data_imports.getPtr(name)) |import| {2557 if (wasm.object_data_imports.getPtr(name)) |import| {
1582 return fromDataLoc(flush, import.resolution.dataLoc(wasm), addend);2558 if (import.resolution != .unresolved) {
1583 } else if (wasm.data_imports.get(name)) |id| {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| {
1584 return fromDataLoc(flush, .fromDataImportId(wasm, id), addend);2566 return fromDataLoc(flush, .fromDataImportId(wasm, id), addend);
1585 } else {
1586 unreachable;
1587 }2567 }
2568 unreachable;
1588 }2569 }
15892570
1590 fn fromDataLoc(flush: *const Flush, data_loc: Wasm.DataLoc, addend: i32) RelocAddr {2571 fn fromDataLoc(flush: *const Flush, data_loc: Wasm.DataLoc, addend: i32) RelocAddr {
...@@ -1702,13 +2683,11 @@ fn emitInitMemoryFunction(...@@ -1702,13 +2683,11 @@ fn emitInitMemoryFunction(
1702 }2683 }
17032684
1704 const segment_groups = wasm.flush_buffer.data_segment_groups.items;2685 const segment_groups = wasm.flush_buffer.data_segment_groups.items;
1705 var prev_end: u32 = 0;
1706 for (segment_groups, 0..) |group, segment_index| {2686 for (segment_groups, 0..) |group, segment_index| {
1707 defer prev_end = group.end_addr;
1708 const segment = group.first_segment;2687 const segment = group.first_segment;
1709 if (!segment.isPassive(wasm)) continue;2688 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).?;
1712 const segment_size: u32 = group.end_addr - start_addr;2691 const segment_size: u32 = group.end_addr - start_addr;
17132692
1714 try binary_bytes.ensureUnusedCapacity(gpa, 6 + 6 + 1 + 5 + 6 + 6 + 1 + 6 * 2 + 1 + 1);2693 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 {...@@ -2028,11 +3007,15 @@ fn appendReservedUleb32(bytes: *ArrayList(u8), val: u32) void {
2028 };3007 };
2029}3008}
20303009
2031fn appendGlobal(gpa: Allocator, bytes: *ArrayList(u8), mutable: u8, val: u32) Allocator.Error!void {3010fn appendGlobal(gpa: Allocator, bytes: *ArrayList(u8), mutable: u8, val: u64, is64: bool) Allocator.Error!void {
2032 try bytes.ensureUnusedCapacity(gpa, 9);3011 try bytes.ensureUnusedCapacity(gpa, if (is64) 14 else 9);
2033 bytes.appendAssumeCapacity(@backingInt(std.wasm.Valtype.i32));3012 bytes.appendAssumeCapacity(@backingInt(@as(std.wasm.Valtype, if (is64) .i64 else .i32)));
2034 bytes.appendAssumeCapacity(mutable);3013 bytes.appendAssumeCapacity(mutable);
2035 appendReservedI32Const(bytes, val);3014 if (is64) {
3015 appendReservedI64Const(bytes, val);
3016 } else {
3017 appendReservedI32Const(bytes, @intCast(val));
3018 }
2036 bytes.appendAssumeCapacity(@backingInt(std.wasm.Opcode.end));3019 bytes.appendAssumeCapacity(@backingInt(std.wasm.Opcode.end));
2037}3020}
20383021
src/link/Wasm/Object.zig+1-1
...@@ -146,7 +146,7 @@ pub const Symbol = struct {...@@ -146,7 +146,7 @@ pub const Symbol = struct {
146 pointee: Pointee,146 pointee: Pointee,
147147
148 /// https://github.com/WebAssembly/tool-conventions/blob/df8d737539eb8a8f446ba5eab9dc670c40dfb81e/Linking.md#symbol-table-subsection148 /// https://github.com/WebAssembly/tool-conventions/blob/df8d737539eb8a8f446ba5eab9dc670c40dfb81e/Linking.md#symbol-table-subsection
149 const Tag = enum(u8) {149 pub const Tag = enum(u8) {
150 function,150 function,
151 data,151 data,
152 global,152 global,
src/target.zig+1-1
...@@ -437,7 +437,7 @@ pub fn canBuildLibCompilerRt(target: *const std.Target) enum { no, yes, llvm_onl...@@ -437,7 +437,7 @@ pub fn canBuildLibCompilerRt(target: *const std.Target) enum { no, yes, llvm_onl
437 else => {},437 else => {},
438 }438 }
439 return switch (zigBackend(target, false)) {439 return switch (zigBackend(target, false)) {
440 .stage2_aarch64, .stage2_x86_64 => .yes,440 .stage2_aarch64, .stage2_wasm, .stage2_x86_64 => .yes,
441 else => .llvm_only,441 else => .llvm_only,
442 };442 };
443}443}
test/behavior/basic.zig-1
...@@ -797,7 +797,6 @@ test "auto created variables have correct alignment" {...@@ -797,7 +797,6 @@ test "auto created variables have correct alignment" {
797}797}
798798
799test "extern variable with non-pointer opaque type" {799test "extern variable with non-pointer opaque type" {
800 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
801 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO800 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
802 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO801 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
803 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO802 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;...@@ -6,7 +6,6 @@ var x: u8 = 1;
66
7// This excludes builtin functions that return void or noreturn that cannot be tested.7// This excludes builtin functions that return void or noreturn that cannot be tested.
8test {8test {
9 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO10 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;11 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/call.zig-1
...@@ -21,7 +21,6 @@ test "super basic invocations" {...@@ -21,7 +21,6 @@ test "super basic invocations" {
2121
22test "basic invocations" {22test "basic invocations" {
23 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;23 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
24 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
25 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO24 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
26 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO25 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
27 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;26 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/export_builtin.zig-15
...@@ -5,11 +5,6 @@ const expect = std.testing.expect;...@@ -5,11 +5,6 @@ const expect = std.testing.expect;
5test "exporting enum value" {5test "exporting enum value" {
6 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;6 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
13 const S = struct {8 const S = struct {
14 const E = enum(c_int) { one, two };9 const E = enum(c_int) { one, two };
15 const e: E = .two;10 const e: E = .two;
...@@ -35,11 +30,6 @@ test "exporting with internal linkage" {...@@ -35,11 +30,6 @@ test "exporting with internal linkage" {
35test "exporting using namespace access" {30test "exporting using namespace access" {
36 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;31 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
43 const S = struct {33 const S = struct {
44 const Inner = struct {34 const Inner = struct {
45 const x: u32 = 5;35 const x: u32 = 5;
...@@ -57,11 +47,6 @@ test "exporting comptime-known value" {...@@ -57,11 +47,6 @@ test "exporting comptime-known value" {
57 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;47 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
58 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;48 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
65 const x: u32 = 10;50 const x: u32 = 10;
66 @export(&x, .{ .name = "exporting_comptime_known_value_foo" });51 @export(&x, .{ .name = "exporting_comptime_known_value_foo" });
67 const S = struct {52 const S = struct {
test/behavior/fn.zig-1
...@@ -418,7 +418,6 @@ test "import passed byref to function in return type" {...@@ -418,7 +418,6 @@ test "import passed byref to function in return type" {
418418
419test "implicit cast function to function ptr" {419test "implicit cast function to function ptr" {
420 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO420 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
421 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
422 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;421 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
423422
424 const S1 = struct {423 const S1 = struct {
test/tests.zig-1
...@@ -1568,7 +1568,6 @@ const module_test_targets = blk: {...@@ -1568,7 +1568,6 @@ const module_test_targets = blk: {
1568 .os_tag = .wasi,1568 .os_tag = .wasi,
1569 .abi = .none,1569 .abi = .none,
1570 },1570 },
1571 .skip_modules = &.{"compiler-rt"},
1572 .use_llvm = false,1571 .use_llvm = false,
1573 .use_lld = false,1572 .use_lld = false,
1574 },1573 },