diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index ca571370ad..4c6a9641eb 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1318,13 +1318,14 @@ pub const DeclGen = struct { if (decl.link.wasm.sym_index == 0) { try writer.writeIntLittle(u32, 0); } else { - try writer.writeIntLittle(u32, try self.bin_file.getDeclVAddr( - self.decl, // parent decl that owns the atom of the symbol - self.symbol_index, // source symbol index - decl, // target decl that contains the target symbol - @intCast(u32, self.code.items.len), // offset - @intCast(u32, offset), // addend - )); + try writer.writeIntLittle(u32, @intCast(u32, try self.bin_file.getDeclVAddr( + decl, + .{ + .parent_atom_index = self.symbol_index, + .offset = self.code.items.len, + .addend = @intCast(u32, offset), + }, + ))); } return Result{ .appended = {} }; } @@ -1809,8 +1810,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue { if (func_val.castTag(.function)) |func| { break :blk func.data.owner_decl; - } else if (func_val.castTag(.extern_fn)) |ext_fn| { - break :blk ext_fn.data.owner_decl; + } else if (func_val.castTag(.extern_fn)) |extern_fn| { + const ext_decl = extern_fn.data.owner_decl; + var func_type = try genFunctype(self.gpa, ext_decl.ty, self.target); + defer func_type.deinit(self.gpa); + ext_decl.fn_link.wasm.type_index = try self.bin_file.putOrGetFuncType(func_type); + break :blk ext_decl; } else if (func_val.castTag(.decl_ref)) |decl_ref| { break :blk decl_ref.data; } diff --git a/src/link.zig b/src/link.zig index 996622443a..6e33b11669 100644 --- a/src/link.zig +++ b/src/link.zig @@ -702,7 +702,7 @@ pub const File = struct { .macho => return @fieldParentPtr(MachO, "base", base).getDeclVAddr(decl, reloc_info), .plan9 => return @fieldParentPtr(Plan9, "base", base).getDeclVAddr(decl, reloc_info), .c => unreachable, - .wasm => unreachable, + .wasm => return @fieldParentPtr(Wasm, "base", base).getDeclVAddr(decl, reloc_info), .spirv => unreachable, .nvptx => unreachable, } diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 7026418dd5..a3704789e2 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -14,6 +14,7 @@ const Atom = @import("Wasm/Atom.zig"); const Module = @import("../Module.zig"); const Compilation = @import("../Compilation.zig"); const CodeGen = @import("../arch/wasm/CodeGen.zig"); +const codegen = @import("../codegen.zig"); const link = @import("../link.zig"); const lldMain = @import("../main.zig").lldMain; const trace = @import("../tracy.zig").trace; @@ -488,10 +489,8 @@ pub fn allocateDeclIndexes(self: *Wasm, decl: *Module.Decl) !void { self.symbols.appendAssumeCapacity(symbol); } - try self.resolved_symbols.putNoClobber(self.base.allocator, .{ - .index = atom.sym_index, - .file = null, - }, {}); + try self.resolved_symbols.putNoClobber(self.base.allocator, atom.symbolLoc(), {}); + try self.symbol_atom.putNoClobber(self.base.allocator, atom.symbolLoc(), atom); } pub fn updateFunc(self: *Wasm, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { @@ -506,7 +505,7 @@ pub fn updateFunc(self: *Wasm, module: *Module, func: *Module.Fn, air: Air, live decl.link.wasm.clear(); - var codegen: CodeGen = .{ + var codegen_: CodeGen = .{ .gpa = self.base.allocator, .air = air, .liveness = liveness, @@ -519,18 +518,18 @@ pub fn updateFunc(self: *Wasm, module: *Module, func: *Module.Fn, air: Air, live .bin_file = self, .module = module, }; - defer codegen.deinit(); + defer codegen_.deinit(); // generate the 'code' section for the function declaration - codegen.genFunc() catch |err| switch (err) { + codegen_.genFunc() catch |err| switch (err) { error.CodegenFail => { decl.analysis = .codegen_failure; - try module.failed_decls.put(module.gpa, decl, codegen.err_msg); + try module.failed_decls.put(module.gpa, decl, codegen_.err_msg); return; }, else => |e| return e, }; - return self.finishUpdateDecl(decl, codegen.code.items); + return self.finishUpdateDecl(decl, codegen_.code.items); } // Generate code for the Decl, storing it in memory to be later written to @@ -547,31 +546,37 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void { decl.link.wasm.clear(); + if (decl.isExtern()) { + return self.addOrUpdateImport(decl); + } + + if (decl.val.castTag(.function)) |_| { + return; + } else if (decl.val.castTag(.extern_fn)) |_| { + return; + } + const val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; + var code_writer = std.ArrayList(u8).init(self.base.allocator); defer code_writer.deinit(); - var decl_gen: CodeGen.DeclGen = .{ - .gpa = self.base.allocator, - .decl = decl, - .symbol_index = decl.link.wasm.sym_index, - .bin_file = self, - .err_msg = undefined, - .code = &code_writer, - .module = module, - }; - // generate the 'code' section for the function declaration - const result = decl_gen.genDecl() catch |err| switch (err) { - error.CodegenFail => { + const res = try codegen.generateSymbol( + &self.base, + decl.srcLoc(), + .{ .ty = decl.ty, .val = val }, + &code_writer, + .none, + .{ .parent_atom_index = decl.link.wasm.sym_index }, + ); + + const code = switch (res) { + .externally_managed => |x| x, + .appended => code_writer.items, + .fail => |em| { decl.analysis = .codegen_failure; - try module.failed_decls.put(module.gpa, decl, decl_gen.err_msg); + try module.failed_decls.put(module.gpa, decl, em); return; }, - else => |e| return e, - }; - - const code = switch (result) { - .externally_managed => |data| data, - .appended => code_writer.items, }; return self.finishUpdateDecl(decl, code); @@ -624,10 +629,8 @@ pub fn lowerUnnamedConst(self: *Wasm, decl: *Module.Decl, tv: TypedValue) !u32 { atom.sym_index = @intCast(u32, self.symbols.items.len); self.symbols.appendAssumeCapacity(symbol); } - try self.resolved_symbols.putNoClobber(self.base.allocator, .{ - .file = null, - .index = atom.sym_index, - }, {}); + try self.resolved_symbols.putNoClobber(self.base.allocator, atom.symbolLoc(), {}); + try self.symbol_atom.putNoClobber(self.base.allocator, atom.symbolLoc(), atom); var value_bytes = std.ArrayList(u8).init(self.base.allocator); defer value_bytes.deinit(); @@ -665,35 +668,31 @@ pub fn lowerUnnamedConst(self: *Wasm, decl: *Module.Decl, tv: TypedValue) !u32 { /// Returns the given pointer address pub fn getDeclVAddr( self: *Wasm, - decl: *Module.Decl, - symbol_index: u32, - target_decl: *Module.Decl, - offset: u32, - addend: u32, -) !u32 { - const target_symbol_index = target_decl.link.wasm.sym_index; + decl: *const Module.Decl, + reloc_info: link.File.RelocInfo, +) !u64 { + const target_symbol_index = decl.link.wasm.sym_index; assert(target_symbol_index != 0); - assert(symbol_index != 0); - - const atom = decl.link.wasm.symbolAtom(symbol_index); + assert(reloc_info.parent_atom_index != 0); + const atom = self.symbol_atom.get(.{ .file = null, .index = reloc_info.parent_atom_index }).?; const is_wasm32 = self.base.options.target.cpu.arch == .wasm32; - if (target_decl.ty.zigTypeTag() == .Fn) { - assert(addend == 0); // addend not allowed for function relocations + if (decl.ty.zigTypeTag() == .Fn) { + assert(reloc_info.addend == 0); // addend not allowed for function relocations // We found a function pointer, so add it to our table, // as function pointers are not allowed to be stored inside the data section. // They are instead stored in a function table which are called by index. try self.addTableFunction(target_symbol_index); try atom.relocs.append(self.base.allocator, .{ .index = target_symbol_index, - .offset = offset, + .offset = @intCast(u32, reloc_info.offset), .relocation_type = if (is_wasm32) .R_WASM_TABLE_INDEX_I32 else .R_WASM_TABLE_INDEX_I64, }); } else { try atom.relocs.append(self.base.allocator, .{ .index = target_symbol_index, - .offset = offset, + .offset = @intCast(u32, reloc_info.offset), .relocation_type = if (is_wasm32) .R_WASM_MEMORY_ADDR_I32 else .R_WASM_MEMORY_ADDR_I64, - .addend = addend, + .addend = reloc_info.addend, }); } // we do not know the final address at this point, @@ -823,12 +822,14 @@ pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void { local_symbol.tag = .dead; // also for any local symbol self.symbols_free_list.append(self.base.allocator, local_atom.sym_index) catch {}; assert(self.resolved_symbols.swapRemove(local_atom.symbolLoc())); + assert(self.symbol_atom.remove(local_atom.symbolLoc())); } if (decl.isExtern()) { assert(self.imports.remove(atom.symbolLoc())); } assert(self.resolved_symbols.swapRemove(atom.symbolLoc())); + assert(self.symbol_atom.remove(atom.symbolLoc())); atom.deinit(self.base.allocator); } @@ -988,7 +989,6 @@ fn allocateAtoms(self: *Wasm) !void { atom.size, }); offset += atom.size; - try self.symbol_atom.putNoClobber(self.base.allocator, symbol_loc, atom); atom = atom.next orelse break; } } diff --git a/src/link/Wasm/Object.zig b/src/link/Wasm/Object.zig index b0ec835a86..011ec2e9e4 100644 --- a/src/link/Wasm/Object.zig +++ b/src/link/Wasm/Object.zig @@ -861,6 +861,7 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin } try atom.code.appendSlice(gpa, relocatable_data.data[0..relocatable_data.size]); + try wasm_bin.symbol_atom.putNoClobber(gpa, atom.symbolLoc(), atom); const segment: *Wasm.Segment = &wasm_bin.segments.items[final_index]; segment.alignment = std.math.max(segment.alignment, atom.alignment); diff --git a/test/behavior/bugs/7250.zig b/test/behavior/bugs/7250.zig index ee04847e51..ea05cf70e3 100644 --- a/test/behavior/bugs/7250.zig +++ b/test/behavior/bugs/7250.zig @@ -18,5 +18,6 @@ test "reference a global threadlocal variable" { if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; _ = nrfx_uart_rx(&g_uart0); } diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index f3037c2d09..f68a34d341 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -1060,6 +1060,7 @@ test "compile time int to ptr of function" { if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO try foobar(FUNCTION_CONSTANT); } diff --git a/test/behavior/slice.zig b/test/behavior/slice.zig index edb14e7f61..740eaefc90 100644 --- a/test/behavior/slice.zig +++ b/test/behavior/slice.zig @@ -209,6 +209,7 @@ test "compile time slice of pointer to hard coded address" { if (builtin.zig_backend == .stage1) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; try expect(@ptrToInt(x) == 0x1000); try expect(x.len == 0x500);