| author | |
| committer | |
| log | 677427bc3ac839629654175f0a2aaaec9fd6fb6c |
| tree | deb37ed3275cfef97f9d49d7e8a1eeea5a3c64db |
| parent | ccefa9dbf5369e0fadc75b9e705e74ec96a02859 |
11 files changed, 529 insertions(+), 42 deletions(-)
src/arch/x86_64/CodeGen.zig+102-25| ... | @@ -1923,7 +1923,7 @@ fn genSetStackTruncatedOverflowCompare( | ... | @@ -1923,7 +1923,7 @@ fn genSetStackTruncatedOverflowCompare( |
| 1923 | ); | 1923 | ); |
| 1924 | 1924 | ||
| 1925 | try self.genSetStack(ty, stack_offset, .{ .register = scratch_reg }, .{}); | 1925 | try self.genSetStack(ty, stack_offset, .{ .register = scratch_reg }, .{}); |
| 1926 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ | 1926 | try self.genSetStack(Type.u1, stack_offset - overflow_bit_offset, .{ |
| 1927 | .register = overflow_reg.to8(), | 1927 | .register = overflow_reg.to8(), |
| 1928 | }, .{}); | 1928 | }, .{}); |
| 1929 | } | 1929 | } |
| ... | @@ -5280,8 +5280,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -5280,8 +5280,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 5280 | 5280 | ||
| 5281 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { | 5281 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 5282 | const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl); | 5282 | const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl); |
| 5283 | const atom = elf_file.getAtom(atom_index); | 5283 | const got_addr = elf_file.getAtom(atom_index).getOffsetTableAddress(elf_file); |
| 5284 | const got_addr = atom.getOffsetTableAddress(elf_file); | ||
| 5285 | try self.asmMemory(.call, Memory.sib(.qword, .{ | 5284 | try self.asmMemory(.call, Memory.sib(.qword, .{ |
| 5286 | .base = .ds, | 5285 | .base = .ds, |
| 5287 | .disp = @intCast(i32, got_addr), | 5286 | .disp = @intCast(i32, got_addr), |
| ... | @@ -5289,22 +5288,18 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -5289,22 +5288,18 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 5289 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { | 5288 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { |
| 5290 | const atom_index = try coff_file.getOrCreateAtomForDecl(func.owner_decl); | 5289 | const atom_index = try coff_file.getOrCreateAtomForDecl(func.owner_decl); |
| 5291 | const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; | 5290 | const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; |
| 5292 | try self.genSetReg(Type.initTag(.usize), .rax, .{ | 5291 | try self.genSetReg(Type.usize, .rax, .{ .linker_load = .{ |
| 5293 | .linker_load = .{ | 5292 | .type = .got, |
| 5294 | .type = .got, | 5293 | .sym_index = sym_index, |
| 5295 | .sym_index = sym_index, | 5294 | } }); |
| 5296 | }, | ||
| 5297 | }); | ||
| 5298 | try self.asmRegister(.call, .rax); | 5295 | try self.asmRegister(.call, .rax); |
| 5299 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { | 5296 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| 5300 | const atom_index = try macho_file.getOrCreateAtomForDecl(func.owner_decl); | 5297 | const atom_index = try macho_file.getOrCreateAtomForDecl(func.owner_decl); |
| 5301 | const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; | 5298 | const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; |
| 5302 | try self.genSetReg(Type.initTag(.usize), .rax, .{ | 5299 | try self.genSetReg(Type.usize, .rax, .{ .linker_load = .{ |
| 5303 | .linker_load = .{ | 5300 | .type = .got, |
| 5304 | .type = .got, | 5301 | .sym_index = sym_index, |
| 5305 | .sym_index = sym_index, | 5302 | } }); |
| 5306 | }, | ||
| 5307 | }); | ||
| 5308 | try self.asmRegister(.call, .rax); | 5303 | try self.asmRegister(.call, .rax); |
| 5309 | } else if (self.bin_file.cast(link.File.Plan9)) |p9| { | 5304 | } else if (self.bin_file.cast(link.File.Plan9)) |p9| { |
| 5310 | const decl_block_index = try p9.seeDecl(func.owner_decl); | 5305 | const decl_block_index = try p9.seeDecl(func.owner_decl); |
| ... | @@ -5325,7 +5320,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -5325,7 +5320,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 5325 | const lib_name = mem.sliceTo(extern_fn.lib_name, 0); | 5320 | const lib_name = mem.sliceTo(extern_fn.lib_name, 0); |
| 5326 | if (self.bin_file.cast(link.File.Coff)) |coff_file| { | 5321 | if (self.bin_file.cast(link.File.Coff)) |coff_file| { |
| 5327 | const sym_index = try coff_file.getGlobalSymbol(decl_name, lib_name); | 5322 | const sym_index = try coff_file.getGlobalSymbol(decl_name, lib_name); |
| 5328 | try self.genSetReg(Type.initTag(.usize), .rax, .{ | 5323 | try self.genSetReg(Type.usize, .rax, .{ |
| 5329 | .linker_load = .{ | 5324 | .linker_load = .{ |
| 5330 | .type = .import, | 5325 | .type = .import, |
| 5331 | .sym_index = sym_index, | 5326 | .sym_index = sym_index, |
| ... | @@ -5353,7 +5348,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -5353,7 +5348,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 5353 | } else { | 5348 | } else { |
| 5354 | assert(ty.zigTypeTag() == .Pointer); | 5349 | assert(ty.zigTypeTag() == .Pointer); |
| 5355 | const mcv = try self.resolveInst(callee); | 5350 | const mcv = try self.resolveInst(callee); |
| 5356 | try self.genSetReg(Type.initTag(.usize), .rax, mcv); | 5351 | try self.genSetReg(Type.usize, .rax, mcv); |
| 5357 | try self.asmRegister(.call, .rax); | 5352 | try self.asmRegister(.call, .rax); |
| 5358 | } | 5353 | } |
| 5359 | 5354 | ||
| ... | @@ -7299,7 +7294,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -7299,7 +7294,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 7299 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { | 7294 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { |
| 7300 | const stack_offset = @intCast(i32, try self.allocMem(inst, 16, 16)); | 7295 | const stack_offset = @intCast(i32, try self.allocMem(inst, 16, 16)); |
| 7301 | try self.genSetStack(ptr_ty, stack_offset, ptr, .{}); | 7296 | try self.genSetStack(ptr_ty, stack_offset, ptr, .{}); |
| 7302 | try self.genSetStack(Type.initTag(.u64), stack_offset - 8, .{ .immediate = array_len }, .{}); | 7297 | try self.genSetStack(Type.u64, stack_offset - 8, .{ .immediate = array_len }, .{}); |
| 7303 | break :blk .{ .stack_offset = stack_offset }; | 7298 | break :blk .{ .stack_offset = stack_offset }; |
| 7304 | }; | 7299 | }; |
| 7305 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 7300 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| ... | @@ -7809,10 +7804,92 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -7809,10 +7804,92 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { |
| 7809 | 7804 | ||
| 7810 | fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { | 7805 | fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { |
| 7811 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 7806 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 7812 | const operand = try self.resolveInst(un_op); | 7807 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 7813 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else { | 7808 | const err_ty = self.air.typeOf(un_op); |
| 7814 | _ = operand; | 7809 | const err_mcv = try self.resolveInst(un_op); |
| 7815 | return self.fail("TODO implement airErrorName for x86_64", .{}); | 7810 | const err_reg = try self.copyToTmpRegister(err_ty, err_mcv); |
| 7811 | const err_lock = self.register_manager.lockRegAssumeUnused(err_reg); | ||
| 7812 | defer self.register_manager.unlockReg(err_lock); | ||
| 7813 | |||
| 7814 | const addr_reg = try self.register_manager.allocReg(null, gp); | ||
| 7815 | const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); | ||
| 7816 | defer self.register_manager.unlockReg(addr_lock); | ||
| 7817 | |||
| 7818 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { | ||
| 7819 | const atom_index = try elf_file.getOrCreateAtomForLazySymbol( | ||
| 7820 | .{ .kind = .const_data, .ty = Type.anyerror }, | ||
| 7821 | 4, // dword alignment | ||
| 7822 | ); | ||
| 7823 | const got_addr = elf_file.getAtom(atom_index).getOffsetTableAddress(elf_file); | ||
| 7824 | try self.asmRegisterMemory(.mov, addr_reg.to64(), Memory.sib(.qword, .{ | ||
| 7825 | .base = .ds, | ||
| 7826 | .disp = @intCast(i32, got_addr), | ||
| 7827 | })); | ||
| 7828 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { | ||
| 7829 | const atom_index = try coff_file.getOrCreateAtomForLazySymbol( | ||
| 7830 | .{ .kind = .const_data, .ty = Type.anyerror }, | ||
| 7831 | 4, // dword alignment | ||
| 7832 | ); | ||
| 7833 | const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; | ||
| 7834 | try self.genSetReg(Type.usize, addr_reg, .{ .linker_load = .{ | ||
| 7835 | .type = .got, | ||
| 7836 | .sym_index = sym_index, | ||
| 7837 | } }); | ||
| 7838 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { | ||
| 7839 | const atom_index = try macho_file.getOrCreateAtomForLazySymbol( | ||
| 7840 | .{ .kind = .const_data, .ty = Type.anyerror }, | ||
| 7841 | 4, // dword alignment | ||
| 7842 | ); | ||
| 7843 | const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; | ||
| 7844 | try self.genSetReg(Type.usize, addr_reg, .{ .linker_load = .{ | ||
| 7845 | .type = .got, | ||
| 7846 | .sym_index = sym_index, | ||
| 7847 | } }); | ||
| 7848 | } else { | ||
| 7849 | return self.fail("TODO implement airErrorName for x86_64 {s}", .{@tagName(self.bin_file.tag)}); | ||
| 7850 | } | ||
| 7851 | |||
| 7852 | const start_reg = try self.register_manager.allocReg(null, gp); | ||
| 7853 | const start_lock = self.register_manager.lockRegAssumeUnused(start_reg); | ||
| 7854 | defer self.register_manager.unlockReg(start_lock); | ||
| 7855 | |||
| 7856 | const end_reg = try self.register_manager.allocReg(null, gp); | ||
| 7857 | const end_lock = self.register_manager.lockRegAssumeUnused(end_reg); | ||
| 7858 | defer self.register_manager.unlockReg(end_lock); | ||
| 7859 | |||
| 7860 | try self.truncateRegister(err_ty, err_reg.to32()); | ||
| 7861 | |||
| 7862 | try self.asmRegisterMemory(.mov, start_reg.to32(), Memory.sib(.dword, .{ | ||
| 7863 | .base = addr_reg.to64(), | ||
| 7864 | .scale_index = .{ .scale = 4, .index = err_reg.to64() }, | ||
| 7865 | .disp = 0, | ||
| 7866 | })); | ||
| 7867 | try self.asmRegisterMemory(.mov, end_reg.to32(), Memory.sib(.dword, .{ | ||
| 7868 | .base = addr_reg.to64(), | ||
| 7869 | .scale_index = .{ .scale = 4, .index = err_reg.to64() }, | ||
| 7870 | .disp = 4, | ||
| 7871 | })); | ||
| 7872 | try self.asmRegisterRegister(.sub, end_reg.to32(), start_reg.to32()); | ||
| 7873 | try self.asmRegisterMemory(.lea, start_reg.to64(), Memory.sib(.byte, .{ | ||
| 7874 | .base = addr_reg.to64(), | ||
| 7875 | .scale_index = .{ .scale = 1, .index = start_reg.to64() }, | ||
| 7876 | .disp = 0, | ||
| 7877 | })); | ||
| 7878 | try self.asmRegisterMemory(.lea, end_reg.to32(), Memory.sib(.byte, .{ | ||
| 7879 | .base = end_reg.to64(), | ||
| 7880 | .disp = -1, | ||
| 7881 | })); | ||
| 7882 | |||
| 7883 | const dst_mcv = try self.allocRegOrMem(inst, false); | ||
| 7884 | try self.asmMemoryRegister(.mov, Memory.sib(.qword, .{ | ||
| 7885 | .base = .rbp, | ||
| 7886 | .disp = 0 - dst_mcv.stack_offset, | ||
| 7887 | }), start_reg.to64()); | ||
| 7888 | try self.asmMemoryRegister(.mov, Memory.sib(.qword, .{ | ||
| 7889 | .base = .rbp, | ||
| 7890 | .disp = 8 - dst_mcv.stack_offset, | ||
| 7891 | }), end_reg.to64()); | ||
| 7892 | break :result dst_mcv; | ||
| 7816 | }; | 7893 | }; |
| 7817 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 7894 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 7818 | } | 7895 | } |
| ... | @@ -8046,7 +8123,7 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV | ... | @@ -8046,7 +8123,7 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV |
| 8046 | // This immediate is unsigned. | 8123 | // This immediate is unsigned. |
| 8047 | const U = std.meta.Int(.unsigned, ti.bits - @boolToInt(ti.signedness == .signed)); | 8124 | const U = std.meta.Int(.unsigned, ti.bits - @boolToInt(ti.signedness == .signed)); |
| 8048 | if (imm >= math.maxInt(U)) { | 8125 | if (imm >= math.maxInt(U)) { |
| 8049 | return MCValue{ .register = try self.copyToTmpRegister(Type.initTag(.usize), mcv) }; | 8126 | return MCValue{ .register = try self.copyToTmpRegister(Type.usize, mcv) }; |
| 8050 | } | 8127 | } |
| 8051 | }, | 8128 | }, |
| 8052 | else => {}, | 8129 | else => {}, |
| ... | @@ -8321,8 +8398,8 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void { | ... | @@ -8321,8 +8398,8 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void { |
| 8321 | .unsigned => { | 8398 | .unsigned => { |
| 8322 | const shift = @intCast(u6, max_reg_bit_width - int_info.bits); | 8399 | const shift = @intCast(u6, max_reg_bit_width - int_info.bits); |
| 8323 | const mask = (~@as(u64, 0)) >> shift; | 8400 | const mask = (~@as(u64, 0)) >> shift; |
| 8324 | if (int_info.bits < 32) { | 8401 | if (int_info.bits <= 32) { |
| 8325 | try self.genBinOpMir(.@"and", Type.usize, .{ .register = reg }, .{ .immediate = mask }); | 8402 | try self.genBinOpMir(.@"and", Type.u32, .{ .register = reg }, .{ .immediate = mask }); |
| 8326 | } else { | 8403 | } else { |
| 8327 | const tmp_reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = mask }); | 8404 | const tmp_reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = mask }); |
| 8328 | try self.genBinOpMir(.@"and", Type.usize, .{ .register = reg }, .{ .register = tmp_reg }); | 8405 | try self.genBinOpMir(.@"and", Type.usize, .{ .register = reg }, .{ .register = tmp_reg }); |
src/codegen.zig+44-7| ... | @@ -99,6 +99,47 @@ fn writeFloat(comptime F: type, f: F, target: Target, endian: std.builtin.Endian | ... | @@ -99,6 +99,47 @@ fn writeFloat(comptime F: type, f: F, target: Target, endian: std.builtin.Endian |
| 99 | mem.writeInt(Int, code[0..@sizeOf(Int)], int, endian); | 99 | mem.writeInt(Int, code[0..@sizeOf(Int)], int, endian); |
| 100 | } | 100 | } |
| 101 | 101 | ||
| 102 | pub fn generateLazySymbol( | ||
| 103 | bin_file: *link.File, | ||
| 104 | src_loc: Module.SrcLoc, | ||
| 105 | lazy_sym: link.File.LazySymbol, | ||
| 106 | code: *std.ArrayList(u8), | ||
| 107 | debug_output: DebugInfoOutput, | ||
| 108 | reloc_info: RelocInfo, | ||
| 109 | ) CodeGenError!Result { | ||
| 110 | _ = debug_output; | ||
| 111 | _ = reloc_info; | ||
| 112 | |||
| 113 | const tracy = trace(@src()); | ||
| 114 | defer tracy.end(); | ||
| 115 | |||
| 116 | const target = bin_file.options.target; | ||
| 117 | const endian = target.cpu.arch.endian(); | ||
| 118 | |||
| 119 | const mod = bin_file.options.module.?; | ||
| 120 | log.debug("generateLazySymbol: kind = {s}, ty = {}", .{ | ||
| 121 | @tagName(lazy_sym.kind), | ||
| 122 | lazy_sym.ty.fmt(mod), | ||
| 123 | }); | ||
| 124 | |||
| 125 | if (lazy_sym.kind == .const_data and lazy_sym.ty.isAnyError()) { | ||
| 126 | const err_names = mod.error_name_list.items; | ||
| 127 | try code.resize(err_names.len * 4); | ||
| 128 | for (err_names, 0..) |err_name, index| { | ||
| 129 | mem.writeInt(u32, code.items[index * 4 ..][0..4], @intCast(u32, code.items.len), endian); | ||
| 130 | try code.ensureUnusedCapacity(err_name.len + 1); | ||
| 131 | code.appendSliceAssumeCapacity(err_name); | ||
| 132 | code.appendAssumeCapacity(0); | ||
| 133 | } | ||
| 134 | return Result.ok; | ||
| 135 | } else return .{ .fail = try ErrorMsg.create( | ||
| 136 | bin_file.allocator, | ||
| 137 | src_loc, | ||
| 138 | "TODO implement generateLazySymbol for {s} {}", | ||
| 139 | .{ @tagName(lazy_sym.kind), lazy_sym.ty.fmt(mod) }, | ||
| 140 | ) }; | ||
| 141 | } | ||
| 142 | |||
| 102 | pub fn generateSymbol( | 143 | pub fn generateSymbol( |
| 103 | bin_file: *link.File, | 144 | bin_file: *link.File, |
| 104 | src_loc: Module.SrcLoc, | 145 | src_loc: Module.SrcLoc, |
| ... | @@ -118,9 +159,10 @@ pub fn generateSymbol( | ... | @@ -118,9 +159,10 @@ pub fn generateSymbol( |
| 118 | const target = bin_file.options.target; | 159 | const target = bin_file.options.target; |
| 119 | const endian = target.cpu.arch.endian(); | 160 | const endian = target.cpu.arch.endian(); |
| 120 | 161 | ||
| 162 | const mod = bin_file.options.module.?; | ||
| 121 | log.debug("generateSymbol: ty = {}, val = {}", .{ | 163 | log.debug("generateSymbol: ty = {}, val = {}", .{ |
| 122 | typed_value.ty.fmtDebug(), | 164 | typed_value.ty.fmt(mod), |
| 123 | typed_value.val.fmtDebug(), | 165 | typed_value.val.fmtValue(typed_value.ty, mod), |
| 124 | }); | 166 | }); |
| 125 | 167 | ||
| 126 | if (typed_value.val.isUndefDeep()) { | 168 | if (typed_value.val.isUndefDeep()) { |
| ... | @@ -170,7 +212,6 @@ pub fn generateSymbol( | ... | @@ -170,7 +212,6 @@ pub fn generateSymbol( |
| 170 | }, | 212 | }, |
| 171 | .str_lit => { | 213 | .str_lit => { |
| 172 | const str_lit = typed_value.val.castTag(.str_lit).?.data; | 214 | const str_lit = typed_value.val.castTag(.str_lit).?.data; |
| 173 | const mod = bin_file.options.module.?; | ||
| 174 | const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | 215 | const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; |
| 175 | try code.ensureUnusedCapacity(bytes.len + 1); | 216 | try code.ensureUnusedCapacity(bytes.len + 1); |
| 176 | code.appendSliceAssumeCapacity(bytes); | 217 | code.appendSliceAssumeCapacity(bytes); |
| ... | @@ -300,7 +341,6 @@ pub fn generateSymbol( | ... | @@ -300,7 +341,6 @@ pub fn generateSymbol( |
| 300 | switch (container_ptr.tag()) { | 341 | switch (container_ptr.tag()) { |
| 301 | .decl_ref => { | 342 | .decl_ref => { |
| 302 | const decl_index = container_ptr.castTag(.decl_ref).?.data; | 343 | const decl_index = container_ptr.castTag(.decl_ref).?.data; |
| 303 | const mod = bin_file.options.module.?; | ||
| 304 | const decl = mod.declPtr(decl_index); | 344 | const decl = mod.declPtr(decl_index); |
| 305 | const addend = blk: { | 345 | const addend = blk: { |
| 306 | switch (decl.ty.zigTypeTag()) { | 346 | switch (decl.ty.zigTypeTag()) { |
| ... | @@ -493,7 +533,6 @@ pub fn generateSymbol( | ... | @@ -493,7 +533,6 @@ pub fn generateSymbol( |
| 493 | const field_vals = typed_value.val.castTag(.aggregate).?.data; | 533 | const field_vals = typed_value.val.castTag(.aggregate).?.data; |
| 494 | const abi_size = math.cast(usize, typed_value.ty.abiSize(target)) orelse return error.Overflow; | 534 | const abi_size = math.cast(usize, typed_value.ty.abiSize(target)) orelse return error.Overflow; |
| 495 | const current_pos = code.items.len; | 535 | const current_pos = code.items.len; |
| 496 | const mod = bin_file.options.module.?; | ||
| 497 | try code.resize(current_pos + abi_size); | 536 | try code.resize(current_pos + abi_size); |
| 498 | var bits: u16 = 0; | 537 | var bits: u16 = 0; |
| 499 | 538 | ||
| ... | @@ -570,7 +609,6 @@ pub fn generateSymbol( | ... | @@ -570,7 +609,6 @@ pub fn generateSymbol( |
| 570 | } | 609 | } |
| 571 | 610 | ||
| 572 | const union_ty = typed_value.ty.cast(Type.Payload.Union).?.data; | 611 | const union_ty = typed_value.ty.cast(Type.Payload.Union).?.data; |
| 573 | const mod = bin_file.options.module.?; | ||
| 574 | const field_index = typed_value.ty.unionTagFieldIndex(union_obj.tag, mod).?; | 612 | const field_index = typed_value.ty.unionTagFieldIndex(union_obj.tag, mod).?; |
| 575 | assert(union_ty.haveFieldTypes()); | 613 | assert(union_ty.haveFieldTypes()); |
| 576 | const field_ty = union_ty.fields.values()[field_index].ty; | 614 | const field_ty = union_ty.fields.values()[field_index].ty; |
| ... | @@ -776,7 +814,6 @@ pub fn generateSymbol( | ... | @@ -776,7 +814,6 @@ pub fn generateSymbol( |
| 776 | }, | 814 | }, |
| 777 | .str_lit => { | 815 | .str_lit => { |
| 778 | const str_lit = typed_value.val.castTag(.str_lit).?.data; | 816 | const str_lit = typed_value.val.castTag(.str_lit).?.data; |
| 779 | const mod = bin_file.options.module.?; | ||
| 780 | const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | 817 | const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; |
| 781 | try code.ensureUnusedCapacity(str_lit.len); | 818 | try code.ensureUnusedCapacity(str_lit.len); |
| 782 | code.appendSliceAssumeCapacity(bytes); | 819 | code.appendSliceAssumeCapacity(bytes); |
src/link.zig+21| ... | @@ -687,6 +687,7 @@ pub const File = struct { | ... | @@ -687,6 +687,7 @@ pub const File = struct { |
| 687 | FrameworkNotFound, | 687 | FrameworkNotFound, |
| 688 | FunctionSignatureMismatch, | 688 | FunctionSignatureMismatch, |
| 689 | GlobalTypeMismatch, | 689 | GlobalTypeMismatch, |
| 690 | HotSwapUnavailableOnHostOperatingSystem, | ||
| 690 | InvalidCharacter, | 691 | InvalidCharacter, |
| 691 | InvalidEntryKind, | 692 | InvalidEntryKind, |
| 692 | InvalidFeatureSet, | 693 | InvalidFeatureSet, |
| ... | @@ -1104,6 +1105,26 @@ pub const File = struct { | ... | @@ -1104,6 +1105,26 @@ pub const File = struct { |
| 1104 | missing_libc: bool = false, | 1105 | missing_libc: bool = false, |
| 1105 | }; | 1106 | }; |
| 1106 | 1107 | ||
| 1108 | pub const LazySymbol = struct { | ||
| 1109 | kind: enum { code, const_data }, | ||
| 1110 | ty: Type, | ||
| 1111 | |||
| 1112 | pub const Context = struct { | ||
| 1113 | mod: *Module, | ||
| 1114 | |||
| 1115 | pub fn hash(ctx: @This(), sym: LazySymbol) u32 { | ||
| 1116 | var hasher = std.hash.Wyhash.init(0); | ||
| 1117 | std.hash.autoHash(&hasher, sym.kind); | ||
| 1118 | sym.ty.hashWithHasher(&hasher, ctx.mod); | ||
| 1119 | return @truncate(u32, hasher.final()); | ||
| 1120 | } | ||
| 1121 | |||
| 1122 | pub fn eql(ctx: @This(), lhs: LazySymbol, rhs: LazySymbol, _: usize) bool { | ||
| 1123 | return lhs.kind == rhs.kind and lhs.ty.eql(rhs.ty, ctx.mod); | ||
| 1124 | } | ||
| 1125 | }; | ||
| 1126 | }; | ||
| 1127 | |||
| 1107 | pub const C = @import("link/C.zig"); | 1128 | pub const C = @import("link/C.zig"); |
| 1108 | pub const Coff = @import("link/Coff.zig"); | 1129 | pub const Coff = @import("link/Coff.zig"); |
| 1109 | pub const Plan9 = @import("link/Plan9.zig"); | 1130 | pub const Plan9 = @import("link/Plan9.zig"); |
src/link/Coff.zig+122| ... | @@ -49,6 +49,9 @@ imports_count_dirty: bool = true, | ... | @@ -49,6 +49,9 @@ imports_count_dirty: bool = true, |
| 49 | /// Virtual address of the entry point procedure relative to image base. | 49 | /// Virtual address of the entry point procedure relative to image base. |
| 50 | entry_addr: ?u32 = null, | 50 | entry_addr: ?u32 = null, |
| 51 | 51 | ||
| 52 | /// Table of tracked LazySymbols. | ||
| 53 | lazy_syms: LazySymbolTable = .{}, | ||
| 54 | |||
| 52 | /// Table of tracked Decls. | 55 | /// Table of tracked Decls. |
| 53 | decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{}, | 56 | decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{}, |
| 54 | 57 | ||
| ... | @@ -142,6 +145,18 @@ const Section = struct { | ... | @@ -142,6 +145,18 @@ const Section = struct { |
| 142 | free_list: std.ArrayListUnmanaged(Atom.Index) = .{}, | 145 | free_list: std.ArrayListUnmanaged(Atom.Index) = .{}, |
| 143 | }; | 146 | }; |
| 144 | 147 | ||
| 148 | const LazySymbolTable = std.ArrayHashMapUnmanaged( | ||
| 149 | link.File.LazySymbol, | ||
| 150 | LazySymbolMetadata, | ||
| 151 | link.File.LazySymbol.Context, | ||
| 152 | true, | ||
| 153 | ); | ||
| 154 | |||
| 155 | const LazySymbolMetadata = struct { | ||
| 156 | atom: Atom.Index, | ||
| 157 | section: u16, | ||
| 158 | }; | ||
| 159 | |||
| 145 | const DeclMetadata = struct { | 160 | const DeclMetadata = struct { |
| 146 | atom: Atom.Index, | 161 | atom: Atom.Index, |
| 147 | section: u16, | 162 | section: u16, |
| ... | @@ -1168,6 +1183,100 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) ! | ... | @@ -1168,6 +1183,100 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) ! |
| 1168 | return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); | 1183 | return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); |
| 1169 | } | 1184 | } |
| 1170 | 1185 | ||
| 1186 | fn updateLazySymbol( | ||
| 1187 | self: *Coff, | ||
| 1188 | lazy_sym: link.File.LazySymbol, | ||
| 1189 | lazy_metadata: LazySymbolMetadata, | ||
| 1190 | ) !void { | ||
| 1191 | const gpa = self.base.allocator; | ||
| 1192 | const mod = self.base.options.module.?; | ||
| 1193 | |||
| 1194 | var code_buffer = std.ArrayList(u8).init(gpa); | ||
| 1195 | defer code_buffer.deinit(); | ||
| 1196 | |||
| 1197 | const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{ | ||
| 1198 | @tagName(lazy_sym.kind), | ||
| 1199 | lazy_sym.ty.fmt(mod), | ||
| 1200 | }); | ||
| 1201 | defer gpa.free(name); | ||
| 1202 | |||
| 1203 | const atom_index = lazy_metadata.atom; | ||
| 1204 | const atom = self.getAtomPtr(atom_index); | ||
| 1205 | const local_sym_index = atom.getSymbolIndex().?; | ||
| 1206 | |||
| 1207 | const src = if (lazy_sym.ty.getOwnerDeclOrNull()) |owner_decl| | ||
| 1208 | mod.declPtr(owner_decl).srcLoc() | ||
| 1209 | else | ||
| 1210 | Module.SrcLoc{ | ||
| 1211 | .file_scope = undefined, | ||
| 1212 | .parent_decl_node = undefined, | ||
| 1213 | .lazy = .unneeded, | ||
| 1214 | }; | ||
| 1215 | const res = try codegen.generateLazySymbol( | ||
| 1216 | &self.base, | ||
| 1217 | src, | ||
| 1218 | lazy_sym, | ||
| 1219 | &code_buffer, | ||
| 1220 | .none, | ||
| 1221 | .{ .parent_atom_index = local_sym_index }, | ||
| 1222 | ); | ||
| 1223 | const code = switch (res) { | ||
| 1224 | .ok => code_buffer.items, | ||
| 1225 | .fail => |em| { | ||
| 1226 | log.err("{s}", .{em.msg}); | ||
| 1227 | return error.CodegenFail; | ||
| 1228 | }, | ||
| 1229 | }; | ||
| 1230 | |||
| 1231 | const required_alignment = atom.alignment; | ||
| 1232 | const code_len = @intCast(u32, code.len); | ||
| 1233 | const symbol = atom.getSymbolPtr(self); | ||
| 1234 | try self.setSymbolName(symbol, name); | ||
| 1235 | symbol.section_number = @intToEnum(coff.SectionNumber, lazy_metadata.section + 1); | ||
| 1236 | symbol.type = .{ .complex_type = .NULL, .base_type = .NULL }; | ||
| 1237 | |||
| 1238 | const vaddr = try self.allocateAtom(atom_index, code_len, required_alignment); | ||
| 1239 | errdefer self.freeAtom(atom_index); | ||
| 1240 | |||
| 1241 | log.debug("allocated atom for {s} at 0x{x}", .{ name, vaddr }); | ||
| 1242 | log.debug(" (required alignment 0x{x})", .{required_alignment}); | ||
| 1243 | |||
| 1244 | atom.size = code_len; | ||
| 1245 | symbol.value = vaddr; | ||
| 1246 | |||
| 1247 | const got_target = SymbolWithLoc{ .sym_index = local_sym_index, .file = null }; | ||
| 1248 | const got_index = try self.allocateGotEntry(got_target); | ||
| 1249 | const got_atom_index = try self.createGotAtom(got_target); | ||
| 1250 | const got_atom = self.getAtom(got_atom_index); | ||
| 1251 | self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?; | ||
| 1252 | try self.writePtrWidthAtom(got_atom_index); | ||
| 1253 | |||
| 1254 | self.markRelocsDirtyByTarget(atom.getSymbolWithLoc()); | ||
| 1255 | try self.writeAtom(atom_index, code); | ||
| 1256 | } | ||
| 1257 | |||
| 1258 | pub fn getOrCreateAtomForLazySymbol( | ||
| 1259 | self: *Coff, | ||
| 1260 | lazy_sym: link.File.LazySymbol, | ||
| 1261 | alignment: u32, | ||
| 1262 | ) !Atom.Index { | ||
| 1263 | const gop = try self.lazy_syms.getOrPutContext(self.base.allocator, lazy_sym, .{ | ||
| 1264 | .mod = self.base.options.module.?, | ||
| 1265 | }); | ||
| 1266 | errdefer _ = self.lazy_syms.pop(); | ||
| 1267 | if (!gop.found_existing) { | ||
| 1268 | gop.value_ptr.* = .{ | ||
| 1269 | .atom = try self.createAtom(), | ||
| 1270 | .section = switch (lazy_sym.kind) { | ||
| 1271 | .code => self.text_section_index.?, | ||
| 1272 | .const_data => self.rdata_section_index.?, | ||
| 1273 | }, | ||
| 1274 | }; | ||
| 1275 | self.getAtomPtr(gop.value_ptr.atom).alignment = alignment; | ||
| 1276 | } | ||
| 1277 | return gop.value_ptr.atom; | ||
| 1278 | } | ||
| 1279 | |||
| 1171 | pub fn getOrCreateAtomForDecl(self: *Coff, decl_index: Module.Decl.Index) !Atom.Index { | 1280 | pub fn getOrCreateAtomForDecl(self: *Coff, decl_index: Module.Decl.Index) !Atom.Index { |
| 1172 | const gop = try self.decls.getOrPut(self.base.allocator, decl_index); | 1281 | const gop = try self.decls.getOrPut(self.base.allocator, decl_index); |
| 1173 | if (!gop.found_existing) { | 1282 | if (!gop.found_existing) { |
| ... | @@ -1498,6 +1607,19 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -1498,6 +1607,19 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod |
| 1498 | sub_prog_node.activate(); | 1607 | sub_prog_node.activate(); |
| 1499 | defer sub_prog_node.end(); | 1608 | defer sub_prog_node.end(); |
| 1500 | 1609 | ||
| 1610 | { | ||
| 1611 | var lazy_it = self.lazy_syms.iterator(); | ||
| 1612 | while (lazy_it.next()) |lazy_entry| { | ||
| 1613 | self.updateLazySymbol( | ||
| 1614 | lazy_entry.key_ptr.*, | ||
| 1615 | lazy_entry.value_ptr.*, | ||
| 1616 | ) catch |err| switch (err) { | ||
| 1617 | error.CodegenFail => return error.FlushFailure, | ||
| 1618 | else => |e| return e, | ||
| 1619 | }; | ||
| 1620 | } | ||
| 1621 | } | ||
| 1622 | |||
| 1501 | const gpa = self.base.allocator; | 1623 | const gpa = self.base.allocator; |
| 1502 | 1624 | ||
| 1503 | while (self.unresolved.popOrNull()) |entry| { | 1625 | while (self.unresolved.popOrNull()) |entry| { |
src/link/Elf.zig+114| ... | @@ -63,6 +63,12 @@ const Section = struct { | ... | @@ -63,6 +63,12 @@ const Section = struct { |
| 63 | free_list: std.ArrayListUnmanaged(Atom.Index) = .{}, | 63 | free_list: std.ArrayListUnmanaged(Atom.Index) = .{}, |
| 64 | }; | 64 | }; |
| 65 | 65 | ||
| 66 | const LazySymbolMetadata = struct { | ||
| 67 | atom: Atom.Index, | ||
| 68 | shdr: u16, | ||
| 69 | alignment: u32, | ||
| 70 | }; | ||
| 71 | |||
| 66 | const DeclMetadata = struct { | 72 | const DeclMetadata = struct { |
| 67 | atom: Atom.Index, | 73 | atom: Atom.Index, |
| 68 | shdr: u16, | 74 | shdr: u16, |
| ... | @@ -157,6 +163,9 @@ debug_line_header_dirty: bool = false, | ... | @@ -157,6 +163,9 @@ debug_line_header_dirty: bool = false, |
| 157 | 163 | ||
| 158 | error_flags: File.ErrorFlags = File.ErrorFlags{}, | 164 | error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 159 | 165 | ||
| 166 | /// Table of tracked LazySymbols. | ||
| 167 | lazy_syms: LazySymbolTable = .{}, | ||
| 168 | |||
| 160 | /// Table of tracked Decls. | 169 | /// Table of tracked Decls. |
| 161 | decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{}, | 170 | decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{}, |
| 162 | 171 | ||
| ... | @@ -194,6 +203,7 @@ relocs: RelocTable = .{}, | ... | @@ -194,6 +203,7 @@ relocs: RelocTable = .{}, |
| 194 | 203 | ||
| 195 | const RelocTable = std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Reloc)); | 204 | const RelocTable = std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Reloc)); |
| 196 | const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index)); | 205 | const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index)); |
| 206 | const LazySymbolTable = std.ArrayHashMapUnmanaged(File.LazySymbol, LazySymbolMetadata, File.LazySymbol.Context, true); | ||
| 197 | 207 | ||
| 198 | /// When allocating, the ideal_capacity is calculated by | 208 | /// When allocating, the ideal_capacity is calculated by |
| 199 | /// actual_capacity + (actual_capacity / ideal_factor) | 209 | /// actual_capacity + (actual_capacity / ideal_factor) |
| ... | @@ -1011,6 +1021,19 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node | ... | @@ -1011,6 +1021,19 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1011 | sub_prog_node.activate(); | 1021 | sub_prog_node.activate(); |
| 1012 | defer sub_prog_node.end(); | 1022 | defer sub_prog_node.end(); |
| 1013 | 1023 | ||
| 1024 | { | ||
| 1025 | var lazy_it = self.lazy_syms.iterator(); | ||
| 1026 | while (lazy_it.next()) |lazy_entry| { | ||
| 1027 | self.updateLazySymbol( | ||
| 1028 | lazy_entry.key_ptr.*, | ||
| 1029 | lazy_entry.value_ptr.*, | ||
| 1030 | ) catch |err| switch (err) { | ||
| 1031 | error.CodegenFail => return error.FlushFailure, | ||
| 1032 | else => |e| return e, | ||
| 1033 | }; | ||
| 1034 | } | ||
| 1035 | } | ||
| 1036 | |||
| 1014 | // TODO This linker code currently assumes there is only 1 compilation unit and it | 1037 | // TODO This linker code currently assumes there is only 1 compilation unit and it |
| 1015 | // corresponds to the Zig source code. | 1038 | // corresponds to the Zig source code. |
| 1016 | const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; | 1039 | const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; |
| ... | @@ -2344,6 +2367,24 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void { | ... | @@ -2344,6 +2367,24 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void { |
| 2344 | } | 2367 | } |
| 2345 | } | 2368 | } |
| 2346 | 2369 | ||
| 2370 | pub fn getOrCreateAtomForLazySymbol(self: *Elf, lazy_sym: File.LazySymbol, alignment: u32) !Atom.Index { | ||
| 2371 | const gop = try self.lazy_syms.getOrPutContext(self.base.allocator, lazy_sym, .{ | ||
| 2372 | .mod = self.base.options.module.?, | ||
| 2373 | }); | ||
| 2374 | errdefer _ = self.lazy_syms.pop(); | ||
| 2375 | if (!gop.found_existing) { | ||
| 2376 | gop.value_ptr.* = .{ | ||
| 2377 | .atom = try self.createAtom(), | ||
| 2378 | .shdr = switch (lazy_sym.kind) { | ||
| 2379 | .code => self.text_section_index.?, | ||
| 2380 | .const_data => self.rodata_section_index.?, | ||
| 2381 | }, | ||
| 2382 | .alignment = alignment, | ||
| 2383 | }; | ||
| 2384 | } | ||
| 2385 | return gop.value_ptr.atom; | ||
| 2386 | } | ||
| 2387 | |||
| 2347 | pub fn getOrCreateAtomForDecl(self: *Elf, decl_index: Module.Decl.Index) !Atom.Index { | 2388 | pub fn getOrCreateAtomForDecl(self: *Elf, decl_index: Module.Decl.Index) !Atom.Index { |
| 2348 | const gop = try self.decls.getOrPut(self.base.allocator, decl_index); | 2389 | const gop = try self.decls.getOrPut(self.base.allocator, decl_index); |
| 2349 | if (!gop.found_existing) { | 2390 | if (!gop.found_existing) { |
| ... | @@ -2610,6 +2651,79 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v | ... | @@ -2610,6 +2651,79 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v |
| 2610 | return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); | 2651 | return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); |
| 2611 | } | 2652 | } |
| 2612 | 2653 | ||
| 2654 | fn updateLazySymbol(self: *Elf, lazy_sym: File.LazySymbol, lazy_metadata: LazySymbolMetadata) !void { | ||
| 2655 | const gpa = self.base.allocator; | ||
| 2656 | const mod = self.base.options.module.?; | ||
| 2657 | |||
| 2658 | var code_buffer = std.ArrayList(u8).init(gpa); | ||
| 2659 | defer code_buffer.deinit(); | ||
| 2660 | |||
| 2661 | const name_str_index = blk: { | ||
| 2662 | const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{ | ||
| 2663 | @tagName(lazy_sym.kind), | ||
| 2664 | lazy_sym.ty.fmt(mod), | ||
| 2665 | }); | ||
| 2666 | defer gpa.free(name); | ||
| 2667 | break :blk try self.shstrtab.insert(gpa, name); | ||
| 2668 | }; | ||
| 2669 | const name = self.shstrtab.get(name_str_index).?; | ||
| 2670 | |||
| 2671 | const atom_index = lazy_metadata.atom; | ||
| 2672 | const atom = self.getAtom(atom_index); | ||
| 2673 | const local_sym_index = atom.getSymbolIndex().?; | ||
| 2674 | |||
| 2675 | const src = if (lazy_sym.ty.getOwnerDeclOrNull()) |owner_decl| | ||
| 2676 | mod.declPtr(owner_decl).srcLoc() | ||
| 2677 | else | ||
| 2678 | Module.SrcLoc{ | ||
| 2679 | .file_scope = undefined, | ||
| 2680 | .parent_decl_node = undefined, | ||
| 2681 | .lazy = .unneeded, | ||
| 2682 | }; | ||
| 2683 | const res = try codegen.generateLazySymbol( | ||
| 2684 | &self.base, | ||
| 2685 | src, | ||
| 2686 | lazy_sym, | ||
| 2687 | &code_buffer, | ||
| 2688 | .none, | ||
| 2689 | .{ .parent_atom_index = local_sym_index }, | ||
| 2690 | ); | ||
| 2691 | const code = switch (res) { | ||
| 2692 | .ok => code_buffer.items, | ||
| 2693 | .fail => |em| { | ||
| 2694 | log.err("{s}", .{em.msg}); | ||
| 2695 | return error.CodegenFail; | ||
| 2696 | }, | ||
| 2697 | }; | ||
| 2698 | |||
| 2699 | const shdr_index = lazy_metadata.shdr; | ||
| 2700 | const phdr_index = self.sections.items(.phdr_index)[shdr_index]; | ||
| 2701 | const local_sym = atom.getSymbolPtr(self); | ||
| 2702 | local_sym.* = .{ | ||
| 2703 | .st_name = name_str_index, | ||
| 2704 | .st_info = (elf.STB_LOCAL << 4) | elf.STT_OBJECT, | ||
| 2705 | .st_other = 0, | ||
| 2706 | .st_shndx = shdr_index, | ||
| 2707 | .st_value = 0, | ||
| 2708 | .st_size = 0, | ||
| 2709 | }; | ||
| 2710 | const required_alignment = lazy_metadata.alignment; | ||
| 2711 | const vaddr = try self.allocateAtom(atom_index, code.len, required_alignment); | ||
| 2712 | errdefer self.freeAtom(atom_index); | ||
| 2713 | log.debug("allocated text block for {s} at 0x{x}", .{ name, vaddr }); | ||
| 2714 | |||
| 2715 | self.offset_table.items[atom.offset_table_index] = vaddr; | ||
| 2716 | local_sym.st_value = vaddr; | ||
| 2717 | local_sym.st_size = code.len; | ||
| 2718 | |||
| 2719 | try self.writeSymbol(local_sym_index); | ||
| 2720 | try self.writeOffsetTableEntry(atom.offset_table_index); | ||
| 2721 | |||
| 2722 | const section_offset = vaddr - self.program_headers.items[phdr_index].p_vaddr; | ||
| 2723 | const file_offset = self.sections.items(.shdr)[shdr_index].sh_offset + section_offset; | ||
| 2724 | try self.base.file.?.pwriteAll(code, file_offset); | ||
| 2725 | } | ||
| 2726 | |||
| 2613 | pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module.Decl.Index) !u32 { | 2727 | pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module.Decl.Index) !u32 { |
| 2614 | const gpa = self.base.allocator; | 2728 | const gpa = self.base.allocator; |
| 2615 | 2729 |
src/link/MachO.zig+126-4| ... | @@ -218,6 +218,9 @@ bindings: BindingTable = .{}, | ... | @@ -218,6 +218,9 @@ bindings: BindingTable = .{}, |
| 218 | /// this will be a table indexed by index into the list of Atoms. | 218 | /// this will be a table indexed by index into the list of Atoms. |
| 219 | lazy_bindings: BindingTable = .{}, | 219 | lazy_bindings: BindingTable = .{}, |
| 220 | 220 | ||
| 221 | /// Table of tracked LazySymbols. | ||
| 222 | lazy_syms: LazySymbolTable = .{}, | ||
| 223 | |||
| 221 | /// Table of tracked Decls. | 224 | /// Table of tracked Decls. |
| 222 | decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{}, | 225 | decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{}, |
| 223 | 226 | ||
| ... | @@ -229,6 +232,18 @@ const is_hot_update_compatible = switch (builtin.target.os.tag) { | ... | @@ -229,6 +232,18 @@ const is_hot_update_compatible = switch (builtin.target.os.tag) { |
| 229 | else => false, | 232 | else => false, |
| 230 | }; | 233 | }; |
| 231 | 234 | ||
| 235 | const LazySymbolTable = std.ArrayHashMapUnmanaged( | ||
| 236 | link.File.LazySymbol, | ||
| 237 | LazySymbolMetadata, | ||
| 238 | link.File.LazySymbol.Context, | ||
| 239 | true, | ||
| 240 | ); | ||
| 241 | |||
| 242 | const LazySymbolMetadata = struct { | ||
| 243 | atom: Atom.Index, | ||
| 244 | section: u8, | ||
| 245 | }; | ||
| 246 | |||
| 232 | const DeclMetadata = struct { | 247 | const DeclMetadata = struct { |
| 233 | atom: Atom.Index, | 248 | atom: Atom.Index, |
| 234 | section: u8, | 249 | section: u8, |
| ... | @@ -497,6 +512,19 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -497,6 +512,19 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 497 | sub_prog_node.activate(); | 512 | sub_prog_node.activate(); |
| 498 | defer sub_prog_node.end(); | 513 | defer sub_prog_node.end(); |
| 499 | 514 | ||
| 515 | { | ||
| 516 | var lazy_it = self.lazy_syms.iterator(); | ||
| 517 | while (lazy_it.next()) |lazy_entry| { | ||
| 518 | self.updateLazySymbol( | ||
| 519 | lazy_entry.key_ptr.*, | ||
| 520 | lazy_entry.value_ptr.*, | ||
| 521 | ) catch |err| switch (err) { | ||
| 522 | error.CodegenFail => return error.FlushFailure, | ||
| 523 | else => |e| return e, | ||
| 524 | }; | ||
| 525 | } | ||
| 526 | } | ||
| 527 | |||
| 500 | const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; | 528 | const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; |
| 501 | 529 | ||
| 502 | if (self.d_sym) |*d_sym| { | 530 | if (self.d_sym) |*d_sym| { |
| ... | @@ -2163,13 +2191,13 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu | ... | @@ -2163,13 +2191,13 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu |
| 2163 | 2191 | ||
| 2164 | const name_str_index = blk: { | 2192 | const name_str_index = blk: { |
| 2165 | const index = unnamed_consts.items.len; | 2193 | const index = unnamed_consts.items.len; |
| 2166 | const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index }); | 2194 | const name = try std.fmt.allocPrint(gpa, "___unnamed_{s}_{d}", .{ decl_name, index }); |
| 2167 | defer gpa.free(name); | 2195 | defer gpa.free(name); |
| 2168 | break :blk try self.strtab.insert(gpa, name); | 2196 | break :blk try self.strtab.insert(gpa, name); |
| 2169 | }; | 2197 | }; |
| 2170 | const name = self.strtab.get(name_str_index); | 2198 | const name = self.strtab.get(name_str_index).?; |
| 2171 | 2199 | ||
| 2172 | log.debug("allocating symbol indexes for {?s}", .{name}); | 2200 | log.debug("allocating symbol indexes for {s}", .{name}); |
| 2173 | 2201 | ||
| 2174 | const atom_index = try self.createAtom(); | 2202 | const atom_index = try self.createAtom(); |
| 2175 | 2203 | ||
| ... | @@ -2202,7 +2230,7 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu | ... | @@ -2202,7 +2230,7 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu |
| 2202 | 2230 | ||
| 2203 | try unnamed_consts.append(gpa, atom_index); | 2231 | try unnamed_consts.append(gpa, atom_index); |
| 2204 | 2232 | ||
| 2205 | log.debug("allocated atom for {?s} at 0x{x}", .{ name, symbol.n_value }); | 2233 | log.debug("allocated atom for {s} at 0x{x}", .{ name, symbol.n_value }); |
| 2206 | log.debug(" (required alignment 0x{x})", .{required_alignment}); | 2234 | log.debug(" (required alignment 0x{x})", .{required_alignment}); |
| 2207 | 2235 | ||
| 2208 | try self.writeAtom(atom_index, code); | 2236 | try self.writeAtom(atom_index, code); |
| ... | @@ -2282,6 +2310,100 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) | ... | @@ -2282,6 +2310,100 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) |
| 2282 | try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); | 2310 | try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); |
| 2283 | } | 2311 | } |
| 2284 | 2312 | ||
| 2313 | fn updateLazySymbol(self: *MachO, lazy_sym: File.LazySymbol, lazy_metadata: LazySymbolMetadata) !void { | ||
| 2314 | const gpa = self.base.allocator; | ||
| 2315 | const mod = self.base.options.module.?; | ||
| 2316 | |||
| 2317 | var code_buffer = std.ArrayList(u8).init(gpa); | ||
| 2318 | defer code_buffer.deinit(); | ||
| 2319 | |||
| 2320 | const name_str_index = blk: { | ||
| 2321 | const name = try std.fmt.allocPrint(gpa, "___lazy_{s}_{}", .{ | ||
| 2322 | @tagName(lazy_sym.kind), | ||
| 2323 | lazy_sym.ty.fmt(mod), | ||
| 2324 | }); | ||
| 2325 | defer gpa.free(name); | ||
| 2326 | break :blk try self.strtab.insert(gpa, name); | ||
| 2327 | }; | ||
| 2328 | const name = self.strtab.get(name_str_index).?; | ||
| 2329 | |||
| 2330 | const atom_index = lazy_metadata.atom; | ||
| 2331 | const atom = self.getAtomPtr(atom_index); | ||
| 2332 | const local_sym_index = atom.getSymbolIndex().?; | ||
| 2333 | |||
| 2334 | const src = if (lazy_sym.ty.getOwnerDeclOrNull()) |owner_decl| | ||
| 2335 | mod.declPtr(owner_decl).srcLoc() | ||
| 2336 | else | ||
| 2337 | Module.SrcLoc{ | ||
| 2338 | .file_scope = undefined, | ||
| 2339 | .parent_decl_node = undefined, | ||
| 2340 | .lazy = .unneeded, | ||
| 2341 | }; | ||
| 2342 | const res = try codegen.generateLazySymbol( | ||
| 2343 | &self.base, | ||
| 2344 | src, | ||
| 2345 | lazy_sym, | ||
| 2346 | &code_buffer, | ||
| 2347 | .none, | ||
| 2348 | .{ .parent_atom_index = local_sym_index }, | ||
| 2349 | ); | ||
| 2350 | const code = switch (res) { | ||
| 2351 | .ok => code_buffer.items, | ||
| 2352 | .fail => |em| { | ||
| 2353 | log.err("{s}", .{em.msg}); | ||
| 2354 | return error.CodegenFail; | ||
| 2355 | }, | ||
| 2356 | }; | ||
| 2357 | |||
| 2358 | const required_alignment = atom.alignment; | ||
| 2359 | const symbol = atom.getSymbolPtr(self); | ||
| 2360 | symbol.n_strx = name_str_index; | ||
| 2361 | symbol.n_type = macho.N_SECT; | ||
| 2362 | symbol.n_sect = lazy_metadata.section + 1; | ||
| 2363 | symbol.n_desc = 0; | ||
| 2364 | |||
| 2365 | const vaddr = try self.allocateAtom(atom_index, code.len, required_alignment); | ||
| 2366 | errdefer self.freeAtom(atom_index); | ||
| 2367 | |||
| 2368 | log.debug("allocated atom for {s} at 0x{x}", .{ name, vaddr }); | ||
| 2369 | log.debug(" (required alignment 0x{x}", .{required_alignment}); | ||
| 2370 | |||
| 2371 | atom.size = code.len; | ||
| 2372 | symbol.n_value = vaddr; | ||
| 2373 | |||
| 2374 | const got_target = SymbolWithLoc{ .sym_index = local_sym_index, .file = null }; | ||
| 2375 | const got_index = try self.allocateGotEntry(got_target); | ||
| 2376 | const got_atom_index = try self.createGotAtom(got_target); | ||
| 2377 | const got_atom = self.getAtom(got_atom_index); | ||
| 2378 | self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?; | ||
| 2379 | try self.writePtrWidthAtom(got_atom_index); | ||
| 2380 | |||
| 2381 | self.markRelocsDirtyByTarget(atom.getSymbolWithLoc()); | ||
| 2382 | try self.writeAtom(atom_index, code); | ||
| 2383 | } | ||
| 2384 | |||
| 2385 | pub fn getOrCreateAtomForLazySymbol( | ||
| 2386 | self: *MachO, | ||
| 2387 | lazy_sym: File.LazySymbol, | ||
| 2388 | alignment: u32, | ||
| 2389 | ) !Atom.Index { | ||
| 2390 | const gop = try self.lazy_syms.getOrPutContext(self.base.allocator, lazy_sym, .{ | ||
| 2391 | .mod = self.base.options.module.?, | ||
| 2392 | }); | ||
| 2393 | errdefer _ = self.lazy_syms.pop(); | ||
| 2394 | if (!gop.found_existing) { | ||
| 2395 | gop.value_ptr.* = .{ | ||
| 2396 | .atom = try self.createAtom(), | ||
| 2397 | .section = switch (lazy_sym.kind) { | ||
| 2398 | .code => self.text_section_index.?, | ||
| 2399 | .const_data => self.data_const_section_index.?, | ||
| 2400 | }, | ||
| 2401 | }; | ||
| 2402 | self.getAtomPtr(gop.value_ptr.atom).alignment = alignment; | ||
| 2403 | } | ||
| 2404 | return gop.value_ptr.atom; | ||
| 2405 | } | ||
| 2406 | |||
| 2285 | pub fn getOrCreateAtomForDecl(self: *MachO, decl_index: Module.Decl.Index) !Atom.Index { | 2407 | pub fn getOrCreateAtomForDecl(self: *MachO, decl_index: Module.Decl.Index) !Atom.Index { |
| 2286 | const gop = try self.decls.getOrPut(self.base.allocator, decl_index); | 2408 | const gop = try self.decls.getOrPut(self.base.allocator, decl_index); |
| 2287 | if (!gop.found_existing) { | 2409 | if (!gop.found_existing) { |
test/behavior/bugs/6047.zig-1| ... | @@ -11,7 +11,6 @@ fn getError2() !void { | ... | @@ -11,7 +11,6 @@ fn getError2() !void { |
| 11 | 11 | ||
| 12 | test "`try`ing an if/else expression" { | 12 | test "`try`ing an if/else expression" { |
| 13 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 13 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 14 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 15 | if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO | 14 | if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO |
| 16 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 15 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 17 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 16 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
test/behavior/defer.zig-1| ... | @@ -110,7 +110,6 @@ test "mixing normal and error defers" { | ... | @@ -110,7 +110,6 @@ test "mixing normal and error defers" { |
| 110 | } | 110 | } |
| 111 | 111 | ||
| 112 | test "errdefer with payload" { | 112 | test "errdefer with payload" { |
| 113 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 114 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 113 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 115 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 114 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 116 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 115 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
test/behavior/error.zig-2| ... | @@ -575,7 +575,6 @@ fn gimmeItBroke() anyerror { | ... | @@ -575,7 +575,6 @@ fn gimmeItBroke() anyerror { |
| 575 | } | 575 | } |
| 576 | 576 | ||
| 577 | test "@errorName sentinel length matches slice length" { | 577 | test "@errorName sentinel length matches slice length" { |
| 578 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 579 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 578 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 580 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 579 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 581 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 580 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | @@ -851,7 +850,6 @@ test "catch within a function that calls no errorable functions" { | ... | @@ -851,7 +850,6 @@ test "catch within a function that calls no errorable functions" { |
| 851 | test "error from comptime string" { | 850 | test "error from comptime string" { |
| 852 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 851 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 853 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 852 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 854 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 855 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 853 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 856 | 854 | ||
| 857 | const name = "Weird error name!"; | 855 | const name = "Weird error name!"; |
test/behavior/optional.zig-1| ... | @@ -468,7 +468,6 @@ test "peer type resolution in nested if expressions" { | ... | @@ -468,7 +468,6 @@ test "peer type resolution in nested if expressions" { |
| 468 | test "cast slice to const slice nested in error union and optional" { | 468 | test "cast slice to const slice nested in error union and optional" { |
| 469 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 469 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 470 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 470 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 471 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 472 | 471 | ||
| 473 | const S = struct { | 472 | const S = struct { |
| 474 | fn inner() !?[]u8 { | 473 | fn inner() !?[]u8 { |
test/behavior/switch.zig-1| ... | @@ -419,7 +419,6 @@ test "switch on integer with else capturing expr" { | ... | @@ -419,7 +419,6 @@ test "switch on integer with else capturing expr" { |
| 419 | } | 419 | } |
| 420 | 420 | ||
| 421 | test "else prong of switch on error set excludes other cases" { | 421 | test "else prong of switch on error set excludes other cases" { |
| 422 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 423 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 422 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 424 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 423 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 425 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 424 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |