| author | |
| committer | |
| log | 90989be0e31a91335f8d1c1eafb84c3b34792a8c |
| tree | 7b3e4b1769b02db219442bd9c83d4df185848d3d |
| parent | f1eed99f3d2d355054c6cf36d6f332d83b2ec595 |
| parent | 73f385eec57d4fc28069b60f059fa8553d3a0c1b |
| signature |
elf: replace .got.zig with a zig jump table27 files changed, 488 insertions(+), 787 deletions(-)
src/Builtin.zig+1-1| ... | @@ -218,7 +218,7 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void { | ... | @@ -218,7 +218,7 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void { |
| 218 | 218 | ||
| 219 | if (opts.is_test) { | 219 | if (opts.is_test) { |
| 220 | try buffer.appendSlice( | 220 | try buffer.appendSlice( |
| 221 | \\pub var test_functions: []const std.builtin.TestFn = undefined; // overwritten later | 221 | \\pub var test_functions: []const std.builtin.TestFn = &.{}; // overwritten later |
| 222 | \\ | 222 | \\ |
| 223 | ); | 223 | ); |
| 224 | } | 224 | } |
src/Compilation.zig+7| ... | @@ -3092,6 +3092,10 @@ pub fn totalErrorCount(comp: *Compilation) u32 { | ... | @@ -3092,6 +3092,10 @@ pub fn totalErrorCount(comp: *Compilation) u32 { |
| 3092 | if (zcu.intern_pool.global_error_set.getNamesFromMainThread().len > zcu.error_limit) { | 3092 | if (zcu.intern_pool.global_error_set.getNamesFromMainThread().len > zcu.error_limit) { |
| 3093 | total += 1; | 3093 | total += 1; |
| 3094 | } | 3094 | } |
| 3095 | |||
| 3096 | for (zcu.failed_codegen.keys()) |_| { | ||
| 3097 | total += 1; | ||
| 3098 | } | ||
| 3095 | } | 3099 | } |
| 3096 | 3100 | ||
| 3097 | // The "no entry point found" error only counts if there are no semantic analysis errors. | 3101 | // The "no entry point found" error only counts if there are no semantic analysis errors. |
| ... | @@ -3237,6 +3241,9 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { | ... | @@ -3237,6 +3241,9 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { |
| 3237 | } | 3241 | } |
| 3238 | } | 3242 | } |
| 3239 | } | 3243 | } |
| 3244 | for (zcu.failed_codegen.values()) |error_msg| { | ||
| 3245 | try addModuleErrorMsg(zcu, &bundle, error_msg.*, &all_references); | ||
| 3246 | } | ||
| 3240 | for (zcu.failed_exports.values()) |value| { | 3247 | for (zcu.failed_exports.values()) |value| { |
| 3241 | try addModuleErrorMsg(zcu, &bundle, value.*, &all_references); | 3248 | try addModuleErrorMsg(zcu, &bundle, value.*, &all_references); |
| 3242 | } | 3249 | } |
src/arch/aarch64/CodeGen.zig+7-34| ... | @@ -4352,24 +4352,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -4352,24 +4352,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4352 | // on linking. | 4352 | // on linking. |
| 4353 | if (try self.air.value(callee, pt)) |func_value| switch (ip.indexToKey(func_value.toIntern())) { | 4353 | if (try self.air.value(callee, pt)) |func_value| switch (ip.indexToKey(func_value.toIntern())) { |
| 4354 | .func => |func| { | 4354 | .func => |func| { |
| 4355 | if (self.bin_file.cast(.elf)) |elf_file| { | 4355 | if (self.bin_file.cast(.elf)) |_| { |
| 4356 | const zo = elf_file.zigObjectPtr().?; | 4356 | return self.fail("TODO implement calling functions for Elf", .{}); |
| 4357 | const sym_index = try zo.getOrCreateMetadataForNav(elf_file, func.owner_nav); | 4357 | } else if (self.bin_file.cast(.macho)) |_| { |
| 4358 | const sym = zo.symbol(sym_index); | 4358 | return self.fail("TODO implement calling functions for MachO", .{}); |
| 4359 | _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file); | ||
| 4360 | const got_addr = @as(u32, @intCast(sym.zigGotAddress(elf_file))); | ||
| 4361 | try self.genSetReg(Type.usize, .x30, .{ .memory = got_addr }); | ||
| 4362 | } else if (self.bin_file.cast(.macho)) |macho_file| { | ||
| 4363 | _ = macho_file; | ||
| 4364 | @panic("TODO airCall"); | ||
| 4365 | // const atom = try macho_file.getOrCreateAtomForNav(func.owner_nav); | ||
| 4366 | // const sym_index = macho_file.getAtom(atom).getSymbolIndex().?; | ||
| 4367 | // try self.genSetReg(Type.u64, .x30, .{ | ||
| 4368 | // .linker_load = .{ | ||
| 4369 | // .type = .got, | ||
| 4370 | // .sym_index = sym_index, | ||
| 4371 | // }, | ||
| 4372 | // }); | ||
| 4373 | } else if (self.bin_file.cast(.coff)) |coff_file| { | 4359 | } else if (self.bin_file.cast(.coff)) |coff_file| { |
| 4374 | const atom = try coff_file.getOrCreateAtomForNav(func.owner_nav); | 4360 | const atom = try coff_file.getOrCreateAtomForNav(func.owner_nav); |
| 4375 | const sym_index = coff_file.getAtom(atom).getSymbolIndex().?; | 4361 | const sym_index = coff_file.getAtom(atom).getSymbolIndex().?; |
| ... | @@ -4393,21 +4379,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -4393,21 +4379,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4393 | .@"extern" => |@"extern"| { | 4379 | .@"extern" => |@"extern"| { |
| 4394 | const nav_name = ip.getNav(@"extern".owner_nav).name.toSlice(ip); | 4380 | const nav_name = ip.getNav(@"extern".owner_nav).name.toSlice(ip); |
| 4395 | const lib_name = @"extern".lib_name.toSlice(ip); | 4381 | const lib_name = @"extern".lib_name.toSlice(ip); |
| 4396 | if (self.bin_file.cast(.macho)) |macho_file| { | 4382 | if (self.bin_file.cast(.macho)) |_| { |
| 4397 | _ = macho_file; | 4383 | return self.fail("TODO implement calling extern functions for MachO", .{}); |
| 4398 | @panic("TODO airCall"); | ||
| 4399 | // const sym_index = try macho_file.getGlobalSymbol(nav_name, lib_name); | ||
| 4400 | // const atom = try macho_file.getOrCreateAtomForNav(self.owner_nav); | ||
| 4401 | // const atom_index = macho_file.getAtom(atom).getSymbolIndex().?; | ||
| 4402 | // _ = try self.addInst(.{ | ||
| 4403 | // .tag = .call_extern, | ||
| 4404 | // .data = .{ | ||
| 4405 | // .relocation = .{ | ||
| 4406 | // .atom_index = atom_index, | ||
| 4407 | // .sym_index = sym_index, | ||
| 4408 | // }, | ||
| 4409 | // }, | ||
| 4410 | // }); | ||
| 4411 | } else if (self.bin_file.cast(.coff)) |coff_file| { | 4384 | } else if (self.bin_file.cast(.coff)) |coff_file| { |
| 4412 | const sym_index = try coff_file.getGlobalSymbol(nav_name, lib_name); | 4385 | const sym_index = try coff_file.getGlobalSymbol(nav_name, lib_name); |
| 4413 | try self.genSetReg(Type.u64, .x30, .{ | 4386 | try self.genSetReg(Type.u64, .x30, .{ |
| ... | @@ -6234,7 +6207,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue { | ... | @@ -6234,7 +6207,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue { |
| 6234 | .memory => |addr| .{ .memory = addr }, | 6207 | .memory => |addr| .{ .memory = addr }, |
| 6235 | .load_got => |sym_index| .{ .linker_load = .{ .type = .got, .sym_index = sym_index } }, | 6208 | .load_got => |sym_index| .{ .linker_load = .{ .type = .got, .sym_index = sym_index } }, |
| 6236 | .load_direct => |sym_index| .{ .linker_load = .{ .type = .direct, .sym_index = sym_index } }, | 6209 | .load_direct => |sym_index| .{ .linker_load = .{ .type = .direct, .sym_index = sym_index } }, |
| 6237 | .load_symbol, .load_tlv => unreachable, // TODO | 6210 | .load_symbol, .load_tlv, .lea_symbol => unreachable, // TODO |
| 6238 | }, | 6211 | }, |
| 6239 | .fail => |msg| { | 6212 | .fail => |msg| { |
| 6240 | self.err_msg = msg; | 6213 | self.err_msg = msg; |
src/arch/arm/CodeGen.zig+3-17| ... | @@ -4333,22 +4333,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -4333,22 +4333,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4333 | // Due to incremental compilation, how function calls are generated depends | 4333 | // Due to incremental compilation, how function calls are generated depends |
| 4334 | // on linking. | 4334 | // on linking. |
| 4335 | if (try self.air.value(callee, pt)) |func_value| switch (ip.indexToKey(func_value.toIntern())) { | 4335 | if (try self.air.value(callee, pt)) |func_value| switch (ip.indexToKey(func_value.toIntern())) { |
| 4336 | .func => |func| { | 4336 | .func => { |
| 4337 | if (self.bin_file.cast(.elf)) |elf_file| { | 4337 | return self.fail("TODO implement calling functions", .{}); |
| 4338 | const zo = elf_file.zigObjectPtr().?; | ||
| 4339 | const sym_index = try zo.getOrCreateMetadataForNav(elf_file, func.owner_nav); | ||
| 4340 | const sym = zo.symbol(sym_index); | ||
| 4341 | _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file); | ||
| 4342 | const got_addr: u32 = @intCast(sym.zigGotAddress(elf_file)); | ||
| 4343 | try self.genSetReg(Type.usize, .lr, .{ .memory = got_addr }); | ||
| 4344 | } else if (self.bin_file.cast(.macho)) |_| { | ||
| 4345 | unreachable; // unsupported architecture for MachO | ||
| 4346 | } else { | ||
| 4347 | return self.fail("TODO implement call on {s} for {s}", .{ | ||
| 4348 | @tagName(self.bin_file.tag), | ||
| 4349 | @tagName(self.target.cpu.arch), | ||
| 4350 | }); | ||
| 4351 | } | ||
| 4352 | }, | 4338 | }, |
| 4353 | .@"extern" => { | 4339 | .@"extern" => { |
| 4354 | return self.fail("TODO implement calling extern functions", .{}); | 4340 | return self.fail("TODO implement calling extern functions", .{}); |
| ... | @@ -6184,7 +6170,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue { | ... | @@ -6184,7 +6170,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue { |
| 6184 | .mcv => |mcv| switch (mcv) { | 6170 | .mcv => |mcv| switch (mcv) { |
| 6185 | .none => .none, | 6171 | .none => .none, |
| 6186 | .undef => .undef, | 6172 | .undef => .undef, |
| 6187 | .load_got, .load_symbol, .load_direct, .load_tlv => unreachable, // TODO | 6173 | .load_got, .load_symbol, .load_direct, .load_tlv, .lea_symbol => unreachable, // TODO |
| 6188 | .immediate => |imm| .{ .immediate = @truncate(imm) }, | 6174 | .immediate => |imm| .{ .immediate = @truncate(imm) }, |
| 6189 | .memory => |addr| .{ .memory = addr }, | 6175 | .memory => |addr| .{ .memory = addr }, |
| 6190 | }, | 6176 | }, |
src/arch/riscv64/CodeGen.zig+6-5| ... | @@ -4937,7 +4937,7 @@ fn genCall( | ... | @@ -4937,7 +4937,7 @@ fn genCall( |
| 4937 | if (func.mod.pic) { | 4937 | if (func.mod.pic) { |
| 4938 | return func.fail("TODO: genCall pic", .{}); | 4938 | return func.fail("TODO: genCall pic", .{}); |
| 4939 | } else { | 4939 | } else { |
| 4940 | try func.genSetReg(Type.u64, .ra, .{ .load_symbol = .{ .sym = sym_index } }); | 4940 | try func.genSetReg(Type.u64, .ra, .{ .lea_symbol = .{ .sym = sym_index } }); |
| 4941 | _ = try func.addInst(.{ | 4941 | _ = try func.addInst(.{ |
| 4942 | .tag = .jalr, | 4942 | .tag = .jalr, |
| 4943 | .data = .{ .i_type = .{ | 4943 | .data = .{ .i_type = .{ |
| ... | @@ -6120,7 +6120,7 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -6120,7 +6120,7 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void { |
| 6120 | arg_map.get(op_str["%[".len .. mod_index orelse op_str.len - "]".len]) orelse | 6120 | arg_map.get(op_str["%[".len .. mod_index orelse op_str.len - "]".len]) orelse |
| 6121 | return func.fail("no matching constraint: '{s}'", .{op_str}) | 6121 | return func.fail("no matching constraint: '{s}'", .{op_str}) |
| 6122 | ]) { | 6122 | ]) { |
| 6123 | .load_symbol => |sym_off| if (mem.eql(u8, modifier, "plt")) blk: { | 6123 | .lea_symbol => |sym_off| if (mem.eql(u8, modifier, "plt")) blk: { |
| 6124 | assert(sym_off.off == 0); | 6124 | assert(sym_off.off == 0); |
| 6125 | break :blk .{ .sym = sym_off }; | 6125 | break :blk .{ .sym = sym_off }; |
| 6126 | } else return func.fail("invalid modifier: '{s}'", .{modifier}), | 6126 | } else return func.fail("invalid modifier: '{s}'", .{modifier}), |
| ... | @@ -6388,7 +6388,7 @@ fn genCopy(func: *Func, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void { | ... | @@ -6388,7 +6388,7 @@ fn genCopy(func: *Func, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void { |
| 6388 | ty, | 6388 | ty, |
| 6389 | src_mcv, | 6389 | src_mcv, |
| 6390 | ), | 6390 | ), |
| 6391 | .load_tlv => { | 6391 | .load_symbol, .load_tlv => { |
| 6392 | const addr_reg, const addr_lock = try func.allocReg(.int); | 6392 | const addr_reg, const addr_lock = try func.allocReg(.int); |
| 6393 | defer func.register_manager.unlockReg(addr_lock); | 6393 | defer func.register_manager.unlockReg(addr_lock); |
| 6394 | 6394 | ||
| ... | @@ -6433,7 +6433,7 @@ fn genCopy(func: *Func, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void { | ... | @@ -6433,7 +6433,7 @@ fn genCopy(func: *Func, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void { |
| 6433 | part_disp += @intCast(dst_ty.abiSize(func.pt)); | 6433 | part_disp += @intCast(dst_ty.abiSize(func.pt)); |
| 6434 | } | 6434 | } |
| 6435 | }, | 6435 | }, |
| 6436 | else => return func.fail("TODO: genCopy to {s} from {s}", .{ @tagName(dst_mcv), @tagName(src_mcv) }), | 6436 | else => return std.debug.panic("TODO: genCopy to {s} from {s}", .{ @tagName(dst_mcv), @tagName(src_mcv) }), |
| 6437 | } | 6437 | } |
| 6438 | } | 6438 | } |
| 6439 | 6439 | ||
| ... | @@ -6594,7 +6594,7 @@ fn genInlineMemset( | ... | @@ -6594,7 +6594,7 @@ fn genInlineMemset( |
| 6594 | .tag = .beq, | 6594 | .tag = .beq, |
| 6595 | .data = .{ | 6595 | .data = .{ |
| 6596 | .b_type = .{ | 6596 | .b_type = .{ |
| 6597 | .inst = @intCast(func.mir_instructions.len + 4), // points after the last inst | 6597 | .inst = @intCast(func.mir_instructions.len + 3), // points after the last inst |
| 6598 | .rs1 = count, | 6598 | .rs1 = count, |
| 6599 | .rs2 = .zero, | 6599 | .rs2 = .zero, |
| 6600 | }, | 6600 | }, |
| ... | @@ -8026,6 +8026,7 @@ fn genTypedValue(func: *Func, val: Value) InnerError!MCValue { | ... | @@ -8026,6 +8026,7 @@ fn genTypedValue(func: *Func, val: Value) InnerError!MCValue { |
| 8026 | .mcv => |mcv| switch (mcv) { | 8026 | .mcv => |mcv| switch (mcv) { |
| 8027 | .none => .none, | 8027 | .none => .none, |
| 8028 | .undef => unreachable, | 8028 | .undef => unreachable, |
| 8029 | .lea_symbol => |sym_index| .{ .lea_symbol = .{ .sym = sym_index } }, | ||
| 8029 | .load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } }, | 8030 | .load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } }, |
| 8030 | .load_tlv => |sym_index| .{ .lea_tlv = sym_index }, | 8031 | .load_tlv => |sym_index| .{ .lea_tlv = sym_index }, |
| 8031 | .immediate => |imm| .{ .immediate = imm }, | 8032 | .immediate => |imm| .{ .immediate = imm }, |
src/arch/riscv64/Emit.zig+5-17| ... | @@ -43,31 +43,19 @@ pub fn emitMir(emit: *Emit) Error!void { | ... | @@ -43,31 +43,19 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 43 | .fmt = std.meta.activeTag(lowered_inst), | 43 | .fmt = std.meta.activeTag(lowered_inst), |
| 44 | }), | 44 | }), |
| 45 | .load_symbol_reloc => |symbol| { | 45 | .load_symbol_reloc => |symbol| { |
| 46 | const is_obj_or_static_lib = switch (emit.lower.output_mode) { | ||
| 47 | .Exe => false, | ||
| 48 | .Obj => true, | ||
| 49 | .Lib => emit.lower.link_mode == .static, | ||
| 50 | }; | ||
| 51 | |||
| 52 | const elf_file = emit.bin_file.cast(.elf).?; | 46 | const elf_file = emit.bin_file.cast(.elf).?; |
| 53 | const zo = elf_file.zigObjectPtr().?; | 47 | const zo = elf_file.zigObjectPtr().?; |
| 54 | 48 | ||
| 55 | const atom_ptr = zo.symbol(symbol.atom_index).atom(elf_file).?; | 49 | const atom_ptr = zo.symbol(symbol.atom_index).atom(elf_file).?; |
| 56 | const sym = zo.symbol(symbol.sym_index); | 50 | const sym = zo.symbol(symbol.sym_index); |
| 57 | 51 | ||
| 58 | var hi_r_type: u32 = @intFromEnum(std.elf.R_RISCV.HI20); | 52 | if (sym.flags.is_extern_ptr and emit.lower.pic) { |
| 59 | var lo_r_type: u32 = @intFromEnum(std.elf.R_RISCV.LO12_I); | 53 | return emit.fail("emit GOT relocation for symbol '{s}'", .{sym.name(elf_file)}); |
| 60 | |||
| 61 | if (sym.flags.needs_zig_got and !is_obj_or_static_lib) { | ||
| 62 | _ = try sym.getOrCreateZigGotEntry(symbol.sym_index, elf_file); | ||
| 63 | |||
| 64 | hi_r_type = Elf.R_ZIG_GOT_HI20; | ||
| 65 | lo_r_type = Elf.R_ZIG_GOT_LO12; | ||
| 66 | } else if (sym.flags.needs_got) { | ||
| 67 | hi_r_type = Elf.R_GOT_HI20_STATIC; // TODO: rework this #20887 | ||
| 68 | lo_r_type = Elf.R_GOT_LO12_I_STATIC; // TODO: rework this #20887 | ||
| 69 | } | 54 | } |
| 70 | 55 | ||
| 56 | const hi_r_type: u32 = @intFromEnum(std.elf.R_RISCV.HI20); | ||
| 57 | const lo_r_type: u32 = @intFromEnum(std.elf.R_RISCV.LO12_I); | ||
| 58 | |||
| 71 | try atom_ptr.addReloc(elf_file, .{ | 59 | try atom_ptr.addReloc(elf_file, .{ |
| 72 | .r_offset = start_offset, | 60 | .r_offset = start_offset, |
| 73 | .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | hi_r_type, | 61 | .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | hi_r_type, |
src/arch/sparc64/CodeGen.zig+3-29| ... | @@ -1349,34 +1349,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -1349,34 +1349,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 1349 | // Due to incremental compilation, how function calls are generated depends | 1349 | // Due to incremental compilation, how function calls are generated depends |
| 1350 | // on linking. | 1350 | // on linking. |
| 1351 | if (try self.air.value(callee, pt)) |func_value| switch (ip.indexToKey(func_value.toIntern())) { | 1351 | if (try self.air.value(callee, pt)) |func_value| switch (ip.indexToKey(func_value.toIntern())) { |
| 1352 | .func => |func| { | 1352 | .func => { |
| 1353 | const got_addr = if (self.bin_file.cast(.elf)) |elf_file| blk: { | 1353 | return self.fail("TODO implement calling functions", .{}); |
| 1354 | const zo = elf_file.zigObjectPtr().?; | ||
| 1355 | const sym_index = try zo.getOrCreateMetadataForNav(elf_file, func.owner_nav); | ||
| 1356 | const sym = zo.symbol(sym_index); | ||
| 1357 | _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file); | ||
| 1358 | break :blk @as(u32, @intCast(sym.zigGotAddress(elf_file))); | ||
| 1359 | } else @panic("TODO SPARCv9 currently does not support non-ELF binaries"); | ||
| 1360 | |||
| 1361 | try self.genSetReg(Type.usize, .o7, .{ .memory = got_addr }); | ||
| 1362 | |||
| 1363 | _ = try self.addInst(.{ | ||
| 1364 | .tag = .jmpl, | ||
| 1365 | .data = .{ | ||
| 1366 | .arithmetic_3op = .{ | ||
| 1367 | .is_imm = false, | ||
| 1368 | .rd = .o7, | ||
| 1369 | .rs1 = .o7, | ||
| 1370 | .rs2_or_imm = .{ .rs2 = .g0 }, | ||
| 1371 | }, | ||
| 1372 | }, | ||
| 1373 | }); | ||
| 1374 | |||
| 1375 | // TODO Find a way to fill this delay slot | ||
| 1376 | _ = try self.addInst(.{ | ||
| 1377 | .tag = .nop, | ||
| 1378 | .data = .{ .nop = {} }, | ||
| 1379 | }); | ||
| 1380 | }, | 1354 | }, |
| 1381 | .@"extern" => { | 1355 | .@"extern" => { |
| 1382 | return self.fail("TODO implement calling extern functions", .{}); | 1356 | return self.fail("TODO implement calling extern functions", .{}); |
| ... | @@ -4153,7 +4127,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue { | ... | @@ -4153,7 +4127,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue { |
| 4153 | .mcv => |mcv| switch (mcv) { | 4127 | .mcv => |mcv| switch (mcv) { |
| 4154 | .none => .none, | 4128 | .none => .none, |
| 4155 | .undef => .undef, | 4129 | .undef => .undef, |
| 4156 | .load_got, .load_symbol, .load_direct, .load_tlv => unreachable, // TODO | 4130 | .load_got, .load_symbol, .load_direct, .load_tlv, .lea_symbol => unreachable, // TODO |
| 4157 | .immediate => |imm| .{ .immediate = imm }, | 4131 | .immediate => |imm| .{ .immediate = imm }, |
| 4158 | .memory => |addr| .{ .memory = addr }, | 4132 | .memory => |addr| .{ .memory = addr }, |
| 4159 | }, | 4133 | }, |
src/arch/x86_64/CodeGen.zig+52-53| ... | @@ -1379,14 +1379,22 @@ fn asmImmediate(self: *Self, tag: Mir.Inst.FixedTag, imm: Immediate) !void { | ... | @@ -1379,14 +1379,22 @@ fn asmImmediate(self: *Self, tag: Mir.Inst.FixedTag, imm: Immediate) !void { |
| 1379 | .ops = switch (imm) { | 1379 | .ops = switch (imm) { |
| 1380 | .signed => .i_s, | 1380 | .signed => .i_s, |
| 1381 | .unsigned => .i_u, | 1381 | .unsigned => .i_u, |
| 1382 | .reloc => .rel, | ||
| 1382 | }, | 1383 | }, |
| 1383 | .data = .{ .i = .{ | 1384 | .data = switch (imm) { |
| 1384 | .fixes = tag[0], | 1385 | .reloc => |x| reloc: { |
| 1385 | .i = switch (imm) { | 1386 | assert(tag[0] == ._); |
| 1386 | .signed => |s| @bitCast(s), | 1387 | break :reloc .{ .reloc = x }; |
| 1387 | .unsigned => |u| @intCast(u), | ||
| 1388 | }, | 1388 | }, |
| 1389 | } }, | 1389 | .signed, .unsigned => .{ .i = .{ |
| 1390 | .fixes = tag[0], | ||
| 1391 | .i = switch (imm) { | ||
| 1392 | .signed => |s| @bitCast(s), | ||
| 1393 | .unsigned => |u| @intCast(u), | ||
| 1394 | .reloc => unreachable, | ||
| 1395 | }, | ||
| 1396 | } }, | ||
| 1397 | }, | ||
| 1390 | }); | 1398 | }); |
| 1391 | } | 1399 | } |
| 1392 | 1400 | ||
| ... | @@ -1406,6 +1414,7 @@ fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.FixedTag, reg: Register, imm: | ... | @@ -1406,6 +1414,7 @@ fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.FixedTag, reg: Register, imm: |
| 1406 | const ops: Mir.Inst.Ops = switch (imm) { | 1414 | const ops: Mir.Inst.Ops = switch (imm) { |
| 1407 | .signed => .ri_s, | 1415 | .signed => .ri_s, |
| 1408 | .unsigned => |u| if (math.cast(u32, u)) |_| .ri_u else .ri64, | 1416 | .unsigned => |u| if (math.cast(u32, u)) |_| .ri_u else .ri64, |
| 1417 | .reloc => unreachable, | ||
| 1409 | }; | 1418 | }; |
| 1410 | _ = try self.addInst(.{ | 1419 | _ = try self.addInst(.{ |
| 1411 | .tag = tag[1], | 1420 | .tag = tag[1], |
| ... | @@ -1417,6 +1426,7 @@ fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.FixedTag, reg: Register, imm: | ... | @@ -1417,6 +1426,7 @@ fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.FixedTag, reg: Register, imm: |
| 1417 | .i = switch (imm) { | 1426 | .i = switch (imm) { |
| 1418 | .signed => |s| @bitCast(s), | 1427 | .signed => |s| @bitCast(s), |
| 1419 | .unsigned => |u| @intCast(u), | 1428 | .unsigned => |u| @intCast(u), |
| 1429 | .reloc => unreachable, | ||
| 1420 | }, | 1430 | }, |
| 1421 | } }, | 1431 | } }, |
| 1422 | .ri64 => .{ .rx = .{ | 1432 | .ri64 => .{ .rx = .{ |
| ... | @@ -1488,6 +1498,7 @@ fn asmRegisterRegisterRegisterImmediate( | ... | @@ -1488,6 +1498,7 @@ fn asmRegisterRegisterRegisterImmediate( |
| 1488 | .i = switch (imm) { | 1498 | .i = switch (imm) { |
| 1489 | .signed => |s| @bitCast(@as(i8, @intCast(s))), | 1499 | .signed => |s| @bitCast(@as(i8, @intCast(s))), |
| 1490 | .unsigned => |u| @intCast(u), | 1500 | .unsigned => |u| @intCast(u), |
| 1501 | .reloc => unreachable, | ||
| 1491 | }, | 1502 | }, |
| 1492 | } }, | 1503 | } }, |
| 1493 | }); | 1504 | }); |
| ... | @@ -1505,6 +1516,7 @@ fn asmRegisterRegisterImmediate( | ... | @@ -1505,6 +1516,7 @@ fn asmRegisterRegisterImmediate( |
| 1505 | .ops = switch (imm) { | 1516 | .ops = switch (imm) { |
| 1506 | .signed => .rri_s, | 1517 | .signed => .rri_s, |
| 1507 | .unsigned => .rri_u, | 1518 | .unsigned => .rri_u, |
| 1519 | .reloc => unreachable, | ||
| 1508 | }, | 1520 | }, |
| 1509 | .data = .{ .rri = .{ | 1521 | .data = .{ .rri = .{ |
| 1510 | .fixes = tag[0], | 1522 | .fixes = tag[0], |
| ... | @@ -1513,6 +1525,7 @@ fn asmRegisterRegisterImmediate( | ... | @@ -1513,6 +1525,7 @@ fn asmRegisterRegisterImmediate( |
| 1513 | .i = switch (imm) { | 1525 | .i = switch (imm) { |
| 1514 | .signed => |s| @bitCast(s), | 1526 | .signed => |s| @bitCast(s), |
| 1515 | .unsigned => |u| @intCast(u), | 1527 | .unsigned => |u| @intCast(u), |
| 1528 | .reloc => unreachable, | ||
| 1516 | }, | 1529 | }, |
| 1517 | } }, | 1530 | } }, |
| 1518 | }); | 1531 | }); |
| ... | @@ -1610,6 +1623,7 @@ fn asmRegisterMemoryImmediate( | ... | @@ -1610,6 +1623,7 @@ fn asmRegisterMemoryImmediate( |
| 1610 | if (switch (imm) { | 1623 | if (switch (imm) { |
| 1611 | .signed => |s| if (math.cast(i16, s)) |x| @as(u16, @bitCast(x)) else null, | 1624 | .signed => |s| if (math.cast(i16, s)) |x| @as(u16, @bitCast(x)) else null, |
| 1612 | .unsigned => |u| math.cast(u16, u), | 1625 | .unsigned => |u| math.cast(u16, u), |
| 1626 | .reloc => unreachable, | ||
| 1613 | }) |small_imm| { | 1627 | }) |small_imm| { |
| 1614 | _ = try self.addInst(.{ | 1628 | _ = try self.addInst(.{ |
| 1615 | .tag = tag[1], | 1629 | .tag = tag[1], |
| ... | @@ -1625,6 +1639,7 @@ fn asmRegisterMemoryImmediate( | ... | @@ -1625,6 +1639,7 @@ fn asmRegisterMemoryImmediate( |
| 1625 | const payload = try self.addExtra(Mir.Imm32{ .imm = switch (imm) { | 1639 | const payload = try self.addExtra(Mir.Imm32{ .imm = switch (imm) { |
| 1626 | .signed => |s| @bitCast(s), | 1640 | .signed => |s| @bitCast(s), |
| 1627 | .unsigned => unreachable, | 1641 | .unsigned => unreachable, |
| 1642 | .reloc => unreachable, | ||
| 1628 | } }); | 1643 | } }); |
| 1629 | assert(payload + 1 == try self.addExtra(Mir.Memory.encode(m))); | 1644 | assert(payload + 1 == try self.addExtra(Mir.Memory.encode(m))); |
| 1630 | _ = try self.addInst(.{ | 1645 | _ = try self.addInst(.{ |
| ... | @@ -1632,6 +1647,7 @@ fn asmRegisterMemoryImmediate( | ... | @@ -1632,6 +1647,7 @@ fn asmRegisterMemoryImmediate( |
| 1632 | .ops = switch (imm) { | 1647 | .ops = switch (imm) { |
| 1633 | .signed => .rmi_s, | 1648 | .signed => .rmi_s, |
| 1634 | .unsigned => .rmi_u, | 1649 | .unsigned => .rmi_u, |
| 1650 | .reloc => unreachable, | ||
| 1635 | }, | 1651 | }, |
| 1636 | .data = .{ .rx = .{ | 1652 | .data = .{ .rx = .{ |
| 1637 | .fixes = tag[0], | 1653 | .fixes = tag[0], |
| ... | @@ -1679,6 +1695,7 @@ fn asmMemoryImmediate(self: *Self, tag: Mir.Inst.FixedTag, m: Memory, imm: Immed | ... | @@ -1679,6 +1695,7 @@ fn asmMemoryImmediate(self: *Self, tag: Mir.Inst.FixedTag, m: Memory, imm: Immed |
| 1679 | const payload = try self.addExtra(Mir.Imm32{ .imm = switch (imm) { | 1695 | const payload = try self.addExtra(Mir.Imm32{ .imm = switch (imm) { |
| 1680 | .signed => |s| @bitCast(s), | 1696 | .signed => |s| @bitCast(s), |
| 1681 | .unsigned => |u| @intCast(u), | 1697 | .unsigned => |u| @intCast(u), |
| 1698 | .reloc => unreachable, | ||
| 1682 | } }); | 1699 | } }); |
| 1683 | assert(payload + 1 == try self.addExtra(Mir.Memory.encode(m))); | 1700 | assert(payload + 1 == try self.addExtra(Mir.Memory.encode(m))); |
| 1684 | _ = try self.addInst(.{ | 1701 | _ = try self.addInst(.{ |
| ... | @@ -1686,6 +1703,7 @@ fn asmMemoryImmediate(self: *Self, tag: Mir.Inst.FixedTag, m: Memory, imm: Immed | ... | @@ -1686,6 +1703,7 @@ fn asmMemoryImmediate(self: *Self, tag: Mir.Inst.FixedTag, m: Memory, imm: Immed |
| 1686 | .ops = switch (imm) { | 1703 | .ops = switch (imm) { |
| 1687 | .signed => .mi_s, | 1704 | .signed => .mi_s, |
| 1688 | .unsigned => .mi_u, | 1705 | .unsigned => .mi_u, |
| 1706 | .reloc => unreachable, | ||
| 1689 | }, | 1707 | }, |
| 1690 | .data = .{ .x = .{ | 1708 | .data = .{ .x = .{ |
| 1691 | .fixes = tag[0], | 1709 | .fixes = tag[0], |
| ... | @@ -12310,33 +12328,10 @@ fn genCall(self: *Self, info: union(enum) { | ... | @@ -12310,33 +12328,10 @@ fn genCall(self: *Self, info: union(enum) { |
| 12310 | if (self.bin_file.cast(.elf)) |elf_file| { | 12328 | if (self.bin_file.cast(.elf)) |elf_file| { |
| 12311 | const zo = elf_file.zigObjectPtr().?; | 12329 | const zo = elf_file.zigObjectPtr().?; |
| 12312 | const sym_index = try zo.getOrCreateMetadataForNav(elf_file, func.owner_nav); | 12330 | const sym_index = try zo.getOrCreateMetadataForNav(elf_file, func.owner_nav); |
| 12313 | if (self.mod.pic) { | 12331 | try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ |
| 12314 | const callee_reg: Register = switch (resolved_cc) { | 12332 | .atom_index = try self.owner.getSymbolIndex(self), |
| 12315 | .SysV => callee: { | 12333 | .sym_index = sym_index, |
| 12316 | if (!fn_info.is_var_args) break :callee .rax; | 12334 | })); |
| 12317 | const param_regs = abi.getCAbiIntParamRegs(resolved_cc); | ||
| 12318 | break :callee if (call_info.gp_count < param_regs.len) | ||
| 12319 | param_regs[call_info.gp_count] | ||
| 12320 | else | ||
| 12321 | .r10; | ||
| 12322 | }, | ||
| 12323 | .Win64 => .rax, | ||
| 12324 | else => unreachable, | ||
| 12325 | }; | ||
| 12326 | try self.genSetReg( | ||
| 12327 | callee_reg, | ||
| 12328 | Type.usize, | ||
| 12329 | .{ .load_symbol = .{ .sym = sym_index } }, | ||
| 12330 | .{}, | ||
| 12331 | ); | ||
| 12332 | try self.asmRegister(.{ ._, .call }, callee_reg); | ||
| 12333 | } else try self.asmMemory(.{ ._, .call }, .{ | ||
| 12334 | .base = .{ .reloc = .{ | ||
| 12335 | .atom_index = try self.owner.getSymbolIndex(self), | ||
| 12336 | .sym_index = sym_index, | ||
| 12337 | } }, | ||
| 12338 | .mod = .{ .rm = .{ .size = .qword } }, | ||
| 12339 | }); | ||
| 12340 | } else if (self.bin_file.cast(.coff)) |coff_file| { | 12335 | } else if (self.bin_file.cast(.coff)) |coff_file| { |
| 12341 | const atom = try coff_file.getOrCreateAtomForNav(func.owner_nav); | 12336 | const atom = try coff_file.getOrCreateAtomForNav(func.owner_nav); |
| 12342 | const sym_index = coff_file.getAtom(atom).getSymbolIndex().?; | 12337 | const sym_index = coff_file.getAtom(atom).getSymbolIndex().?; |
| ... | @@ -12365,7 +12360,16 @@ fn genCall(self: *Self, info: union(enum) { | ... | @@ -12365,7 +12360,16 @@ fn genCall(self: *Self, info: union(enum) { |
| 12365 | }); | 12360 | }); |
| 12366 | } else unreachable; | 12361 | } else unreachable; |
| 12367 | }, | 12362 | }, |
| 12368 | .@"extern" => |@"extern"| try self.genExternSymbolRef( | 12363 | .@"extern" => |@"extern"| if (self.bin_file.cast(.elf)) |elf_file| { |
| 12364 | const target_sym_index = try elf_file.getGlobalSymbol( | ||
| 12365 | @"extern".name.toSlice(ip), | ||
| 12366 | @"extern".lib_name.toSlice(ip), | ||
| 12367 | ); | ||
| 12368 | try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ | ||
| 12369 | .atom_index = try self.owner.getSymbolIndex(self), | ||
| 12370 | .sym_index = target_sym_index, | ||
| 12371 | })); | ||
| 12372 | } else try self.genExternSymbolRef( | ||
| 12369 | .call, | 12373 | .call, |
| 12370 | @"extern".lib_name.toSlice(ip), | 12374 | @"extern".lib_name.toSlice(ip), |
| 12371 | @"extern".name.toSlice(ip), | 12375 | @"extern".name.toSlice(ip), |
| ... | @@ -12377,7 +12381,13 @@ fn genCall(self: *Self, info: union(enum) { | ... | @@ -12377,7 +12381,13 @@ fn genCall(self: *Self, info: union(enum) { |
| 12377 | try self.genSetReg(.rax, Type.usize, .{ .air_ref = callee }, .{}); | 12381 | try self.genSetReg(.rax, Type.usize, .{ .air_ref = callee }, .{}); |
| 12378 | try self.asmRegister(.{ ._, .call }, .rax); | 12382 | try self.asmRegister(.{ ._, .call }, .rax); |
| 12379 | }, | 12383 | }, |
| 12380 | .lib => |lib| try self.genExternSymbolRef(.call, lib.lib, lib.callee), | 12384 | .lib => |lib| if (self.bin_file.cast(.elf)) |elf_file| { |
| 12385 | const target_sym_index = try elf_file.getGlobalSymbol(lib.callee, lib.lib); | ||
| 12386 | try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ | ||
| 12387 | .atom_index = try self.owner.getSymbolIndex(self), | ||
| 12388 | .sym_index = target_sym_index, | ||
| 12389 | })); | ||
| 12390 | } else try self.genExternSymbolRef(.call, lib.lib, lib.callee), | ||
| 12381 | } | 12391 | } |
| 12382 | return call_info.return_value.short; | 12392 | return call_info.return_value.short; |
| 12383 | } | 12393 | } |
| ... | @@ -14096,8 +14106,8 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -14096,8 +14106,8 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 14096 | .{ .reg = try self.copyToTmpRegister(Type.usize, .{ .lea_got = sym_index }) } | 14106 | .{ .reg = try self.copyToTmpRegister(Type.usize, .{ .lea_got = sym_index }) } |
| 14097 | else | 14107 | else |
| 14098 | return self.fail("invalid modifier: '{s}'", .{modifier}), | 14108 | return self.fail("invalid modifier: '{s}'", .{modifier}), |
| 14099 | .load_symbol => |sym_off| if (mem.eql(u8, modifier, "P")) | 14109 | .lea_symbol => |sym_off| if (mem.eql(u8, modifier, "P")) |
| 14100 | .{ .reg = try self.copyToTmpRegister(Type.usize, .{ .load_symbol = sym_off }) } | 14110 | .{ .reg = try self.copyToTmpRegister(Type.usize, .{ .lea_symbol = sym_off }) } |
| 14101 | else | 14111 | else |
| 14102 | return self.fail("invalid modifier: '{s}'", .{modifier}), | 14112 | return self.fail("invalid modifier: '{s}'", .{modifier}), |
| 14103 | else => return self.fail("invalid constraint: '{s}'", .{op_str}), | 14113 | else => return self.fail("invalid constraint: '{s}'", .{op_str}), |
| ... | @@ -15253,16 +15263,7 @@ fn genExternSymbolRef( | ... | @@ -15253,16 +15263,7 @@ fn genExternSymbolRef( |
| 15253 | callee: []const u8, | 15263 | callee: []const u8, |
| 15254 | ) InnerError!void { | 15264 | ) InnerError!void { |
| 15255 | const atom_index = try self.owner.getSymbolIndex(self); | 15265 | const atom_index = try self.owner.getSymbolIndex(self); |
| 15256 | if (self.bin_file.cast(.elf)) |elf_file| { | 15266 | if (self.bin_file.cast(.coff)) |coff_file| { |
| 15257 | _ = try self.addInst(.{ | ||
| 15258 | .tag = tag, | ||
| 15259 | .ops = .extern_fn_reloc, | ||
| 15260 | .data = .{ .reloc = .{ | ||
| 15261 | .atom_index = atom_index, | ||
| 15262 | .sym_index = try elf_file.getGlobalSymbol(callee, lib), | ||
| 15263 | } }, | ||
| 15264 | }); | ||
| 15265 | } else if (self.bin_file.cast(.coff)) |coff_file| { | ||
| 15266 | const global_index = try coff_file.getGlobalSymbol(callee, lib); | 15267 | const global_index = try coff_file.getGlobalSymbol(callee, lib); |
| 15267 | _ = try self.addInst(.{ | 15268 | _ = try self.addInst(.{ |
| 15268 | .tag = .mov, | 15269 | .tag = .mov, |
| ... | @@ -15306,7 +15307,7 @@ fn genLazySymbolRef( | ... | @@ -15306,7 +15307,7 @@ fn genLazySymbolRef( |
| 15306 | if (self.mod.pic) { | 15307 | if (self.mod.pic) { |
| 15307 | switch (tag) { | 15308 | switch (tag) { |
| 15308 | .lea, .call => try self.genSetReg(reg, Type.usize, .{ | 15309 | .lea, .call => try self.genSetReg(reg, Type.usize, .{ |
| 15309 | .load_symbol = .{ .sym = sym_index }, | 15310 | .lea_symbol = .{ .sym = sym_index }, |
| 15310 | }, .{}), | 15311 | }, .{}), |
| 15311 | .mov => try self.genSetReg(reg, Type.usize, .{ | 15312 | .mov => try self.genSetReg(reg, Type.usize, .{ |
| 15312 | .load_symbol = .{ .sym = sym_index }, | 15313 | .load_symbol = .{ .sym = sym_index }, |
| ... | @@ -15324,14 +15325,11 @@ fn genLazySymbolRef( | ... | @@ -15324,14 +15325,11 @@ fn genLazySymbolRef( |
| 15324 | .sym_index = sym_index, | 15325 | .sym_index = sym_index, |
| 15325 | }; | 15326 | }; |
| 15326 | switch (tag) { | 15327 | switch (tag) { |
| 15327 | .lea, .mov => try self.asmRegisterMemory(.{ ._, .mov }, reg.to64(), .{ | 15328 | .lea, .mov => try self.asmRegisterMemory(.{ ._, tag }, reg.to64(), .{ |
| 15328 | .base = .{ .reloc = reloc }, | ||
| 15329 | .mod = .{ .rm = .{ .size = .qword } }, | ||
| 15330 | }), | ||
| 15331 | .call => try self.asmMemory(.{ ._, .call }, .{ | ||
| 15332 | .base = .{ .reloc = reloc }, | 15329 | .base = .{ .reloc = reloc }, |
| 15333 | .mod = .{ .rm = .{ .size = .qword } }, | 15330 | .mod = .{ .rm = .{ .size = .qword } }, |
| 15334 | }), | 15331 | }), |
| 15332 | .call => try self.asmImmediate(.{ ._, .call }, Immediate.rel(reloc)), | ||
| 15335 | else => unreachable, | 15333 | else => unreachable, |
| 15336 | } | 15334 | } |
| 15337 | } | 15335 | } |
| ... | @@ -18790,6 +18788,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue { | ... | @@ -18790,6 +18788,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue { |
| 18790 | .immediate => |imm| .{ .immediate = imm }, | 18788 | .immediate => |imm| .{ .immediate = imm }, |
| 18791 | .memory => |addr| .{ .memory = addr }, | 18789 | .memory => |addr| .{ .memory = addr }, |
| 18792 | .load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } }, | 18790 | .load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } }, |
| 18791 | .lea_symbol => |sym_index| .{ .lea_symbol = .{ .sym = sym_index } }, | ||
| 18793 | .load_direct => |sym_index| .{ .load_direct = sym_index }, | 18792 | .load_direct => |sym_index| .{ .load_direct = sym_index }, |
| 18794 | .load_got => |sym_index| .{ .lea_got = sym_index }, | 18793 | .load_got => |sym_index| .{ .lea_got = sym_index }, |
| 18795 | .load_tlv => |sym_index| .{ .lea_tlv = sym_index }, | 18794 | .load_tlv => |sym_index| .{ .lea_tlv = sym_index }, |
src/arch/x86_64/Disassembler.zig+1-1| ... | @@ -8,7 +8,7 @@ const bits = @import("bits.zig"); | ... | @@ -8,7 +8,7 @@ const bits = @import("bits.zig"); |
| 8 | const encoder = @import("encoder.zig"); | 8 | const encoder = @import("encoder.zig"); |
| 9 | 9 | ||
| 10 | const Encoding = @import("Encoding.zig"); | 10 | const Encoding = @import("Encoding.zig"); |
| 11 | const Immediate = bits.Immediate; | 11 | const Immediate = Instruction.Immediate; |
| 12 | const Instruction = encoder.Instruction; | 12 | const Instruction = encoder.Instruction; |
| 13 | const LegacyPrefixes = encoder.LegacyPrefixes; | 13 | const LegacyPrefixes = encoder.LegacyPrefixes; |
| 14 | const Memory = Instruction.Memory; | 14 | const Memory = Instruction.Memory; |
src/arch/x86_64/Emit.zig+10-33| ... | @@ -110,21 +110,11 @@ pub fn emitMir(emit: *Emit) Error!void { | ... | @@ -110,21 +110,11 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 110 | }); | 110 | }); |
| 111 | }, | 111 | }, |
| 112 | .linker_reloc => |data| if (emit.lower.bin_file.cast(.elf)) |elf_file| { | 112 | .linker_reloc => |data| if (emit.lower.bin_file.cast(.elf)) |elf_file| { |
| 113 | const is_obj_or_static_lib = switch (emit.lower.output_mode) { | ||
| 114 | .Exe => false, | ||
| 115 | .Obj => true, | ||
| 116 | .Lib => emit.lower.link_mode == .static, | ||
| 117 | }; | ||
| 118 | const zo = elf_file.zigObjectPtr().?; | 113 | const zo = elf_file.zigObjectPtr().?; |
| 119 | const atom = zo.symbol(data.atom_index).atom(elf_file).?; | 114 | const atom = zo.symbol(data.atom_index).atom(elf_file).?; |
| 120 | const sym = zo.symbol(data.sym_index); | 115 | const sym = zo.symbol(data.sym_index); |
| 121 | if (sym.flags.needs_zig_got and !is_obj_or_static_lib) { | ||
| 122 | _ = try sym.getOrCreateZigGotEntry(data.sym_index, elf_file); | ||
| 123 | } | ||
| 124 | if (emit.lower.pic) { | 116 | if (emit.lower.pic) { |
| 125 | const r_type: u32 = if (sym.flags.needs_zig_got and !is_obj_or_static_lib) | 117 | const r_type: u32 = if (sym.flags.is_extern_ptr) |
| 126 | link.File.Elf.R_ZIG_GOTPCREL | ||
| 127 | else if (sym.flags.needs_got) | ||
| 128 | @intFromEnum(std.elf.R_X86_64.GOTPCREL) | 118 | @intFromEnum(std.elf.R_X86_64.GOTPCREL) |
| 129 | else | 119 | else |
| 130 | @intFromEnum(std.elf.R_X86_64.PC32); | 120 | @intFromEnum(std.elf.R_X86_64.PC32); |
| ... | @@ -134,28 +124,15 @@ pub fn emitMir(emit: *Emit) Error!void { | ... | @@ -134,28 +124,15 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 134 | .r_addend = -4, | 124 | .r_addend = -4, |
| 135 | }); | 125 | }); |
| 136 | } else { | 126 | } else { |
| 137 | if (lowered_inst.encoding.mnemonic == .call and sym.flags.needs_zig_got and is_obj_or_static_lib) { | 127 | const r_type: u32 = if (sym.flags.is_tls) |
| 138 | const r_type = @intFromEnum(std.elf.R_X86_64.PC32); | 128 | @intFromEnum(std.elf.R_X86_64.TPOFF32) |
| 139 | try atom.addReloc(elf_file, .{ | 129 | else |
| 140 | .r_offset = end_offset - 4, | 130 | @intFromEnum(std.elf.R_X86_64.@"32"); |
| 141 | .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | r_type, | 131 | try atom.addReloc(elf_file, .{ |
| 142 | .r_addend = -4, | 132 | .r_offset = end_offset - 4, |
| 143 | }); | 133 | .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | r_type, |
| 144 | } else { | 134 | .r_addend = 0, |
| 145 | const r_type: u32 = if (sym.flags.needs_zig_got and !is_obj_or_static_lib) | 135 | }); |
| 146 | link.File.Elf.R_ZIG_GOT32 | ||
| 147 | else if (sym.flags.needs_got) | ||
| 148 | @intFromEnum(std.elf.R_X86_64.GOT32) | ||
| 149 | else if (sym.flags.is_tls) | ||
| 150 | @intFromEnum(std.elf.R_X86_64.TPOFF32) | ||
| 151 | else | ||
| 152 | @intFromEnum(std.elf.R_X86_64.@"32"); | ||
| 153 | try atom.addReloc(elf_file, .{ | ||
| 154 | .r_offset = end_offset - 4, | ||
| 155 | .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | r_type, | ||
| 156 | .r_addend = 0, | ||
| 157 | }); | ||
| 158 | } | ||
| 159 | } | 136 | } |
| 160 | } else if (emit.lower.bin_file.cast(.macho)) |macho_file| { | 137 | } else if (emit.lower.bin_file.cast(.macho)) |macho_file| { |
| 161 | const is_obj_or_static_lib = switch (emit.lower.output_mode) { | 138 | const is_obj_or_static_lib = switch (emit.lower.output_mode) { |
src/arch/x86_64/Lower.zig+22-15| ... | @@ -397,33 +397,40 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) | ... | @@ -397,33 +397,40 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) |
| 397 | } | 397 | } |
| 398 | 398 | ||
| 399 | _ = lower.reloc(.{ .linker_reloc = sym }); | 399 | _ = lower.reloc(.{ .linker_reloc = sym }); |
| 400 | break :op if (lower.pic) switch (mnemonic) { | 400 | if (lower.pic) switch (mnemonic) { |
| 401 | .lea => { | 401 | .lea => { |
| 402 | if (elf_sym.flags.is_extern_ptr) emit_mnemonic = .mov; | ||
| 402 | break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) }; | 403 | break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) }; |
| 403 | }, | 404 | }, |
| 404 | .mov => { | 405 | .mov => { |
| 405 | if (is_obj_or_static_lib and elf_sym.flags.needs_zig_got) emit_mnemonic = .lea; | 406 | if (elf_sym.flags.is_extern_ptr) { |
| 407 | const reg = ops[0].reg; | ||
| 408 | lower.result_insts[lower.result_insts_len] = | ||
| 409 | try Instruction.new(.none, .mov, &[_]Operand{ | ||
| 410 | .{ .reg = reg.to64() }, | ||
| 411 | .{ .mem = Memory.rip(.qword, 0) }, | ||
| 412 | }); | ||
| 413 | lower.result_insts_len += 1; | ||
| 414 | break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ .base = .{ | ||
| 415 | .reg = reg.to64(), | ||
| 416 | } }) }; | ||
| 417 | } | ||
| 406 | break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) }; | 418 | break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) }; |
| 407 | }, | 419 | }, |
| 408 | else => unreachable, | 420 | else => unreachable, |
| 409 | } else switch (mnemonic) { | 421 | } else switch (mnemonic) { |
| 410 | .call => break :op if (is_obj_or_static_lib and elf_sym.flags.needs_zig_got) .{ | 422 | .call => break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ |
| 411 | .imm = Immediate.s(0), | ||
| 412 | } else .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ | ||
| 413 | .base = .{ .reg = .ds }, | 423 | .base = .{ .reg = .ds }, |
| 414 | }) }, | 424 | }) }, |
| 415 | .lea => { | 425 | .lea => { |
| 416 | emit_mnemonic = .mov; | 426 | emit_mnemonic = .mov; |
| 417 | break :op .{ .imm = Immediate.s(0) }; | 427 | break :op .{ .imm = Immediate.s(0) }; |
| 418 | }, | 428 | }, |
| 419 | .mov => { | 429 | .mov => break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ |
| 420 | if (is_obj_or_static_lib and elf_sym.flags.needs_zig_got) emit_mnemonic = .lea; | 430 | .base = .{ .reg = .ds }, |
| 421 | break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ | 431 | }) }, |
| 422 | .base = .{ .reg = .ds }, | ||
| 423 | }) }; | ||
| 424 | }, | ||
| 425 | else => unreachable, | 432 | else => unreachable, |
| 426 | }; | 433 | } |
| 427 | } else if (lower.bin_file.cast(.macho)) |macho_file| { | 434 | } else if (lower.bin_file.cast(.macho)) |macho_file| { |
| 428 | const zo = macho_file.getZigObject().?; | 435 | const zo = macho_file.getZigObject().?; |
| 429 | const macho_sym = zo.symbols.items[sym.sym_index]; | 436 | const macho_sym = zo.symbols.items[sym.sym_index]; |
| ... | @@ -485,7 +492,7 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void { | ... | @@ -485,7 +492,7 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void { |
| 485 | .rrmi => inst.data.rrix.fixes, | 492 | .rrmi => inst.data.rrix.fixes, |
| 486 | .mi_u, .mi_s => inst.data.x.fixes, | 493 | .mi_u, .mi_s => inst.data.x.fixes, |
| 487 | .m => inst.data.x.fixes, | 494 | .m => inst.data.x.fixes, |
| 488 | .extern_fn_reloc, .got_reloc, .direct_reloc, .import_reloc, .tlv_reloc => ._, | 495 | .extern_fn_reloc, .got_reloc, .direct_reloc, .import_reloc, .tlv_reloc, .rel => ._, |
| 489 | else => return lower.fail("TODO lower .{s}", .{@tagName(inst.ops)}), | 496 | else => return lower.fail("TODO lower .{s}", .{@tagName(inst.ops)}), |
| 490 | }; | 497 | }; |
| 491 | try lower.emit(switch (fixes) { | 498 | try lower.emit(switch (fixes) { |
| ... | @@ -617,7 +624,7 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void { | ... | @@ -617,7 +624,7 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void { |
| 617 | .{ .mem = lower.mem(inst.data.rrix.payload) }, | 624 | .{ .mem = lower.mem(inst.data.rrix.payload) }, |
| 618 | .{ .imm = lower.imm(inst.ops, inst.data.rrix.i) }, | 625 | .{ .imm = lower.imm(inst.ops, inst.data.rrix.i) }, |
| 619 | }, | 626 | }, |
| 620 | .extern_fn_reloc => &.{ | 627 | .extern_fn_reloc, .rel => &.{ |
| 621 | .{ .imm = lower.reloc(.{ .linker_extern_fn = inst.data.reloc }) }, | 628 | .{ .imm = lower.reloc(.{ .linker_extern_fn = inst.data.reloc }) }, |
| 622 | }, | 629 | }, |
| 623 | .got_reloc, .direct_reloc, .import_reloc => ops: { | 630 | .got_reloc, .direct_reloc, .import_reloc => ops: { |
| ... | @@ -660,7 +667,7 @@ const std = @import("std"); | ... | @@ -660,7 +667,7 @@ const std = @import("std"); |
| 660 | const Air = @import("../../Air.zig"); | 667 | const Air = @import("../../Air.zig"); |
| 661 | const Allocator = std.mem.Allocator; | 668 | const Allocator = std.mem.Allocator; |
| 662 | const ErrorMsg = Zcu.ErrorMsg; | 669 | const ErrorMsg = Zcu.ErrorMsg; |
| 663 | const Immediate = bits.Immediate; | 670 | const Immediate = Instruction.Immediate; |
| 664 | const Instruction = encoder.Instruction; | 671 | const Instruction = encoder.Instruction; |
| 665 | const Lower = @This(); | 672 | const Lower = @This(); |
| 666 | const Memory = Instruction.Memory; | 673 | const Memory = Instruction.Memory; |
src/arch/x86_64/Mir.zig+1-1| ... | @@ -769,7 +769,7 @@ pub const Inst = struct { | ... | @@ -769,7 +769,7 @@ pub const Inst = struct { |
| 769 | /// Uses `imm` payload. | 769 | /// Uses `imm` payload. |
| 770 | i_u, | 770 | i_u, |
| 771 | /// Relative displacement operand. | 771 | /// Relative displacement operand. |
| 772 | /// Uses `imm` payload. | 772 | /// Uses `reloc` payload. |
| 773 | rel, | 773 | rel, |
| 774 | /// Register, memory operands. | 774 | /// Register, memory operands. |
| 775 | /// Uses `rx` payload with extra data of type `Memory`. | 775 | /// Uses `rx` payload with extra data of type `Memory`. |
src/arch/x86_64/bits.zig+13-32| ... | @@ -569,6 +569,7 @@ pub const Memory = struct { | ... | @@ -569,6 +569,7 @@ pub const Memory = struct { |
| 569 | pub const Immediate = union(enum) { | 569 | pub const Immediate = union(enum) { |
| 570 | signed: i32, | 570 | signed: i32, |
| 571 | unsigned: u64, | 571 | unsigned: u64, |
| 572 | reloc: Symbol, | ||
| 572 | 573 | ||
| 573 | pub fn u(x: u64) Immediate { | 574 | pub fn u(x: u64) Immediate { |
| 574 | return .{ .unsigned = x }; | 575 | return .{ .unsigned = x }; |
| ... | @@ -578,39 +579,19 @@ pub const Immediate = union(enum) { | ... | @@ -578,39 +579,19 @@ pub const Immediate = union(enum) { |
| 578 | return .{ .signed = x }; | 579 | return .{ .signed = x }; |
| 579 | } | 580 | } |
| 580 | 581 | ||
| 581 | pub fn asSigned(imm: Immediate, bit_size: u64) i64 { | 582 | pub fn rel(symbol: Symbol) Immediate { |
| 582 | return switch (imm) { | 583 | return .{ .reloc = symbol }; |
| 583 | .signed => |x| switch (bit_size) { | ||
| 584 | 1, 8 => @as(i8, @intCast(x)), | ||
| 585 | 16 => @as(i16, @intCast(x)), | ||
| 586 | 32, 64 => x, | ||
| 587 | else => unreachable, | ||
| 588 | }, | ||
| 589 | .unsigned => |x| switch (bit_size) { | ||
| 590 | 1, 8 => @as(i8, @bitCast(@as(u8, @intCast(x)))), | ||
| 591 | 16 => @as(i16, @bitCast(@as(u16, @intCast(x)))), | ||
| 592 | 32 => @as(i32, @bitCast(@as(u32, @intCast(x)))), | ||
| 593 | 64 => @bitCast(x), | ||
| 594 | else => unreachable, | ||
| 595 | }, | ||
| 596 | }; | ||
| 597 | } | 584 | } |
| 598 | 585 | ||
| 599 | pub fn asUnsigned(imm: Immediate, bit_size: u64) u64 { | 586 | pub fn format( |
| 600 | return switch (imm) { | 587 | imm: Immediate, |
| 601 | .signed => |x| switch (bit_size) { | 588 | comptime fmt: []const u8, |
| 602 | 1, 8 => @as(u8, @bitCast(@as(i8, @intCast(x)))), | 589 | options: std.fmt.FormatOptions, |
| 603 | 16 => @as(u16, @bitCast(@as(i16, @intCast(x)))), | 590 | writer: anytype, |
| 604 | 32, 64 => @as(u32, @bitCast(x)), | 591 | ) @TypeOf(writer).Error!void { |
| 605 | else => unreachable, | 592 | switch (imm) { |
| 606 | }, | 593 | .reloc => |x| try std.fmt.formatType(x, fmt, options, writer, 0), |
| 607 | .unsigned => |x| switch (bit_size) { | 594 | inline else => |x| try writer.print("{d}", .{x}), |
| 608 | 1, 8 => @as(u8, @intCast(x)), | 595 | } |
| 609 | 16 => @as(u16, @intCast(x)), | ||
| 610 | 32 => @as(u32, @intCast(x)), | ||
| 611 | 64 => x, | ||
| 612 | else => unreachable, | ||
| 613 | }, | ||
| 614 | }; | ||
| 615 | } | 596 | } |
| 616 | }; | 597 | }; |
src/arch/x86_64/encoder.zig+91-43| ... | @@ -7,7 +7,6 @@ const testing = std.testing; | ... | @@ -7,7 +7,6 @@ const testing = std.testing; |
| 7 | const bits = @import("bits.zig"); | 7 | const bits = @import("bits.zig"); |
| 8 | const Encoding = @import("Encoding.zig"); | 8 | const Encoding = @import("Encoding.zig"); |
| 9 | const FrameIndex = bits.FrameIndex; | 9 | const FrameIndex = bits.FrameIndex; |
| 10 | const Immediate = bits.Immediate; | ||
| 11 | const Register = bits.Register; | 10 | const Register = bits.Register; |
| 12 | const Symbol = bits.Symbol; | 11 | const Symbol = bits.Symbol; |
| 13 | 12 | ||
| ... | @@ -28,6 +27,55 @@ pub const Instruction = struct { | ... | @@ -28,6 +27,55 @@ pub const Instruction = struct { |
| 28 | repnz, | 27 | repnz, |
| 29 | }; | 28 | }; |
| 30 | 29 | ||
| 30 | pub const Immediate = union(enum) { | ||
| 31 | signed: i32, | ||
| 32 | unsigned: u64, | ||
| 33 | |||
| 34 | pub fn u(x: u64) Immediate { | ||
| 35 | return .{ .unsigned = x }; | ||
| 36 | } | ||
| 37 | |||
| 38 | pub fn s(x: i32) Immediate { | ||
| 39 | return .{ .signed = x }; | ||
| 40 | } | ||
| 41 | |||
| 42 | pub fn asSigned(imm: Immediate, bit_size: u64) i64 { | ||
| 43 | return switch (imm) { | ||
| 44 | .signed => |x| switch (bit_size) { | ||
| 45 | 1, 8 => @as(i8, @intCast(x)), | ||
| 46 | 16 => @as(i16, @intCast(x)), | ||
| 47 | 32, 64 => x, | ||
| 48 | else => unreachable, | ||
| 49 | }, | ||
| 50 | .unsigned => |x| switch (bit_size) { | ||
| 51 | 1, 8 => @as(i8, @bitCast(@as(u8, @intCast(x)))), | ||
| 52 | 16 => @as(i16, @bitCast(@as(u16, @intCast(x)))), | ||
| 53 | 32 => @as(i32, @bitCast(@as(u32, @intCast(x)))), | ||
| 54 | 64 => @bitCast(x), | ||
| 55 | else => unreachable, | ||
| 56 | }, | ||
| 57 | }; | ||
| 58 | } | ||
| 59 | |||
| 60 | pub fn asUnsigned(imm: Immediate, bit_size: u64) u64 { | ||
| 61 | return switch (imm) { | ||
| 62 | .signed => |x| switch (bit_size) { | ||
| 63 | 1, 8 => @as(u8, @bitCast(@as(i8, @intCast(x)))), | ||
| 64 | 16 => @as(u16, @bitCast(@as(i16, @intCast(x)))), | ||
| 65 | 32, 64 => @as(u32, @bitCast(x)), | ||
| 66 | else => unreachable, | ||
| 67 | }, | ||
| 68 | .unsigned => |x| switch (bit_size) { | ||
| 69 | 1, 8 => @as(u8, @intCast(x)), | ||
| 70 | 16 => @as(u16, @intCast(x)), | ||
| 71 | 32 => @as(u32, @intCast(x)), | ||
| 72 | 64 => x, | ||
| 73 | else => unreachable, | ||
| 74 | }, | ||
| 75 | }; | ||
| 76 | } | ||
| 77 | }; | ||
| 78 | |||
| 31 | pub const Memory = union(enum) { | 79 | pub const Memory = union(enum) { |
| 32 | sib: Sib, | 80 | sib: Sib, |
| 33 | rip: Rip, | 81 | rip: Rip, |
| ... | @@ -1119,7 +1167,7 @@ test "encode" { | ... | @@ -1119,7 +1167,7 @@ test "encode" { |
| 1119 | 1167 | ||
| 1120 | const inst = try Instruction.new(.none, .mov, &.{ | 1168 | const inst = try Instruction.new(.none, .mov, &.{ |
| 1121 | .{ .reg = .rbx }, | 1169 | .{ .reg = .rbx }, |
| 1122 | .{ .imm = Immediate.u(4) }, | 1170 | .{ .imm = Instruction.Immediate.u(4) }, |
| 1123 | }); | 1171 | }); |
| 1124 | try inst.encode(buf.writer(), .{}); | 1172 | try inst.encode(buf.writer(), .{}); |
| 1125 | try testing.expectEqualSlices(u8, &.{ 0x48, 0xc7, 0xc3, 0x4, 0x0, 0x0, 0x0 }, buf.items); | 1173 | try testing.expectEqualSlices(u8, &.{ 0x48, 0xc7, 0xc3, 0x4, 0x0, 0x0, 0x0 }, buf.items); |
| ... | @@ -1129,47 +1177,47 @@ test "lower I encoding" { | ... | @@ -1129,47 +1177,47 @@ test "lower I encoding" { |
| 1129 | var enc = TestEncode{}; | 1177 | var enc = TestEncode{}; |
| 1130 | 1178 | ||
| 1131 | try enc.encode(.push, &.{ | 1179 | try enc.encode(.push, &.{ |
| 1132 | .{ .imm = Immediate.u(0x10) }, | 1180 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1133 | }); | 1181 | }); |
| 1134 | try expectEqualHexStrings("\x6A\x10", enc.code(), "push 0x10"); | 1182 | try expectEqualHexStrings("\x6A\x10", enc.code(), "push 0x10"); |
| 1135 | 1183 | ||
| 1136 | try enc.encode(.push, &.{ | 1184 | try enc.encode(.push, &.{ |
| 1137 | .{ .imm = Immediate.u(0x1000) }, | 1185 | .{ .imm = Instruction.Immediate.u(0x1000) }, |
| 1138 | }); | 1186 | }); |
| 1139 | try expectEqualHexStrings("\x66\x68\x00\x10", enc.code(), "push 0x1000"); | 1187 | try expectEqualHexStrings("\x66\x68\x00\x10", enc.code(), "push 0x1000"); |
| 1140 | 1188 | ||
| 1141 | try enc.encode(.push, &.{ | 1189 | try enc.encode(.push, &.{ |
| 1142 | .{ .imm = Immediate.u(0x10000000) }, | 1190 | .{ .imm = Instruction.Immediate.u(0x10000000) }, |
| 1143 | }); | 1191 | }); |
| 1144 | try expectEqualHexStrings("\x68\x00\x00\x00\x10", enc.code(), "push 0x10000000"); | 1192 | try expectEqualHexStrings("\x68\x00\x00\x00\x10", enc.code(), "push 0x10000000"); |
| 1145 | 1193 | ||
| 1146 | try enc.encode(.adc, &.{ | 1194 | try enc.encode(.adc, &.{ |
| 1147 | .{ .reg = .rax }, | 1195 | .{ .reg = .rax }, |
| 1148 | .{ .imm = Immediate.u(0x10000000) }, | 1196 | .{ .imm = Instruction.Immediate.u(0x10000000) }, |
| 1149 | }); | 1197 | }); |
| 1150 | try expectEqualHexStrings("\x48\x15\x00\x00\x00\x10", enc.code(), "adc rax, 0x10000000"); | 1198 | try expectEqualHexStrings("\x48\x15\x00\x00\x00\x10", enc.code(), "adc rax, 0x10000000"); |
| 1151 | 1199 | ||
| 1152 | try enc.encode(.add, &.{ | 1200 | try enc.encode(.add, &.{ |
| 1153 | .{ .reg = .al }, | 1201 | .{ .reg = .al }, |
| 1154 | .{ .imm = Immediate.u(0x10) }, | 1202 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1155 | }); | 1203 | }); |
| 1156 | try expectEqualHexStrings("\x04\x10", enc.code(), "add al, 0x10"); | 1204 | try expectEqualHexStrings("\x04\x10", enc.code(), "add al, 0x10"); |
| 1157 | 1205 | ||
| 1158 | try enc.encode(.add, &.{ | 1206 | try enc.encode(.add, &.{ |
| 1159 | .{ .reg = .rax }, | 1207 | .{ .reg = .rax }, |
| 1160 | .{ .imm = Immediate.u(0x10) }, | 1208 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1161 | }); | 1209 | }); |
| 1162 | try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10"); | 1210 | try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10"); |
| 1163 | 1211 | ||
| 1164 | try enc.encode(.sbb, &.{ | 1212 | try enc.encode(.sbb, &.{ |
| 1165 | .{ .reg = .ax }, | 1213 | .{ .reg = .ax }, |
| 1166 | .{ .imm = Immediate.u(0x10) }, | 1214 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1167 | }); | 1215 | }); |
| 1168 | try expectEqualHexStrings("\x66\x1D\x10\x00", enc.code(), "sbb ax, 0x10"); | 1216 | try expectEqualHexStrings("\x66\x1D\x10\x00", enc.code(), "sbb ax, 0x10"); |
| 1169 | 1217 | ||
| 1170 | try enc.encode(.xor, &.{ | 1218 | try enc.encode(.xor, &.{ |
| 1171 | .{ .reg = .al }, | 1219 | .{ .reg = .al }, |
| 1172 | .{ .imm = Immediate.u(0x10) }, | 1220 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1173 | }); | 1221 | }); |
| 1174 | try expectEqualHexStrings("\x34\x10", enc.code(), "xor al, 0x10"); | 1222 | try expectEqualHexStrings("\x34\x10", enc.code(), "xor al, 0x10"); |
| 1175 | } | 1223 | } |
| ... | @@ -1179,43 +1227,43 @@ test "lower MI encoding" { | ... | @@ -1179,43 +1227,43 @@ test "lower MI encoding" { |
| 1179 | 1227 | ||
| 1180 | try enc.encode(.mov, &.{ | 1228 | try enc.encode(.mov, &.{ |
| 1181 | .{ .reg = .r12 }, | 1229 | .{ .reg = .r12 }, |
| 1182 | .{ .imm = Immediate.u(0x1000) }, | 1230 | .{ .imm = Instruction.Immediate.u(0x1000) }, |
| 1183 | }); | 1231 | }); |
| 1184 | try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000"); | 1232 | try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000"); |
| 1185 | 1233 | ||
| 1186 | try enc.encode(.mov, &.{ | 1234 | try enc.encode(.mov, &.{ |
| 1187 | .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .r12 } }) }, | 1235 | .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .r12 } }) }, |
| 1188 | .{ .imm = Immediate.u(0x10) }, | 1236 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1189 | }); | 1237 | }); |
| 1190 | try expectEqualHexStrings("\x41\xC6\x04\x24\x10", enc.code(), "mov BYTE PTR [r12], 0x10"); | 1238 | try expectEqualHexStrings("\x41\xC6\x04\x24\x10", enc.code(), "mov BYTE PTR [r12], 0x10"); |
| 1191 | 1239 | ||
| 1192 | try enc.encode(.mov, &.{ | 1240 | try enc.encode(.mov, &.{ |
| 1193 | .{ .reg = .r12 }, | 1241 | .{ .reg = .r12 }, |
| 1194 | .{ .imm = Immediate.u(0x1000) }, | 1242 | .{ .imm = Instruction.Immediate.u(0x1000) }, |
| 1195 | }); | 1243 | }); |
| 1196 | try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000"); | 1244 | try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000"); |
| 1197 | 1245 | ||
| 1198 | try enc.encode(.mov, &.{ | 1246 | try enc.encode(.mov, &.{ |
| 1199 | .{ .reg = .r12 }, | 1247 | .{ .reg = .r12 }, |
| 1200 | .{ .imm = Immediate.u(0x1000) }, | 1248 | .{ .imm = Instruction.Immediate.u(0x1000) }, |
| 1201 | }); | 1249 | }); |
| 1202 | try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000"); | 1250 | try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000"); |
| 1203 | 1251 | ||
| 1204 | try enc.encode(.mov, &.{ | 1252 | try enc.encode(.mov, &.{ |
| 1205 | .{ .reg = .rax }, | 1253 | .{ .reg = .rax }, |
| 1206 | .{ .imm = Immediate.u(0x10) }, | 1254 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1207 | }); | 1255 | }); |
| 1208 | try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", enc.code(), "mov rax, 0x10"); | 1256 | try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", enc.code(), "mov rax, 0x10"); |
| 1209 | 1257 | ||
| 1210 | try enc.encode(.mov, &.{ | 1258 | try enc.encode(.mov, &.{ |
| 1211 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r11 } }) }, | 1259 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r11 } }) }, |
| 1212 | .{ .imm = Immediate.u(0x10) }, | 1260 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1213 | }); | 1261 | }); |
| 1214 | try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", enc.code(), "mov DWORD PTR [r11], 0x10"); | 1262 | try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", enc.code(), "mov DWORD PTR [r11], 0x10"); |
| 1215 | 1263 | ||
| 1216 | try enc.encode(.mov, &.{ | 1264 | try enc.encode(.mov, &.{ |
| 1217 | .{ .mem = Instruction.Memory.rip(.qword, 0x10) }, | 1265 | .{ .mem = Instruction.Memory.rip(.qword, 0x10) }, |
| 1218 | .{ .imm = Immediate.u(0x10) }, | 1266 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1219 | }); | 1267 | }); |
| 1220 | try expectEqualHexStrings( | 1268 | try expectEqualHexStrings( |
| 1221 | "\x48\xC7\x05\x10\x00\x00\x00\x10\x00\x00\x00", | 1269 | "\x48\xC7\x05\x10\x00\x00\x00\x10\x00\x00\x00", |
| ... | @@ -1225,19 +1273,19 @@ test "lower MI encoding" { | ... | @@ -1225,19 +1273,19 @@ test "lower MI encoding" { |
| 1225 | 1273 | ||
| 1226 | try enc.encode(.mov, &.{ | 1274 | try enc.encode(.mov, &.{ |
| 1227 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -8 }) }, | 1275 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -8 }) }, |
| 1228 | .{ .imm = Immediate.u(0x10) }, | 1276 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1229 | }); | 1277 | }); |
| 1230 | try expectEqualHexStrings("\x48\xc7\x45\xf8\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rbp - 8], 0x10"); | 1278 | try expectEqualHexStrings("\x48\xc7\x45\xf8\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rbp - 8], 0x10"); |
| 1231 | 1279 | ||
| 1232 | try enc.encode(.mov, &.{ | 1280 | try enc.encode(.mov, &.{ |
| 1233 | .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -2 }) }, | 1281 | .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -2 }) }, |
| 1234 | .{ .imm = Immediate.s(-16) }, | 1282 | .{ .imm = Instruction.Immediate.s(-16) }, |
| 1235 | }); | 1283 | }); |
| 1236 | try expectEqualHexStrings("\x66\xC7\x45\xFE\xF0\xFF", enc.code(), "mov WORD PTR [rbp - 2], -16"); | 1284 | try expectEqualHexStrings("\x66\xC7\x45\xFE\xF0\xFF", enc.code(), "mov WORD PTR [rbp - 2], -16"); |
| 1237 | 1285 | ||
| 1238 | try enc.encode(.mov, &.{ | 1286 | try enc.encode(.mov, &.{ |
| 1239 | .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .rbp }, .disp = -1 }) }, | 1287 | .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .rbp }, .disp = -1 }) }, |
| 1240 | .{ .imm = Immediate.u(0x10) }, | 1288 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1241 | }); | 1289 | }); |
| 1242 | try expectEqualHexStrings("\xC6\x45\xFF\x10", enc.code(), "mov BYTE PTR [rbp - 1], 0x10"); | 1290 | try expectEqualHexStrings("\xC6\x45\xFF\x10", enc.code(), "mov BYTE PTR [rbp - 1], 0x10"); |
| 1243 | 1291 | ||
| ... | @@ -1247,7 +1295,7 @@ test "lower MI encoding" { | ... | @@ -1247,7 +1295,7 @@ test "lower MI encoding" { |
| 1247 | .disp = 0x10000000, | 1295 | .disp = 0x10000000, |
| 1248 | .scale_index = .{ .scale = 2, .index = .rcx }, | 1296 | .scale_index = .{ .scale = 2, .index = .rcx }, |
| 1249 | }) }, | 1297 | }) }, |
| 1250 | .{ .imm = Immediate.u(0x10) }, | 1298 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1251 | }); | 1299 | }); |
| 1252 | try expectEqualHexStrings( | 1300 | try expectEqualHexStrings( |
| 1253 | "\x48\xC7\x04\x4D\x00\x00\x00\x10\x10\x00\x00\x00", | 1301 | "\x48\xC7\x04\x4D\x00\x00\x00\x10\x10\x00\x00\x00", |
| ... | @@ -1257,43 +1305,43 @@ test "lower MI encoding" { | ... | @@ -1257,43 +1305,43 @@ test "lower MI encoding" { |
| 1257 | 1305 | ||
| 1258 | try enc.encode(.adc, &.{ | 1306 | try enc.encode(.adc, &.{ |
| 1259 | .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .rbp }, .disp = -0x10 }) }, | 1307 | .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .rbp }, .disp = -0x10 }) }, |
| 1260 | .{ .imm = Immediate.u(0x10) }, | 1308 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1261 | }); | 1309 | }); |
| 1262 | try expectEqualHexStrings("\x80\x55\xF0\x10", enc.code(), "adc BYTE PTR [rbp - 0x10], 0x10"); | 1310 | try expectEqualHexStrings("\x80\x55\xF0\x10", enc.code(), "adc BYTE PTR [rbp - 0x10], 0x10"); |
| 1263 | 1311 | ||
| 1264 | try enc.encode(.adc, &.{ | 1312 | try enc.encode(.adc, &.{ |
| 1265 | .{ .mem = Instruction.Memory.rip(.qword, 0) }, | 1313 | .{ .mem = Instruction.Memory.rip(.qword, 0) }, |
| 1266 | .{ .imm = Immediate.u(0x10) }, | 1314 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1267 | }); | 1315 | }); |
| 1268 | try expectEqualHexStrings("\x48\x83\x15\x00\x00\x00\x00\x10", enc.code(), "adc QWORD PTR [rip], 0x10"); | 1316 | try expectEqualHexStrings("\x48\x83\x15\x00\x00\x00\x00\x10", enc.code(), "adc QWORD PTR [rip], 0x10"); |
| 1269 | 1317 | ||
| 1270 | try enc.encode(.adc, &.{ | 1318 | try enc.encode(.adc, &.{ |
| 1271 | .{ .reg = .rax }, | 1319 | .{ .reg = .rax }, |
| 1272 | .{ .imm = Immediate.u(0x10) }, | 1320 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1273 | }); | 1321 | }); |
| 1274 | try expectEqualHexStrings("\x48\x83\xD0\x10", enc.code(), "adc rax, 0x10"); | 1322 | try expectEqualHexStrings("\x48\x83\xD0\x10", enc.code(), "adc rax, 0x10"); |
| 1275 | 1323 | ||
| 1276 | try enc.encode(.add, &.{ | 1324 | try enc.encode(.add, &.{ |
| 1277 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .rdx }, .disp = -8 }) }, | 1325 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .rdx }, .disp = -8 }) }, |
| 1278 | .{ .imm = Immediate.u(0x10) }, | 1326 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1279 | }); | 1327 | }); |
| 1280 | try expectEqualHexStrings("\x83\x42\xF8\x10", enc.code(), "add DWORD PTR [rdx - 8], 0x10"); | 1328 | try expectEqualHexStrings("\x83\x42\xF8\x10", enc.code(), "add DWORD PTR [rdx - 8], 0x10"); |
| 1281 | 1329 | ||
| 1282 | try enc.encode(.add, &.{ | 1330 | try enc.encode(.add, &.{ |
| 1283 | .{ .reg = .rax }, | 1331 | .{ .reg = .rax }, |
| 1284 | .{ .imm = Immediate.u(0x10) }, | 1332 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1285 | }); | 1333 | }); |
| 1286 | try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10"); | 1334 | try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10"); |
| 1287 | 1335 | ||
| 1288 | try enc.encode(.add, &.{ | 1336 | try enc.encode(.add, &.{ |
| 1289 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -0x10 }) }, | 1337 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -0x10 }) }, |
| 1290 | .{ .imm = Immediate.s(-0x10) }, | 1338 | .{ .imm = Instruction.Immediate.s(-0x10) }, |
| 1291 | }); | 1339 | }); |
| 1292 | try expectEqualHexStrings("\x48\x83\x45\xF0\xF0", enc.code(), "add QWORD PTR [rbp - 0x10], -0x10"); | 1340 | try expectEqualHexStrings("\x48\x83\x45\xF0\xF0", enc.code(), "add QWORD PTR [rbp - 0x10], -0x10"); |
| 1293 | 1341 | ||
| 1294 | try enc.encode(.@"and", &.{ | 1342 | try enc.encode(.@"and", &.{ |
| 1295 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) }, | 1343 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) }, |
| 1296 | .{ .imm = Immediate.u(0x10) }, | 1344 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1297 | }); | 1345 | }); |
| 1298 | try expectEqualHexStrings( | 1346 | try expectEqualHexStrings( |
| 1299 | "\x83\x24\x25\x00\x00\x00\x10\x10", | 1347 | "\x83\x24\x25\x00\x00\x00\x10\x10", |
| ... | @@ -1303,7 +1351,7 @@ test "lower MI encoding" { | ... | @@ -1303,7 +1351,7 @@ test "lower MI encoding" { |
| 1303 | 1351 | ||
| 1304 | try enc.encode(.@"and", &.{ | 1352 | try enc.encode(.@"and", &.{ |
| 1305 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .es }, .disp = 0x10000000 }) }, | 1353 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .es }, .disp = 0x10000000 }) }, |
| 1306 | .{ .imm = Immediate.u(0x10) }, | 1354 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1307 | }); | 1355 | }); |
| 1308 | try expectEqualHexStrings( | 1356 | try expectEqualHexStrings( |
| 1309 | "\x26\x83\x24\x25\x00\x00\x00\x10\x10", | 1357 | "\x26\x83\x24\x25\x00\x00\x00\x10\x10", |
| ... | @@ -1313,7 +1361,7 @@ test "lower MI encoding" { | ... | @@ -1313,7 +1361,7 @@ test "lower MI encoding" { |
| 1313 | 1361 | ||
| 1314 | try enc.encode(.@"and", &.{ | 1362 | try enc.encode(.@"and", &.{ |
| 1315 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r12 }, .disp = 0x10000000 }) }, | 1363 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r12 }, .disp = 0x10000000 }) }, |
| 1316 | .{ .imm = Immediate.u(0x10) }, | 1364 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1317 | }); | 1365 | }); |
| 1318 | try expectEqualHexStrings( | 1366 | try expectEqualHexStrings( |
| 1319 | "\x41\x83\xA4\x24\x00\x00\x00\x10\x10", | 1367 | "\x41\x83\xA4\x24\x00\x00\x00\x10\x10", |
| ... | @@ -1323,7 +1371,7 @@ test "lower MI encoding" { | ... | @@ -1323,7 +1371,7 @@ test "lower MI encoding" { |
| 1323 | 1371 | ||
| 1324 | try enc.encode(.sub, &.{ | 1372 | try enc.encode(.sub, &.{ |
| 1325 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r11 }, .disp = 0x10000000 }) }, | 1373 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r11 }, .disp = 0x10000000 }) }, |
| 1326 | .{ .imm = Immediate.u(0x10) }, | 1374 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1327 | }); | 1375 | }); |
| 1328 | try expectEqualHexStrings( | 1376 | try expectEqualHexStrings( |
| 1329 | "\x41\x83\xAB\x00\x00\x00\x10\x10", | 1377 | "\x41\x83\xAB\x00\x00\x00\x10\x10", |
| ... | @@ -1542,14 +1590,14 @@ test "lower RMI encoding" { | ... | @@ -1542,14 +1590,14 @@ test "lower RMI encoding" { |
| 1542 | try enc.encode(.imul, &.{ | 1590 | try enc.encode(.imul, &.{ |
| 1543 | .{ .reg = .r11 }, | 1591 | .{ .reg = .r11 }, |
| 1544 | .{ .reg = .r12 }, | 1592 | .{ .reg = .r12 }, |
| 1545 | .{ .imm = Immediate.s(-2) }, | 1593 | .{ .imm = Instruction.Immediate.s(-2) }, |
| 1546 | }); | 1594 | }); |
| 1547 | try expectEqualHexStrings("\x4D\x6B\xDC\xFE", enc.code(), "imul r11, r12, -2"); | 1595 | try expectEqualHexStrings("\x4D\x6B\xDC\xFE", enc.code(), "imul r11, r12, -2"); |
| 1548 | 1596 | ||
| 1549 | try enc.encode(.imul, &.{ | 1597 | try enc.encode(.imul, &.{ |
| 1550 | .{ .reg = .r11 }, | 1598 | .{ .reg = .r11 }, |
| 1551 | .{ .mem = Instruction.Memory.rip(.qword, -16) }, | 1599 | .{ .mem = Instruction.Memory.rip(.qword, -16) }, |
| 1552 | .{ .imm = Immediate.s(-1024) }, | 1600 | .{ .imm = Instruction.Immediate.s(-1024) }, |
| 1553 | }); | 1601 | }); |
| 1554 | try expectEqualHexStrings( | 1602 | try expectEqualHexStrings( |
| 1555 | "\x4C\x69\x1D\xF0\xFF\xFF\xFF\x00\xFC\xFF\xFF", | 1603 | "\x4C\x69\x1D\xF0\xFF\xFF\xFF\x00\xFC\xFF\xFF", |
| ... | @@ -1560,7 +1608,7 @@ test "lower RMI encoding" { | ... | @@ -1560,7 +1608,7 @@ test "lower RMI encoding" { |
| 1560 | try enc.encode(.imul, &.{ | 1608 | try enc.encode(.imul, &.{ |
| 1561 | .{ .reg = .bx }, | 1609 | .{ .reg = .bx }, |
| 1562 | .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) }, | 1610 | .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) }, |
| 1563 | .{ .imm = Immediate.s(-1024) }, | 1611 | .{ .imm = Instruction.Immediate.s(-1024) }, |
| 1564 | }); | 1612 | }); |
| 1565 | try expectEqualHexStrings( | 1613 | try expectEqualHexStrings( |
| 1566 | "\x66\x69\x5D\xF0\x00\xFC", | 1614 | "\x66\x69\x5D\xF0\x00\xFC", |
| ... | @@ -1571,7 +1619,7 @@ test "lower RMI encoding" { | ... | @@ -1571,7 +1619,7 @@ test "lower RMI encoding" { |
| 1571 | try enc.encode(.imul, &.{ | 1619 | try enc.encode(.imul, &.{ |
| 1572 | .{ .reg = .bx }, | 1620 | .{ .reg = .bx }, |
| 1573 | .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) }, | 1621 | .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) }, |
| 1574 | .{ .imm = Immediate.u(1024) }, | 1622 | .{ .imm = Instruction.Immediate.u(1024) }, |
| 1575 | }); | 1623 | }); |
| 1576 | try expectEqualHexStrings( | 1624 | try expectEqualHexStrings( |
| 1577 | "\x66\x69\x5D\xF0\x00\x04", | 1625 | "\x66\x69\x5D\xF0\x00\x04", |
| ... | @@ -1687,7 +1735,7 @@ test "lower M encoding" { | ... | @@ -1687,7 +1735,7 @@ test "lower M encoding" { |
| 1687 | try expectEqualHexStrings("\x65\xFF\x14\x25\x00\x00\x00\x00", enc.code(), "call gs:0x0"); | 1735 | try expectEqualHexStrings("\x65\xFF\x14\x25\x00\x00\x00\x00", enc.code(), "call gs:0x0"); |
| 1688 | 1736 | ||
| 1689 | try enc.encode(.call, &.{ | 1737 | try enc.encode(.call, &.{ |
| 1690 | .{ .imm = Immediate.s(0) }, | 1738 | .{ .imm = Instruction.Immediate.s(0) }, |
| 1691 | }); | 1739 | }); |
| 1692 | try expectEqualHexStrings("\xE8\x00\x00\x00\x00", enc.code(), "call 0x0"); | 1740 | try expectEqualHexStrings("\xE8\x00\x00\x00\x00", enc.code(), "call 0x0"); |
| 1693 | 1741 | ||
| ... | @@ -1746,7 +1794,7 @@ test "lower OI encoding" { | ... | @@ -1746,7 +1794,7 @@ test "lower OI encoding" { |
| 1746 | 1794 | ||
| 1747 | try enc.encode(.mov, &.{ | 1795 | try enc.encode(.mov, &.{ |
| 1748 | .{ .reg = .rax }, | 1796 | .{ .reg = .rax }, |
| 1749 | .{ .imm = Immediate.u(0x1000000000000000) }, | 1797 | .{ .imm = Instruction.Immediate.u(0x1000000000000000) }, |
| 1750 | }); | 1798 | }); |
| 1751 | try expectEqualHexStrings( | 1799 | try expectEqualHexStrings( |
| 1752 | "\x48\xB8\x00\x00\x00\x00\x00\x00\x00\x10", | 1800 | "\x48\xB8\x00\x00\x00\x00\x00\x00\x00\x10", |
| ... | @@ -1756,7 +1804,7 @@ test "lower OI encoding" { | ... | @@ -1756,7 +1804,7 @@ test "lower OI encoding" { |
| 1756 | 1804 | ||
| 1757 | try enc.encode(.mov, &.{ | 1805 | try enc.encode(.mov, &.{ |
| 1758 | .{ .reg = .r11 }, | 1806 | .{ .reg = .r11 }, |
| 1759 | .{ .imm = Immediate.u(0x1000000000000000) }, | 1807 | .{ .imm = Instruction.Immediate.u(0x1000000000000000) }, |
| 1760 | }); | 1808 | }); |
| 1761 | try expectEqualHexStrings( | 1809 | try expectEqualHexStrings( |
| 1762 | "\x49\xBB\x00\x00\x00\x00\x00\x00\x00\x10", | 1810 | "\x49\xBB\x00\x00\x00\x00\x00\x00\x00\x10", |
| ... | @@ -1766,19 +1814,19 @@ test "lower OI encoding" { | ... | @@ -1766,19 +1814,19 @@ test "lower OI encoding" { |
| 1766 | 1814 | ||
| 1767 | try enc.encode(.mov, &.{ | 1815 | try enc.encode(.mov, &.{ |
| 1768 | .{ .reg = .r11d }, | 1816 | .{ .reg = .r11d }, |
| 1769 | .{ .imm = Immediate.u(0x10000000) }, | 1817 | .{ .imm = Instruction.Immediate.u(0x10000000) }, |
| 1770 | }); | 1818 | }); |
| 1771 | try expectEqualHexStrings("\x41\xBB\x00\x00\x00\x10", enc.code(), "mov r11d, 0x10000000"); | 1819 | try expectEqualHexStrings("\x41\xBB\x00\x00\x00\x10", enc.code(), "mov r11d, 0x10000000"); |
| 1772 | 1820 | ||
| 1773 | try enc.encode(.mov, &.{ | 1821 | try enc.encode(.mov, &.{ |
| 1774 | .{ .reg = .r11w }, | 1822 | .{ .reg = .r11w }, |
| 1775 | .{ .imm = Immediate.u(0x1000) }, | 1823 | .{ .imm = Instruction.Immediate.u(0x1000) }, |
| 1776 | }); | 1824 | }); |
| 1777 | try expectEqualHexStrings("\x66\x41\xBB\x00\x10", enc.code(), "mov r11w, 0x1000"); | 1825 | try expectEqualHexStrings("\x66\x41\xBB\x00\x10", enc.code(), "mov r11w, 0x1000"); |
| 1778 | 1826 | ||
| 1779 | try enc.encode(.mov, &.{ | 1827 | try enc.encode(.mov, &.{ |
| 1780 | .{ .reg = .r11b }, | 1828 | .{ .reg = .r11b }, |
| 1781 | .{ .imm = Immediate.u(0x10) }, | 1829 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1782 | }); | 1830 | }); |
| 1783 | try expectEqualHexStrings("\x41\xB3\x10", enc.code(), "mov r11b, 0x10"); | 1831 | try expectEqualHexStrings("\x41\xB3\x10", enc.code(), "mov r11b, 0x10"); |
| 1784 | } | 1832 | } |
| ... | @@ -1900,7 +1948,7 @@ test "invalid instruction" { | ... | @@ -1900,7 +1948,7 @@ test "invalid instruction" { |
| 1900 | .{ .reg = .r12d }, | 1948 | .{ .reg = .r12d }, |
| 1901 | }); | 1949 | }); |
| 1902 | try invalidInstruction(.push, &.{ | 1950 | try invalidInstruction(.push, &.{ |
| 1903 | .{ .imm = Immediate.u(0x1000000000000000) }, | 1951 | .{ .imm = Instruction.Immediate.u(0x1000000000000000) }, |
| 1904 | }); | 1952 | }); |
| 1905 | } | 1953 | } |
| 1906 | 1954 | ||
| ... | @@ -2213,7 +2261,7 @@ const Assembler = struct { | ... | @@ -2213,7 +2261,7 @@ const Assembler = struct { |
| 2213 | .immediate => { | 2261 | .immediate => { |
| 2214 | const is_neg = if (as.expect(.minus)) |_| true else |_| false; | 2262 | const is_neg = if (as.expect(.minus)) |_| true else |_| false; |
| 2215 | const imm_tok = try as.expect(.numeral); | 2263 | const imm_tok = try as.expect(.numeral); |
| 2216 | const imm: Immediate = if (is_neg) blk: { | 2264 | const imm: Instruction.Immediate = if (is_neg) blk: { |
| 2217 | const imm = try std.fmt.parseInt(i32, as.source(imm_tok), 0); | 2265 | const imm = try std.fmt.parseInt(i32, as.source(imm_tok), 0); |
| 2218 | break :blk .{ .signed = imm * -1 }; | 2266 | break :blk .{ .signed = imm * -1 }; |
| 2219 | } else .{ .unsigned = try std.fmt.parseInt(u64, as.source(imm_tok), 0) }; | 2267 | } else .{ .unsigned = try std.fmt.parseInt(u64, as.source(imm_tok), 0) }; |
src/codegen.zig+6-4| ... | @@ -828,6 +828,9 @@ pub const GenResult = union(enum) { | ... | @@ -828,6 +828,9 @@ pub const GenResult = union(enum) { |
| 828 | /// Reference to memory location but deferred until linker allocated the Decl in memory. | 828 | /// Reference to memory location but deferred until linker allocated the Decl in memory. |
| 829 | /// Traditionally, this corresponds to emitting a relocation in a relocatable object file. | 829 | /// Traditionally, this corresponds to emitting a relocation in a relocatable object file. |
| 830 | load_symbol: u32, | 830 | load_symbol: u32, |
| 831 | /// Reference to memory location but deferred until linker allocated the Decl in memory. | ||
| 832 | /// Traditionally, this corresponds to emitting a relocation in a relocatable object file. | ||
| 833 | lea_symbol: u32, | ||
| 831 | }; | 834 | }; |
| 832 | 835 | ||
| 833 | fn mcv(val: MCValue) GenResult { | 836 | fn mcv(val: MCValue) GenResult { |
| ... | @@ -895,16 +898,15 @@ fn genNavRef( | ... | @@ -895,16 +898,15 @@ fn genNavRef( |
| 895 | if (lf.cast(.elf)) |elf_file| { | 898 | if (lf.cast(.elf)) |elf_file| { |
| 896 | const zo = elf_file.zigObjectPtr().?; | 899 | const zo = elf_file.zigObjectPtr().?; |
| 897 | if (is_extern) { | 900 | if (is_extern) { |
| 898 | // TODO audit this | ||
| 899 | const sym_index = try elf_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip)); | 901 | const sym_index = try elf_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip)); |
| 900 | zo.symbol(sym_index).flags.needs_got = true; | 902 | zo.symbol(sym_index).flags.is_extern_ptr = true; |
| 901 | return GenResult.mcv(.{ .load_symbol = sym_index }); | 903 | return GenResult.mcv(.{ .lea_symbol = sym_index }); |
| 902 | } | 904 | } |
| 903 | const sym_index = try zo.getOrCreateMetadataForNav(elf_file, nav_index); | 905 | const sym_index = try zo.getOrCreateMetadataForNav(elf_file, nav_index); |
| 904 | if (!single_threaded and is_threadlocal) { | 906 | if (!single_threaded and is_threadlocal) { |
| 905 | return GenResult.mcv(.{ .load_tlv = sym_index }); | 907 | return GenResult.mcv(.{ .load_tlv = sym_index }); |
| 906 | } | 908 | } |
| 907 | return GenResult.mcv(.{ .load_symbol = sym_index }); | 909 | return GenResult.mcv(.{ .lea_symbol = sym_index }); |
| 908 | } else if (lf.cast(.macho)) |macho_file| { | 910 | } else if (lf.cast(.macho)) |macho_file| { |
| 909 | const zo = macho_file.getZigObject().?; | 911 | const zo = macho_file.getZigObject().?; |
| 910 | if (is_extern) { | 912 | if (is_extern) { |
src/link/Elf.zig+11-104| ... | @@ -64,9 +64,6 @@ phdrs: std.ArrayListUnmanaged(elf.Elf64_Phdr) = .{}, | ... | @@ -64,9 +64,6 @@ phdrs: std.ArrayListUnmanaged(elf.Elf64_Phdr) = .{}, |
| 64 | /// Tracked loadable segments during incremental linking. | 64 | /// Tracked loadable segments during incremental linking. |
| 65 | /// The index into the program headers of a PT_LOAD program header with Read and Execute flags | 65 | /// The index into the program headers of a PT_LOAD program header with Read and Execute flags |
| 66 | phdr_zig_load_re_index: ?u16 = null, | 66 | phdr_zig_load_re_index: ?u16 = null, |
| 67 | /// The index into the program headers of the global offset table. | ||
| 68 | /// It needs PT_LOAD and Read flags. | ||
| 69 | phdr_zig_got_index: ?u16 = null, | ||
| 70 | /// The index into the program headers of a PT_LOAD program header with Read flag | 67 | /// The index into the program headers of a PT_LOAD program header with Read flag |
| 71 | phdr_zig_load_ro_index: ?u16 = null, | 68 | phdr_zig_load_ro_index: ?u16 = null, |
| 72 | /// The index into the program headers of a PT_LOAD program header with Write flag | 69 | /// The index into the program headers of a PT_LOAD program header with Write flag |
| ... | @@ -130,8 +127,6 @@ plt_got: PltGotSection = .{}, | ... | @@ -130,8 +127,6 @@ plt_got: PltGotSection = .{}, |
| 130 | copy_rel: CopyRelSection = .{}, | 127 | copy_rel: CopyRelSection = .{}, |
| 131 | /// .rela.plt section | 128 | /// .rela.plt section |
| 132 | rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{}, | 129 | rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{}, |
| 133 | /// .got.zig section | ||
| 134 | zig_got: ZigGotSection = .{}, | ||
| 135 | /// SHT_GROUP sections | 130 | /// SHT_GROUP sections |
| 136 | /// Applies only to a relocatable. | 131 | /// Applies only to a relocatable. |
| 137 | comdat_group_sections: std.ArrayListUnmanaged(ComdatGroupSection) = .{}, | 132 | comdat_group_sections: std.ArrayListUnmanaged(ComdatGroupSection) = .{}, |
| ... | @@ -142,7 +137,6 @@ zig_text_section_index: ?u32 = null, | ... | @@ -142,7 +137,6 @@ zig_text_section_index: ?u32 = null, |
| 142 | zig_data_rel_ro_section_index: ?u32 = null, | 137 | zig_data_rel_ro_section_index: ?u32 = null, |
| 143 | zig_data_section_index: ?u32 = null, | 138 | zig_data_section_index: ?u32 = null, |
| 144 | zig_bss_section_index: ?u32 = null, | 139 | zig_bss_section_index: ?u32 = null, |
| 145 | zig_got_section_index: ?u32 = null, | ||
| 146 | 140 | ||
| 147 | debug_info_section_index: ?u32 = null, | 141 | debug_info_section_index: ?u32 = null, |
| 148 | debug_abbrev_section_index: ?u32 = null, | 142 | debug_abbrev_section_index: ?u32 = null, |
| ... | @@ -474,7 +468,6 @@ pub fn deinit(self: *Elf) void { | ... | @@ -474,7 +468,6 @@ pub fn deinit(self: *Elf) void { |
| 474 | self.copy_rel.deinit(gpa); | 468 | self.copy_rel.deinit(gpa); |
| 475 | self.rela_dyn.deinit(gpa); | 469 | self.rela_dyn.deinit(gpa); |
| 476 | self.rela_plt.deinit(gpa); | 470 | self.rela_plt.deinit(gpa); |
| 477 | self.zig_got.deinit(gpa); | ||
| 478 | self.comdat_group_sections.deinit(gpa); | 471 | self.comdat_group_sections.deinit(gpa); |
| 479 | } | 472 | } |
| 480 | 473 | ||
| ... | @@ -611,28 +604,13 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void { | ... | @@ -611,28 +604,13 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void { |
| 611 | .type = elf.PT_LOAD, | 604 | .type = elf.PT_LOAD, |
| 612 | .offset = off, | 605 | .offset = off, |
| 613 | .filesz = filesz, | 606 | .filesz = filesz, |
| 614 | .addr = if (ptr_bit_width >= 32) 0x8000000 else 0x8000, | 607 | .addr = if (ptr_bit_width >= 32) 0x4000000 else 0x4000, |
| 615 | .memsz = filesz, | 608 | .memsz = filesz, |
| 616 | .@"align" = self.page_size, | 609 | .@"align" = self.page_size, |
| 617 | .flags = elf.PF_X | elf.PF_R | elf.PF_W, | 610 | .flags = elf.PF_X | elf.PF_R | elf.PF_W, |
| 618 | }); | 611 | }); |
| 619 | } | 612 | } |
| 620 | 613 | ||
| 621 | if (self.phdr_zig_got_index == null) { | ||
| 622 | const alignment = self.page_size; | ||
| 623 | const filesz = @as(u64, ptr_size) * options.symbol_count_hint; | ||
| 624 | const off = self.findFreeSpace(filesz, alignment); | ||
| 625 | self.phdr_zig_got_index = try self.addPhdr(.{ | ||
| 626 | .type = elf.PT_LOAD, | ||
| 627 | .offset = off, | ||
| 628 | .filesz = filesz, | ||
| 629 | .addr = if (ptr_bit_width >= 32) 0x4000000 else 0x4000, | ||
| 630 | .memsz = filesz, | ||
| 631 | .@"align" = alignment, | ||
| 632 | .flags = elf.PF_R | elf.PF_W, | ||
| 633 | }); | ||
| 634 | } | ||
| 635 | |||
| 636 | if (self.phdr_zig_load_ro_index == null) { | 614 | if (self.phdr_zig_load_ro_index == null) { |
| 637 | const alignment = self.page_size; | 615 | const alignment = self.page_size; |
| 638 | const filesz: u64 = 1024; | 616 | const filesz: u64 = 1024; |
| ... | @@ -701,27 +679,6 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void { | ... | @@ -701,27 +679,6 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void { |
| 701 | try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_text_section_index.?, .{}); | 679 | try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_text_section_index.?, .{}); |
| 702 | } | 680 | } |
| 703 | 681 | ||
| 704 | if (self.zig_got_section_index == null and !self.base.isRelocatable()) { | ||
| 705 | self.zig_got_section_index = try self.addSection(.{ | ||
| 706 | .name = try self.insertShString(".got.zig"), | ||
| 707 | .type = elf.SHT_PROGBITS, | ||
| 708 | .addralign = ptr_size, | ||
| 709 | .flags = elf.SHF_ALLOC | elf.SHF_WRITE, | ||
| 710 | .offset = std.math.maxInt(u64), | ||
| 711 | }); | ||
| 712 | const shdr = &self.shdrs.items[self.zig_got_section_index.?]; | ||
| 713 | const phndx = self.phdr_zig_got_index.?; | ||
| 714 | const phdr = self.phdrs.items[phndx]; | ||
| 715 | shdr.sh_addr = phdr.p_vaddr; | ||
| 716 | shdr.sh_offset = phdr.p_offset; | ||
| 717 | shdr.sh_size = phdr.p_memsz; | ||
| 718 | try self.phdr_to_shdr_table.putNoClobber( | ||
| 719 | gpa, | ||
| 720 | self.zig_got_section_index.?, | ||
| 721 | self.phdr_zig_got_index.?, | ||
| 722 | ); | ||
| 723 | } | ||
| 724 | |||
| 725 | if (self.zig_data_rel_ro_section_index == null) { | 682 | if (self.zig_data_rel_ro_section_index == null) { |
| 726 | self.zig_data_rel_ro_section_index = try self.addSection(.{ | 683 | self.zig_data_rel_ro_section_index = try self.addSection(.{ |
| 727 | .name = try self.insertShString(".data.rel.ro.zig"), | 684 | .name = try self.insertShString(".data.rel.ro.zig"), |
| ... | @@ -900,6 +857,11 @@ pub fn growAllocSection(self: *Elf, shdr_index: u32, needed_size: u64) !void { | ... | @@ -900,6 +857,11 @@ pub fn growAllocSection(self: *Elf, shdr_index: u32, needed_size: u64) !void { |
| 900 | const shdr = &self.shdrs.items[shdr_index]; | 857 | const shdr = &self.shdrs.items[shdr_index]; |
| 901 | const maybe_phdr = if (self.phdr_to_shdr_table.get(shdr_index)) |phndx| &self.phdrs.items[phndx] else null; | 858 | const maybe_phdr = if (self.phdr_to_shdr_table.get(shdr_index)) |phndx| &self.phdrs.items[phndx] else null; |
| 902 | const is_zerofill = shdr.sh_type == elf.SHT_NOBITS; | 859 | const is_zerofill = shdr.sh_type == elf.SHT_NOBITS; |
| 860 | log.debug("allocated size {x} of {s}, needed size {x}", .{ | ||
| 861 | self.allocatedSize(shdr.sh_offset), | ||
| 862 | self.getShString(shdr.sh_name), | ||
| 863 | needed_size, | ||
| 864 | }); | ||
| 903 | 865 | ||
| 904 | if (needed_size > self.allocatedSize(shdr.sh_offset) and !is_zerofill) { | 866 | if (needed_size > self.allocatedSize(shdr.sh_offset) and !is_zerofill) { |
| 905 | const existing_size = shdr.sh_size; | 867 | const existing_size = shdr.sh_size; |
| ... | @@ -3156,8 +3118,8 @@ fn initSyntheticSections(self: *Elf) !void { | ... | @@ -3156,8 +3118,8 @@ fn initSyntheticSections(self: *Elf) !void { |
| 3156 | }); | 3118 | }); |
| 3157 | 3119 | ||
| 3158 | const needs_rela_dyn = blk: { | 3120 | const needs_rela_dyn = blk: { |
| 3159 | if (self.got.flags.needs_rela or self.got.flags.needs_tlsld or | 3121 | if (self.got.flags.needs_rela or self.got.flags.needs_tlsld or self.copy_rel.symbols.items.len > 0) |
| 3160 | self.zig_got.flags.needs_rela or self.copy_rel.symbols.items.len > 0) break :blk true; | 3122 | break :blk true; |
| 3161 | if (self.zigObjectPtr()) |zig_object| { | 3123 | if (self.zigObjectPtr()) |zig_object| { |
| 3162 | if (zig_object.num_dynrelocs > 0) break :blk true; | 3124 | if (zig_object.num_dynrelocs > 0) break :blk true; |
| 3163 | } | 3125 | } |
| ... | @@ -3562,7 +3524,6 @@ fn sortPhdrs(self: *Elf) error{OutOfMemory}!void { | ... | @@ -3562,7 +3524,6 @@ fn sortPhdrs(self: *Elf) error{OutOfMemory}!void { |
| 3562 | 3524 | ||
| 3563 | for (&[_]*?u16{ | 3525 | for (&[_]*?u16{ |
| 3564 | &self.phdr_zig_load_re_index, | 3526 | &self.phdr_zig_load_re_index, |
| 3565 | &self.phdr_zig_got_index, | ||
| 3566 | &self.phdr_zig_load_ro_index, | 3527 | &self.phdr_zig_load_ro_index, |
| 3567 | &self.phdr_zig_load_zerofill_index, | 3528 | &self.phdr_zig_load_zerofill_index, |
| 3568 | &self.phdr_table_index, | 3529 | &self.phdr_table_index, |
| ... | @@ -3694,7 +3655,6 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) !void { | ... | @@ -3694,7 +3655,6 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) !void { |
| 3694 | &self.versym_section_index, | 3655 | &self.versym_section_index, |
| 3695 | &self.verneed_section_index, | 3656 | &self.verneed_section_index, |
| 3696 | &self.zig_text_section_index, | 3657 | &self.zig_text_section_index, |
| 3697 | &self.zig_got_section_index, | ||
| 3698 | &self.zig_data_rel_ro_section_index, | 3658 | &self.zig_data_rel_ro_section_index, |
| 3699 | &self.zig_data_section_index, | 3659 | &self.zig_data_section_index, |
| 3700 | &self.zig_bss_section_index, | 3660 | &self.zig_bss_section_index, |
| ... | @@ -3893,7 +3853,7 @@ fn updateSectionSizes(self: *Elf) !void { | ... | @@ -3893,7 +3853,7 @@ fn updateSectionSizes(self: *Elf) !void { |
| 3893 | } | 3853 | } |
| 3894 | 3854 | ||
| 3895 | if (self.rela_dyn_section_index) |shndx| { | 3855 | if (self.rela_dyn_section_index) |shndx| { |
| 3896 | var num = self.got.numRela(self) + self.copy_rel.numRela() + self.zig_got.numRela(); | 3856 | var num = self.got.numRela(self) + self.copy_rel.numRela(); |
| 3897 | if (self.zigObjectPtr()) |zig_object| { | 3857 | if (self.zigObjectPtr()) |zig_object| { |
| 3898 | num += zig_object.num_dynrelocs; | 3858 | num += zig_object.num_dynrelocs; |
| 3899 | } | 3859 | } |
| ... | @@ -4431,15 +4391,6 @@ pub fn updateSymtabSize(self: *Elf) !void { | ... | @@ -4431,15 +4391,6 @@ pub fn updateSymtabSize(self: *Elf) !void { |
| 4431 | strsize += ctx.strsize; | 4391 | strsize += ctx.strsize; |
| 4432 | } | 4392 | } |
| 4433 | 4393 | ||
| 4434 | if (self.zigObjectPtr()) |_| { | ||
| 4435 | if (self.zig_got_section_index) |_| { | ||
| 4436 | self.zig_got.output_symtab_ctx.ilocal = nlocals + 1; | ||
| 4437 | self.zig_got.updateSymtabSize(self); | ||
| 4438 | nlocals += self.zig_got.output_symtab_ctx.nlocals; | ||
| 4439 | strsize += self.zig_got.output_symtab_ctx.strsize; | ||
| 4440 | } | ||
| 4441 | } | ||
| 4442 | |||
| 4443 | if (self.got_section_index) |_| { | 4394 | if (self.got_section_index) |_| { |
| 4444 | self.got.output_symtab_ctx.ilocal = nlocals + 1; | 4395 | self.got.output_symtab_ctx.ilocal = nlocals + 1; |
| 4445 | self.got.updateSymtabSize(self); | 4396 | self.got.updateSymtabSize(self); |
| ... | @@ -4576,9 +4527,6 @@ fn writeSyntheticSections(self: *Elf) !void { | ... | @@ -4576,9 +4527,6 @@ fn writeSyntheticSections(self: *Elf) !void { |
| 4576 | const shdr = self.shdrs.items[shndx]; | 4527 | const shdr = self.shdrs.items[shndx]; |
| 4577 | try self.got.addRela(self); | 4528 | try self.got.addRela(self); |
| 4578 | try self.copy_rel.addRela(self); | 4529 | try self.copy_rel.addRela(self); |
| 4579 | if (self.zigObjectPtr()) |_| { | ||
| 4580 | try self.zig_got.addRela(self); | ||
| 4581 | } | ||
| 4582 | self.sortRelaDyn(); | 4530 | self.sortRelaDyn(); |
| 4583 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.rela_dyn.items), shdr.sh_offset); | 4531 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.rela_dyn.items), shdr.sh_offset); |
| 4584 | } | 4532 | } |
| ... | @@ -4674,10 +4622,6 @@ pub fn writeSymtab(self: *Elf) !void { | ... | @@ -4674,10 +4622,6 @@ pub fn writeSymtab(self: *Elf) !void { |
| 4674 | obj.asFile().writeSymtab(self); | 4622 | obj.asFile().writeSymtab(self); |
| 4675 | } | 4623 | } |
| 4676 | 4624 | ||
| 4677 | if (self.zig_got_section_index) |_| { | ||
| 4678 | self.zig_got.writeSymtab(self); | ||
| 4679 | } | ||
| 4680 | |||
| 4681 | if (self.got_section_index) |_| { | 4625 | if (self.got_section_index) |_| { |
| 4682 | self.got.writeSymtab(self); | 4626 | self.got.writeSymtab(self); |
| 4683 | } | 4627 | } |
| ... | @@ -5085,7 +5029,6 @@ pub fn isZigSection(self: Elf, shndx: u32) bool { | ... | @@ -5085,7 +5029,6 @@ pub fn isZigSection(self: Elf, shndx: u32) bool { |
| 5085 | self.zig_data_rel_ro_section_index, | 5029 | self.zig_data_rel_ro_section_index, |
| 5086 | self.zig_data_section_index, | 5030 | self.zig_data_section_index, |
| 5087 | self.zig_bss_section_index, | 5031 | self.zig_bss_section_index, |
| 5088 | self.zig_got_section_index, | ||
| 5089 | }) |maybe_index| { | 5032 | }) |maybe_index| { |
| 5090 | if (maybe_index) |index| { | 5033 | if (maybe_index) |index| { |
| 5091 | if (index == shndx) return true; | 5034 | if (index == shndx) return true; |
| ... | @@ -5657,10 +5600,11 @@ fn fmtDumpState( | ... | @@ -5657,10 +5600,11 @@ fn fmtDumpState( |
| 5657 | 5600 | ||
| 5658 | if (self.zigObjectPtr()) |zig_object| { | 5601 | if (self.zigObjectPtr()) |zig_object| { |
| 5659 | try writer.print("zig_object({d}) : {s}\n", .{ zig_object.index, zig_object.path }); | 5602 | try writer.print("zig_object({d}) : {s}\n", .{ zig_object.index, zig_object.path }); |
| 5660 | try writer.print("{}{}\n", .{ | 5603 | try writer.print("{}{}", .{ |
| 5661 | zig_object.fmtAtoms(self), | 5604 | zig_object.fmtAtoms(self), |
| 5662 | zig_object.fmtSymtab(self), | 5605 | zig_object.fmtSymtab(self), |
| 5663 | }); | 5606 | }); |
| 5607 | try writer.writeByte('\n'); | ||
| 5664 | } | 5608 | } |
| 5665 | 5609 | ||
| 5666 | for (self.objects.items) |index| { | 5610 | for (self.objects.items) |index| { |
| ... | @@ -5700,7 +5644,6 @@ fn fmtDumpState( | ... | @@ -5700,7 +5644,6 @@ fn fmtDumpState( |
| 5700 | } | 5644 | } |
| 5701 | } | 5645 | } |
| 5702 | 5646 | ||
| 5703 | try writer.print("{}\n", .{self.zig_got.fmt(self)}); | ||
| 5704 | try writer.print("{}\n", .{self.got.fmt(self)}); | 5647 | try writer.print("{}\n", .{self.got.fmt(self)}); |
| 5705 | try writer.print("{}\n", .{self.plt.fmt(self)}); | 5648 | try writer.print("{}\n", .{self.plt.fmt(self)}); |
| 5706 | 5649 | ||
| ... | @@ -5991,41 +5934,6 @@ const RelaSection = struct { | ... | @@ -5991,41 +5934,6 @@ const RelaSection = struct { |
| 5991 | }; | 5934 | }; |
| 5992 | const RelaSectionTable = std.AutoArrayHashMapUnmanaged(u32, RelaSection); | 5935 | const RelaSectionTable = std.AutoArrayHashMapUnmanaged(u32, RelaSection); |
| 5993 | 5936 | ||
| 5994 | pub const R_ZIG_GOT32: u32 = 0xff00; | ||
| 5995 | pub const R_ZIG_GOTPCREL: u32 = 0xff01; | ||
| 5996 | pub const R_ZIG_GOT_HI20: u32 = 0xff02; | ||
| 5997 | pub const R_ZIG_GOT_LO12: u32 = 0xff03; | ||
| 5998 | pub const R_GOT_HI20_STATIC: u32 = 0xff04; | ||
| 5999 | pub const R_GOT_LO12_I_STATIC: u32 = 0xff05; | ||
| 6000 | |||
| 6001 | // Comptime asserts that no Zig relocs overlap with another ISA's reloc number | ||
| 6002 | comptime { | ||
| 6003 | const zig_relocs = .{ | ||
| 6004 | R_ZIG_GOT32, | ||
| 6005 | R_ZIG_GOT_HI20, | ||
| 6006 | R_ZIG_GOT_LO12, | ||
| 6007 | R_ZIG_GOTPCREL, | ||
| 6008 | R_GOT_HI20_STATIC, | ||
| 6009 | R_GOT_LO12_I_STATIC, | ||
| 6010 | }; | ||
| 6011 | |||
| 6012 | const other_relocs = .{ | ||
| 6013 | elf.R_X86_64, | ||
| 6014 | elf.R_AARCH64, | ||
| 6015 | elf.R_RISCV, | ||
| 6016 | elf.R_PPC64, | ||
| 6017 | }; | ||
| 6018 | |||
| 6019 | @setEvalBranchQuota(@min(other_relocs.len * zig_relocs.len * 256, 6200)); | ||
| 6020 | for (other_relocs) |relocs| { | ||
| 6021 | for (@typeInfo(relocs).Enum.fields) |reloc| { | ||
| 6022 | for (zig_relocs) |zig_reloc| { | ||
| 6023 | assert(reloc.value != zig_reloc); | ||
| 6024 | } | ||
| 6025 | } | ||
| 6026 | } | ||
| 6027 | } | ||
| 6028 | |||
| 6029 | fn defaultEntrySymbolName(cpu_arch: std.Target.Cpu.Arch) []const u8 { | 5937 | fn defaultEntrySymbolName(cpu_arch: std.Target.Cpu.Arch) []const u8 { |
| 6030 | return switch (cpu_arch) { | 5938 | return switch (cpu_arch) { |
| 6031 | .mips, .mipsel, .mips64, .mips64el => "__start", | 5939 | .mips, .mipsel, .mips64, .mips64el => "__start", |
| ... | @@ -6095,6 +6003,5 @@ const StringTable = @import("StringTable.zig"); | ... | @@ -6095,6 +6003,5 @@ const StringTable = @import("StringTable.zig"); |
| 6095 | const Thunk = thunks.Thunk; | 6003 | const Thunk = thunks.Thunk; |
| 6096 | const Value = @import("../Value.zig"); | 6004 | const Value = @import("../Value.zig"); |
| 6097 | const VerneedSection = synthetic_sections.VerneedSection; | 6005 | const VerneedSection = synthetic_sections.VerneedSection; |
| 6098 | const ZigGotSection = synthetic_sections.ZigGotSection; | ||
| 6099 | const ZigObject = @import("Elf/ZigObject.zig"); | 6006 | const ZigObject = @import("Elf/ZigObject.zig"); |
| 6100 | const riscv = @import("riscv.zig"); | 6007 | const riscv = @import("riscv.zig"); |
src/link/Elf/Atom.zig+22-81| ... | @@ -746,12 +746,10 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi | ... | @@ -746,12 +746,10 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi |
| 746 | const P = self.address(elf_file) + @as(i64, @intCast(rel.r_offset)); | 746 | const P = self.address(elf_file) + @as(i64, @intCast(rel.r_offset)); |
| 747 | // Addend from the relocation. | 747 | // Addend from the relocation. |
| 748 | const A = rel.r_addend; | 748 | const A = rel.r_addend; |
| 749 | // Address of the target symbol - can be address of the symbol within an atom or address of PLT stub. | 749 | // Address of the target symbol - can be address of the symbol within an atom or address of PLT stub, or address of a Zig trampoline. |
| 750 | const S = target.address(.{}, elf_file); | 750 | const S = target.address(.{}, elf_file); |
| 751 | // Address of the global offset table. | 751 | // Address of the global offset table. |
| 752 | const GOT = elf_file.gotAddress(); | 752 | const GOT = elf_file.gotAddress(); |
| 753 | // Address of the .zig.got table entry if any. | ||
| 754 | const ZIG_GOT = target.zigGotAddress(elf_file); | ||
| 755 | // Relative offset to the start of the global offset table. | 753 | // Relative offset to the start of the global offset table. |
| 756 | const G = target.gotAddress(elf_file) - GOT; | 754 | const G = target.gotAddress(elf_file) - GOT; |
| 757 | // // Address of the thread pointer. | 755 | // // Address of the thread pointer. |
| ... | @@ -759,19 +757,18 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi | ... | @@ -759,19 +757,18 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi |
| 759 | // Address of the dynamic thread pointer. | 757 | // Address of the dynamic thread pointer. |
| 760 | const DTP = elf_file.dtpAddress(); | 758 | const DTP = elf_file.dtpAddress(); |
| 761 | 759 | ||
| 762 | relocs_log.debug(" {s}: {x}: [{x} => {x}] G({x}) ZG({x}) ({s})", .{ | 760 | relocs_log.debug(" {s}: {x}: [{x} => {x}] GOT({x}) ({s})", .{ |
| 763 | relocation.fmtRelocType(rel.r_type(), cpu_arch), | 761 | relocation.fmtRelocType(rel.r_type(), cpu_arch), |
| 764 | r_offset, | 762 | r_offset, |
| 765 | P, | 763 | P, |
| 766 | S + A, | 764 | S + A, |
| 767 | G + GOT + A, | 765 | G + GOT + A, |
| 768 | ZIG_GOT + A, | ||
| 769 | target.name(elf_file), | 766 | target.name(elf_file), |
| 770 | }); | 767 | }); |
| 771 | 768 | ||
| 772 | try stream.seekTo(r_offset); | 769 | try stream.seekTo(r_offset); |
| 773 | 770 | ||
| 774 | const args = ResolveArgs{ P, A, S, GOT, G, TP, DTP, ZIG_GOT }; | 771 | const args = ResolveArgs{ P, A, S, GOT, G, TP, DTP }; |
| 775 | 772 | ||
| 776 | switch (cpu_arch) { | 773 | switch (cpu_arch) { |
| 777 | .x86_64 => x86_64.resolveRelocAlloc(self, elf_file, rel, target, args, &it, code, &stream) catch |err| switch (err) { | 774 | .x86_64 => x86_64.resolveRelocAlloc(self, elf_file, rel, target, args, &it, code, &stream) catch |err| switch (err) { |
| ... | @@ -956,7 +953,7 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any | ... | @@ -956,7 +953,7 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any |
| 956 | // Address of the dynamic thread pointer. | 953 | // Address of the dynamic thread pointer. |
| 957 | const DTP = elf_file.dtpAddress(); | 954 | const DTP = elf_file.dtpAddress(); |
| 958 | 955 | ||
| 959 | const args = ResolveArgs{ P, A, S, GOT, 0, 0, DTP, 0 }; | 956 | const args = ResolveArgs{ P, A, S, GOT, 0, 0, DTP }; |
| 960 | 957 | ||
| 961 | relocs_log.debug(" {}: {x}: [{x} => {x}] ({s})", .{ | 958 | relocs_log.debug(" {}: {x}: [{x} => {x}] ({s})", .{ |
| 962 | relocation.fmtRelocType(rel.r_type(), cpu_arch), | 959 | relocation.fmtRelocType(rel.r_type(), cpu_arch), |
| ... | @@ -1025,7 +1022,7 @@ pub fn format( | ... | @@ -1025,7 +1022,7 @@ pub fn format( |
| 1025 | _ = unused_fmt_string; | 1022 | _ = unused_fmt_string; |
| 1026 | _ = options; | 1023 | _ = options; |
| 1027 | _ = writer; | 1024 | _ = writer; |
| 1028 | @compileError("do not format symbols directly"); | 1025 | @compileError("do not format Atom directly"); |
| 1029 | } | 1026 | } |
| 1030 | 1027 | ||
| 1031 | pub fn fmt(atom: Atom, elf_file: *Elf) std.fmt.Formatter(format2) { | 1028 | pub fn fmt(atom: Atom, elf_file: *Elf) std.fmt.Formatter(format2) { |
| ... | @@ -1051,8 +1048,8 @@ fn format2( | ... | @@ -1051,8 +1048,8 @@ fn format2( |
| 1051 | const atom = ctx.atom; | 1048 | const atom = ctx.atom; |
| 1052 | const elf_file = ctx.elf_file; | 1049 | const elf_file = ctx.elf_file; |
| 1053 | try writer.print("atom({d}) : {s} : @{x} : shdr({d}) : align({x}) : size({x})", .{ | 1050 | try writer.print("atom({d}) : {s} : @{x} : shdr({d}) : align({x}) : size({x})", .{ |
| 1054 | atom.atom_index, atom.name(elf_file), atom.address(elf_file), | 1051 | atom.atom_index, atom.name(elf_file), atom.address(elf_file), |
| 1055 | atom.output_section_index, atom.alignment, atom.size, | 1052 | atom.output_section_index, atom.alignment.toByteUnits() orelse 0, atom.size, |
| 1056 | }); | 1053 | }); |
| 1057 | if (atom.fdes(elf_file).len > 0) { | 1054 | if (atom.fdes(elf_file).len > 0) { |
| 1058 | try writer.writeAll(" : fdes{ "); | 1055 | try writer.writeAll(" : fdes{ "); |
| ... | @@ -1180,16 +1177,7 @@ const x86_64 = struct { | ... | @@ -1180,16 +1177,7 @@ const x86_64 = struct { |
| 1180 | .TLSDESC_CALL, | 1177 | .TLSDESC_CALL, |
| 1181 | => {}, | 1178 | => {}, |
| 1182 | 1179 | ||
| 1183 | else => |x| switch (@intFromEnum(x)) { | 1180 | else => try atom.reportUnhandledRelocError(rel, elf_file), |
| 1184 | // Zig custom relocations | ||
| 1185 | Elf.R_ZIG_GOT32, | ||
| 1186 | Elf.R_ZIG_GOTPCREL, | ||
| 1187 | => { | ||
| 1188 | assert(symbol.flags.has_zig_got); | ||
| 1189 | }, | ||
| 1190 | |||
| 1191 | else => try atom.reportUnhandledRelocError(rel, elf_file), | ||
| 1192 | }, | ||
| 1193 | } | 1181 | } |
| 1194 | } | 1182 | } |
| 1195 | 1183 | ||
| ... | @@ -1209,7 +1197,7 @@ const x86_64 = struct { | ... | @@ -1209,7 +1197,7 @@ const x86_64 = struct { |
| 1209 | 1197 | ||
| 1210 | const cwriter = stream.writer(); | 1198 | const cwriter = stream.writer(); |
| 1211 | 1199 | ||
| 1212 | const P, const A, const S, const GOT, const G, const TP, const DTP, const ZIG_GOT = args; | 1200 | const P, const A, const S, const GOT, const G, const TP, const DTP = args; |
| 1213 | 1201 | ||
| 1214 | switch (r_type) { | 1202 | switch (r_type) { |
| 1215 | .NONE => unreachable, | 1203 | .NONE => unreachable, |
| ... | @@ -1224,9 +1212,8 @@ const x86_64 = struct { | ... | @@ -1224,9 +1212,8 @@ const x86_64 = struct { |
| 1224 | ); | 1212 | ); |
| 1225 | }, | 1213 | }, |
| 1226 | 1214 | ||
| 1227 | .PLT32, | 1215 | .PLT32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little), |
| 1228 | .PC32, | 1216 | .PC32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little), |
| 1229 | => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little), | ||
| 1230 | 1217 | ||
| 1231 | .GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little), | 1218 | .GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little), |
| 1232 | .GOTPC32 => try cwriter.writeInt(i32, @as(i32, @intCast(GOT + A - P)), .little), | 1219 | .GOTPC32 => try cwriter.writeInt(i32, @as(i32, @intCast(GOT + A - P)), .little), |
| ... | @@ -1327,15 +1314,9 @@ const x86_64 = struct { | ... | @@ -1327,15 +1314,9 @@ const x86_64 = struct { |
| 1327 | } | 1314 | } |
| 1328 | }, | 1315 | }, |
| 1329 | 1316 | ||
| 1330 | .GOT32 => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A)), .little), | 1317 | .GOT32 => try cwriter.writeInt(i32, @as(i32, @intCast(G + A)), .little), |
| 1331 | |||
| 1332 | else => |x| switch (@intFromEnum(x)) { | ||
| 1333 | // Zig custom relocations | ||
| 1334 | Elf.R_ZIG_GOT32 => try cwriter.writeInt(u32, @as(u32, @intCast(ZIG_GOT + A)), .little), | ||
| 1335 | Elf.R_ZIG_GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(ZIG_GOT + A - P)), .little), | ||
| 1336 | 1318 | ||
| 1337 | else => try atom.reportUnhandledRelocError(rel, elf_file), | 1319 | else => try atom.reportUnhandledRelocError(rel, elf_file), |
| 1338 | }, | ||
| 1339 | } | 1320 | } |
| 1340 | } | 1321 | } |
| 1341 | 1322 | ||
| ... | @@ -1355,7 +1336,7 @@ const x86_64 = struct { | ... | @@ -1355,7 +1336,7 @@ const x86_64 = struct { |
| 1355 | const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type()); | 1336 | const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type()); |
| 1356 | const cwriter = stream.writer(); | 1337 | const cwriter = stream.writer(); |
| 1357 | 1338 | ||
| 1358 | _, const A, const S, const GOT, _, _, const DTP, _ = args; | 1339 | _, const A, const S, const GOT, _, _, const DTP = args; |
| 1359 | 1340 | ||
| 1360 | switch (r_type) { | 1341 | switch (r_type) { |
| 1361 | .NONE => unreachable, | 1342 | .NONE => unreachable, |
| ... | @@ -1629,7 +1610,7 @@ const x86_64 = struct { | ... | @@ -1629,7 +1610,7 @@ const x86_64 = struct { |
| 1629 | const bits = @import("../../arch/x86_64/bits.zig"); | 1610 | const bits = @import("../../arch/x86_64/bits.zig"); |
| 1630 | const encoder = @import("../../arch/x86_64/encoder.zig"); | 1611 | const encoder = @import("../../arch/x86_64/encoder.zig"); |
| 1631 | const Disassembler = @import("../../arch/x86_64/Disassembler.zig"); | 1612 | const Disassembler = @import("../../arch/x86_64/Disassembler.zig"); |
| 1632 | const Immediate = bits.Immediate; | 1613 | const Immediate = Instruction.Immediate; |
| 1633 | const Instruction = encoder.Instruction; | 1614 | const Instruction = encoder.Instruction; |
| 1634 | }; | 1615 | }; |
| 1635 | 1616 | ||
| ... | @@ -1738,9 +1719,8 @@ const aarch64 = struct { | ... | @@ -1738,9 +1719,8 @@ const aarch64 = struct { |
| 1738 | const code = code_buffer[r_offset..][0..4]; | 1719 | const code = code_buffer[r_offset..][0..4]; |
| 1739 | const file_ptr = atom.file(elf_file).?; | 1720 | const file_ptr = atom.file(elf_file).?; |
| 1740 | 1721 | ||
| 1741 | const P, const A, const S, const GOT, const G, const TP, const DTP, const ZIG_GOT = args; | 1722 | const P, const A, const S, const GOT, const G, const TP, const DTP = args; |
| 1742 | _ = DTP; | 1723 | _ = DTP; |
| 1743 | _ = ZIG_GOT; | ||
| 1744 | 1724 | ||
| 1745 | switch (r_type) { | 1725 | switch (r_type) { |
| 1746 | .NONE => unreachable, | 1726 | .NONE => unreachable, |
| ... | @@ -1942,7 +1922,7 @@ const aarch64 = struct { | ... | @@ -1942,7 +1922,7 @@ const aarch64 = struct { |
| 1942 | const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type()); | 1922 | const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type()); |
| 1943 | const cwriter = stream.writer(); | 1923 | const cwriter = stream.writer(); |
| 1944 | 1924 | ||
| 1945 | _, const A, const S, _, _, _, _, _ = args; | 1925 | _, const A, const S, _, _, _, _ = args; |
| 1946 | 1926 | ||
| 1947 | switch (r_type) { | 1927 | switch (r_type) { |
| 1948 | .NONE => unreachable, | 1928 | .NONE => unreachable, |
| ... | @@ -1998,19 +1978,7 @@ const riscv = struct { | ... | @@ -1998,19 +1978,7 @@ const riscv = struct { |
| 1998 | .SUB32, | 1978 | .SUB32, |
| 1999 | => {}, | 1979 | => {}, |
| 2000 | 1980 | ||
| 2001 | else => |x| switch (@intFromEnum(x)) { | 1981 | else => try atom.reportUnhandledRelocError(rel, elf_file), |
| 2002 | Elf.R_ZIG_GOT_HI20, | ||
| 2003 | Elf.R_ZIG_GOT_LO12, | ||
| 2004 | => { | ||
| 2005 | assert(symbol.flags.has_zig_got); | ||
| 2006 | }, | ||
| 2007 | |||
| 2008 | Elf.R_GOT_HI20_STATIC, | ||
| 2009 | Elf.R_GOT_LO12_I_STATIC, | ||
| 2010 | => symbol.flags.needs_got = true, | ||
| 2011 | |||
| 2012 | else => try atom.reportUnhandledRelocError(rel, elf_file), | ||
| 2013 | }, | ||
| 2014 | } | 1982 | } |
| 2015 | } | 1983 | } |
| 2016 | 1984 | ||
| ... | @@ -2028,7 +1996,7 @@ const riscv = struct { | ... | @@ -2028,7 +1996,7 @@ const riscv = struct { |
| 2028 | const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; | 1996 | const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; |
| 2029 | const cwriter = stream.writer(); | 1997 | const cwriter = stream.writer(); |
| 2030 | 1998 | ||
| 2031 | const P, const A, const S, const GOT, const G, const TP, const DTP, const ZIG_GOT = args; | 1999 | const P, const A, const S, const GOT, const G, const TP, const DTP = args; |
| 2032 | _ = TP; | 2000 | _ = TP; |
| 2033 | _ = DTP; | 2001 | _ = DTP; |
| 2034 | 2002 | ||
| ... | @@ -2147,34 +2115,7 @@ const riscv = struct { | ... | @@ -2147,34 +2115,7 @@ const riscv = struct { |
| 2147 | // TODO: annotates an ADD instruction that can be removed when TPREL is relaxed | 2115 | // TODO: annotates an ADD instruction that can be removed when TPREL is relaxed |
| 2148 | }, | 2116 | }, |
| 2149 | 2117 | ||
| 2150 | else => |x| switch (@intFromEnum(x)) { | 2118 | else => try atom.reportUnhandledRelocError(rel, elf_file), |
| 2151 | // Zig custom relocations | ||
| 2152 | Elf.R_ZIG_GOT_HI20 => { | ||
| 2153 | assert(target.flags.has_zig_got); | ||
| 2154 | const disp: u32 = @bitCast(math.cast(i32, ZIG_GOT + A) orelse return error.Overflow); | ||
| 2155 | riscv_util.writeInstU(code[r_offset..][0..4], disp); | ||
| 2156 | }, | ||
| 2157 | |||
| 2158 | Elf.R_ZIG_GOT_LO12 => { | ||
| 2159 | assert(target.flags.has_zig_got); | ||
| 2160 | const value: u32 = @bitCast(math.cast(i32, ZIG_GOT + A) orelse return error.Overflow); | ||
| 2161 | riscv_util.writeInstI(code[r_offset..][0..4], value); | ||
| 2162 | }, | ||
| 2163 | |||
| 2164 | Elf.R_GOT_HI20_STATIC => { | ||
| 2165 | assert(target.flags.has_got); | ||
| 2166 | const disp: u32 = @bitCast(math.cast(i32, G + GOT + A) orelse return error.Overflow); | ||
| 2167 | riscv_util.writeInstU(code[r_offset..][0..4], disp); | ||
| 2168 | }, | ||
| 2169 | |||
| 2170 | Elf.R_GOT_LO12_I_STATIC => { | ||
| 2171 | assert(target.flags.has_got); | ||
| 2172 | const disp: u32 = @bitCast(math.cast(i32, G + GOT + A) orelse return error.Overflow); | ||
| 2173 | riscv_util.writeInstI(code[r_offset..][0..4], disp); | ||
| 2174 | }, | ||
| 2175 | |||
| 2176 | else => try atom.reportUnhandledRelocError(rel, elf_file), | ||
| 2177 | }, | ||
| 2178 | } | 2119 | } |
| 2179 | } | 2120 | } |
| 2180 | 2121 | ||
| ... | @@ -2194,7 +2135,7 @@ const riscv = struct { | ... | @@ -2194,7 +2135,7 @@ const riscv = struct { |
| 2194 | const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; | 2135 | const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; |
| 2195 | const cwriter = stream.writer(); | 2136 | const cwriter = stream.writer(); |
| 2196 | 2137 | ||
| 2197 | _, const A, const S, const GOT, _, _, const DTP, _ = args; | 2138 | _, const A, const S, const GOT, _, _, const DTP = args; |
| 2198 | _ = GOT; | 2139 | _ = GOT; |
| 2199 | _ = DTP; | 2140 | _ = DTP; |
| 2200 | 2141 | ||
| ... | @@ -2230,7 +2171,7 @@ const riscv = struct { | ... | @@ -2230,7 +2171,7 @@ const riscv = struct { |
| 2230 | const riscv_util = @import("../riscv.zig"); | 2171 | const riscv_util = @import("../riscv.zig"); |
| 2231 | }; | 2172 | }; |
| 2232 | 2173 | ||
| 2233 | const ResolveArgs = struct { i64, i64, i64, i64, i64, i64, i64, i64 }; | 2174 | const ResolveArgs = struct { i64, i64, i64, i64, i64, i64, i64 }; |
| 2234 | 2175 | ||
| 2235 | const RelocError = error{ | 2176 | const RelocError = error{ |
| 2236 | Overflow, | 2177 | Overflow, |
src/link/Elf/Symbol.zig+22-30| ... | @@ -101,7 +101,7 @@ pub fn symbolRank(symbol: Symbol, elf_file: *Elf) u32 { | ... | @@ -101,7 +101,7 @@ pub fn symbolRank(symbol: Symbol, elf_file: *Elf) u32 { |
| 101 | return file_ptr.symbolRank(sym, in_archive); | 101 | return file_ptr.symbolRank(sym, in_archive); |
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | pub fn address(symbol: Symbol, opts: struct { plt: bool = true }, elf_file: *Elf) i64 { | 104 | pub fn address(symbol: Symbol, opts: struct { plt: bool = true, trampoline: bool = true }, elf_file: *Elf) i64 { |
| 105 | if (symbol.mergeSubsection(elf_file)) |msub| { | 105 | if (symbol.mergeSubsection(elf_file)) |msub| { |
| 106 | if (!msub.alive) return 0; | 106 | if (!msub.alive) return 0; |
| 107 | return msub.address(elf_file) + symbol.value; | 107 | return msub.address(elf_file) + symbol.value; |
| ... | @@ -109,6 +109,9 @@ pub fn address(symbol: Symbol, opts: struct { plt: bool = true }, elf_file: *Elf | ... | @@ -109,6 +109,9 @@ pub fn address(symbol: Symbol, opts: struct { plt: bool = true }, elf_file: *Elf |
| 109 | if (symbol.flags.has_copy_rel) { | 109 | if (symbol.flags.has_copy_rel) { |
| 110 | return symbol.copyRelAddress(elf_file); | 110 | return symbol.copyRelAddress(elf_file); |
| 111 | } | 111 | } |
| 112 | if (symbol.flags.has_trampoline and opts.trampoline) { | ||
| 113 | return symbol.trampolineAddress(elf_file); | ||
| 114 | } | ||
| 112 | if (symbol.flags.has_plt and opts.plt) { | 115 | if (symbol.flags.has_plt and opts.plt) { |
| 113 | if (!symbol.flags.is_canonical and symbol.flags.has_got) { | 116 | if (!symbol.flags.is_canonical and symbol.flags.has_got) { |
| 114 | // We have a non-lazy bound function pointer, use that! | 117 | // We have a non-lazy bound function pointer, use that! |
| ... | @@ -217,23 +220,11 @@ pub fn tlsDescAddress(symbol: Symbol, elf_file: *Elf) i64 { | ... | @@ -217,23 +220,11 @@ pub fn tlsDescAddress(symbol: Symbol, elf_file: *Elf) i64 { |
| 217 | return entry.address(elf_file); | 220 | return entry.address(elf_file); |
| 218 | } | 221 | } |
| 219 | 222 | ||
| 220 | const GetOrCreateZigGotEntryResult = struct { | 223 | pub fn trampolineAddress(symbol: Symbol, elf_file: *Elf) i64 { |
| 221 | found_existing: bool, | 224 | if (!symbol.flags.has_trampoline) return 0; |
| 222 | index: ZigGotSection.Index, | 225 | const zo = elf_file.zigObjectPtr().?; |
| 223 | }; | 226 | const index = symbol.extra(elf_file).trampoline; |
| 224 | 227 | return zo.symbol(index).address(.{}, elf_file); | |
| 225 | pub fn getOrCreateZigGotEntry(symbol: *Symbol, symbol_index: Index, elf_file: *Elf) !GetOrCreateZigGotEntryResult { | ||
| 226 | assert(!elf_file.base.isRelocatable()); | ||
| 227 | assert(symbol.flags.needs_zig_got); | ||
| 228 | if (symbol.flags.has_zig_got) return .{ .found_existing = true, .index = symbol.extra(elf_file).zig_got }; | ||
| 229 | const index = try elf_file.zig_got.addSymbol(symbol_index, elf_file); | ||
| 230 | return .{ .found_existing = false, .index = index }; | ||
| 231 | } | ||
| 232 | |||
| 233 | pub fn zigGotAddress(symbol: Symbol, elf_file: *Elf) i64 { | ||
| 234 | if (!symbol.flags.has_zig_got) return 0; | ||
| 235 | const extras = symbol.extra(elf_file); | ||
| 236 | return elf_file.zig_got.entryAddress(extras.zig_got, elf_file); | ||
| 237 | } | 228 | } |
| 238 | 229 | ||
| 239 | pub fn dsoAlignment(symbol: Symbol, elf_file: *Elf) !u64 { | 230 | pub fn dsoAlignment(symbol: Symbol, elf_file: *Elf) !u64 { |
| ... | @@ -259,7 +250,7 @@ const AddExtraOpts = struct { | ... | @@ -259,7 +250,7 @@ const AddExtraOpts = struct { |
| 259 | tlsgd: ?u32 = null, | 250 | tlsgd: ?u32 = null, |
| 260 | gottp: ?u32 = null, | 251 | gottp: ?u32 = null, |
| 261 | tlsdesc: ?u32 = null, | 252 | tlsdesc: ?u32 = null, |
| 262 | zig_got: ?u32 = null, | 253 | trampoline: ?u32 = null, |
| 263 | }; | 254 | }; |
| 264 | 255 | ||
| 265 | pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, elf_file: *Elf) void { | 256 | pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, elf_file: *Elf) void { |
| ... | @@ -312,7 +303,7 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void { | ... | @@ -312,7 +303,7 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void { |
| 312 | const shdr = elf_file.shdrs.items[st_shndx]; | 303 | const shdr = elf_file.shdrs.items[st_shndx]; |
| 313 | if (shdr.sh_flags & elf.SHF_TLS != 0 and file_ptr != .linker_defined) | 304 | if (shdr.sh_flags & elf.SHF_TLS != 0 and file_ptr != .linker_defined) |
| 314 | break :blk symbol.address(.{ .plt = false }, elf_file) - elf_file.tlsAddress(); | 305 | break :blk symbol.address(.{ .plt = false }, elf_file) - elf_file.tlsAddress(); |
| 315 | break :blk symbol.address(.{ .plt = false }, elf_file); | 306 | break :blk symbol.address(.{ .plt = false, .trampoline = false }, elf_file); |
| 316 | }; | 307 | }; |
| 317 | out.st_info = (st_bind << 4) | st_type; | 308 | out.st_info = (st_bind << 4) | st_type; |
| 318 | out.st_other = esym.st_other; | 309 | out.st_other = esym.st_other; |
| ... | @@ -331,7 +322,7 @@ pub fn format( | ... | @@ -331,7 +322,7 @@ pub fn format( |
| 331 | _ = unused_fmt_string; | 322 | _ = unused_fmt_string; |
| 332 | _ = options; | 323 | _ = options; |
| 333 | _ = writer; | 324 | _ = writer; |
| 334 | @compileError("do not format symbols directly"); | 325 | @compileError("do not format Symbol directly"); |
| 335 | } | 326 | } |
| 336 | 327 | ||
| 337 | const FormatContext = struct { | 328 | const FormatContext = struct { |
| ... | @@ -388,7 +379,7 @@ fn format2( | ... | @@ -388,7 +379,7 @@ fn format2( |
| 388 | try writer.print("%{d} : {s} : @{x}", .{ | 379 | try writer.print("%{d} : {s} : @{x}", .{ |
| 389 | symbol.esym_index, | 380 | symbol.esym_index, |
| 390 | symbol.fmtName(elf_file), | 381 | symbol.fmtName(elf_file), |
| 391 | symbol.address(.{}, elf_file), | 382 | symbol.address(.{ .plt = false, .trampoline = false }, elf_file), |
| 392 | }); | 383 | }); |
| 393 | if (symbol.file(elf_file)) |file_ptr| { | 384 | if (symbol.file(elf_file)) |file_ptr| { |
| 394 | if (symbol.isAbs(elf_file)) { | 385 | if (symbol.isAbs(elf_file)) { |
| ... | @@ -456,17 +447,18 @@ pub const Flags = packed struct { | ... | @@ -456,17 +447,18 @@ pub const Flags = packed struct { |
| 456 | needs_tlsdesc: bool = false, | 447 | needs_tlsdesc: bool = false, |
| 457 | has_tlsdesc: bool = false, | 448 | has_tlsdesc: bool = false, |
| 458 | 449 | ||
| 459 | /// Whether the symbol contains .zig.got indirection. | 450 | /// Whether the symbol is a merge subsection. |
| 460 | needs_zig_got: bool = false, | 451 | merge_subsection: bool = false, |
| 461 | has_zig_got: bool = false, | 452 | |
| 453 | /// ZigObject specific flags | ||
| 454 | /// Whether the symbol has a trampoline. | ||
| 455 | has_trampoline: bool = false, | ||
| 462 | 456 | ||
| 463 | /// Whether the symbol is a TLS variable. | 457 | /// Whether the symbol is a TLS variable. |
| 464 | /// TODO this is really not needed if only we operated on esyms between | ||
| 465 | /// codegen and ZigObject. | ||
| 466 | is_tls: bool = false, | 458 | is_tls: bool = false, |
| 467 | 459 | ||
| 468 | /// Whether the symbol is a merge subsection. | 460 | /// Whether the symbol is an extern pointer (as opposed to function). |
| 469 | merge_subsection: bool = false, | 461 | is_extern_ptr: bool = false, |
| 470 | }; | 462 | }; |
| 471 | 463 | ||
| 472 | pub const Extra = struct { | 464 | pub const Extra = struct { |
| ... | @@ -479,8 +471,8 @@ pub const Extra = struct { | ... | @@ -479,8 +471,8 @@ pub const Extra = struct { |
| 479 | tlsgd: u32 = 0, | 471 | tlsgd: u32 = 0, |
| 480 | gottp: u32 = 0, | 472 | gottp: u32 = 0, |
| 481 | tlsdesc: u32 = 0, | 473 | tlsdesc: u32 = 0, |
| 482 | zig_got: u32 = 0, | ||
| 483 | merge_section: u32 = 0, | 474 | merge_section: u32 = 0, |
| 475 | trampoline: u32 = 0, | ||
| 484 | }; | 476 | }; |
| 485 | 477 | ||
| 486 | pub const Index = u32; | 478 | pub const Index = u32; |
src/link/Elf/ZigObject.zig+180-55| ... | @@ -102,23 +102,17 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void { | ... | @@ -102,23 +102,17 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void { |
| 102 | } | 102 | } |
| 103 | self.relocs.deinit(allocator); | 103 | self.relocs.deinit(allocator); |
| 104 | 104 | ||
| 105 | { | 105 | for (self.navs.values()) |*meta| { |
| 106 | var it = self.navs.iterator(); | 106 | meta.exports.deinit(allocator); |
| 107 | while (it.next()) |entry| { | ||
| 108 | entry.value_ptr.exports.deinit(allocator); | ||
| 109 | } | ||
| 110 | self.navs.deinit(allocator); | ||
| 111 | } | 107 | } |
| 108 | self.navs.deinit(allocator); | ||
| 112 | 109 | ||
| 113 | self.lazy_syms.deinit(allocator); | 110 | self.lazy_syms.deinit(allocator); |
| 114 | 111 | ||
| 115 | { | 112 | for (self.uavs.values()) |*meta| { |
| 116 | var it = self.uavs.iterator(); | 113 | meta.exports.deinit(allocator); |
| 117 | while (it.next()) |entry| { | ||
| 118 | entry.value_ptr.exports.deinit(allocator); | ||
| 119 | } | ||
| 120 | self.uavs.deinit(allocator); | ||
| 121 | } | 114 | } |
| 115 | self.uavs.deinit(allocator); | ||
| 122 | 116 | ||
| 123 | for (self.tls_variables.values()) |*tlv| { | 117 | for (self.tls_variables.values()) |*tlv| { |
| 124 | tlv.deinit(allocator); | 118 | tlv.deinit(allocator); |
| ... | @@ -161,6 +155,16 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi | ... | @@ -161,6 +155,16 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi |
| 161 | if (metadata.rodata_state != .unused) metadata.rodata_state = .flushed; | 155 | if (metadata.rodata_state != .unused) metadata.rodata_state = .flushed; |
| 162 | } | 156 | } |
| 163 | 157 | ||
| 158 | if (build_options.enable_logging) { | ||
| 159 | const pt: Zcu.PerThread = .{ .zcu = elf_file.base.comp.module.?, .tid = tid }; | ||
| 160 | for (self.navs.keys(), self.navs.values()) |nav_index, meta| { | ||
| 161 | checkNavAllocated(pt, nav_index, meta); | ||
| 162 | } | ||
| 163 | for (self.uavs.keys(), self.uavs.values()) |uav_index, meta| { | ||
| 164 | checkUavAllocated(pt, uav_index, meta); | ||
| 165 | } | ||
| 166 | } | ||
| 167 | |||
| 164 | if (self.dwarf) |*dw| { | 168 | if (self.dwarf) |*dw| { |
| 165 | const pt: Zcu.PerThread = .{ .zcu = elf_file.base.comp.module.?, .tid = tid }; | 169 | const pt: Zcu.PerThread = .{ .zcu = elf_file.base.comp.module.?, .tid = tid }; |
| 166 | try dw.flushModule(pt); | 170 | try dw.flushModule(pt); |
| ... | @@ -698,6 +702,7 @@ pub fn lowerUav( | ... | @@ -698,6 +702,7 @@ pub fn lowerUav( |
| 698 | else => explicit_alignment, | 702 | else => explicit_alignment, |
| 699 | }; | 703 | }; |
| 700 | if (self.uavs.get(uav)) |metadata| { | 704 | if (self.uavs.get(uav)) |metadata| { |
| 705 | assert(metadata.allocated); | ||
| 701 | const sym = self.symbol(metadata.symbol_index); | 706 | const sym = self.symbol(metadata.symbol_index); |
| 702 | const existing_alignment = sym.atom(elf_file).?.alignment; | 707 | const existing_alignment = sym.atom(elf_file).?.alignment; |
| 703 | if (uav_alignment.order(existing_alignment).compare(.lte)) | 708 | if (uav_alignment.order(existing_alignment).compare(.lte)) |
| ... | @@ -729,7 +734,7 @@ pub fn lowerUav( | ... | @@ -729,7 +734,7 @@ pub fn lowerUav( |
| 729 | .ok => |sym_index| sym_index, | 734 | .ok => |sym_index| sym_index, |
| 730 | .fail => |em| return .{ .fail = em }, | 735 | .fail => |em| return .{ .fail = em }, |
| 731 | }; | 736 | }; |
| 732 | try self.uavs.put(gpa, uav, .{ .symbol_index = sym_index }); | 737 | try self.uavs.put(gpa, uav, .{ .symbol_index = sym_index, .allocated = true }); |
| 733 | return .{ .mcv = .{ .load_symbol = sym_index } }; | 738 | return .{ .mcv = .{ .load_symbol = sym_index } }; |
| 734 | } | 739 | } |
| 735 | 740 | ||
| ... | @@ -747,13 +752,7 @@ pub fn getOrCreateMetadataForLazySymbol( | ... | @@ -747,13 +752,7 @@ pub fn getOrCreateMetadataForLazySymbol( |
| 747 | .const_data => .{ &gop.value_ptr.rodata_symbol_index, &gop.value_ptr.rodata_state }, | 752 | .const_data => .{ &gop.value_ptr.rodata_symbol_index, &gop.value_ptr.rodata_state }, |
| 748 | }; | 753 | }; |
| 749 | switch (state_ptr.*) { | 754 | switch (state_ptr.*) { |
| 750 | .unused => { | 755 | .unused => symbol_index_ptr.* = try self.newSymbolWithAtom(pt.zcu.gpa, 0), |
| 751 | const gpa = elf_file.base.comp.gpa; | ||
| 752 | const symbol_index = try self.newSymbolWithAtom(gpa, 0); | ||
| 753 | const sym = self.symbol(symbol_index); | ||
| 754 | sym.flags.needs_zig_got = true; | ||
| 755 | symbol_index_ptr.* = symbol_index; | ||
| 756 | }, | ||
| 757 | .pending_flush => return symbol_index_ptr.*, | 756 | .pending_flush => return symbol_index_ptr.*, |
| 758 | .flushed => {}, | 757 | .flushed => {}, |
| 759 | } | 758 | } |
| ... | @@ -807,9 +806,6 @@ pub fn getOrCreateMetadataForNav( | ... | @@ -807,9 +806,6 @@ pub fn getOrCreateMetadataForNav( |
| 807 | sym.flags.is_tls = true; | 806 | sym.flags.is_tls = true; |
| 808 | } | 807 | } |
| 809 | } | 808 | } |
| 810 | if (!sym.flags.is_tls) { | ||
| 811 | sym.flags.needs_zig_got = true; | ||
| 812 | } | ||
| 813 | gop.value_ptr.* = .{ .symbol_index = symbol_index }; | 809 | gop.value_ptr.* = .{ .symbol_index = symbol_index }; |
| 814 | } | 810 | } |
| 815 | return gop.value_ptr.symbol_index; | 811 | return gop.value_ptr.symbol_index; |
| ... | @@ -820,9 +816,9 @@ fn getNavShdrIndex( | ... | @@ -820,9 +816,9 @@ fn getNavShdrIndex( |
| 820 | elf_file: *Elf, | 816 | elf_file: *Elf, |
| 821 | zcu: *Zcu, | 817 | zcu: *Zcu, |
| 822 | nav_index: InternPool.Nav.Index, | 818 | nav_index: InternPool.Nav.Index, |
| 819 | sym_index: Symbol.Index, | ||
| 823 | code: []const u8, | 820 | code: []const u8, |
| 824 | ) error{OutOfMemory}!u32 { | 821 | ) error{OutOfMemory}!u32 { |
| 825 | _ = self; | ||
| 826 | const ip = &zcu.intern_pool; | 822 | const ip = &zcu.intern_pool; |
| 827 | const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded; | 823 | const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded; |
| 828 | const nav_val = zcu.navValue(nav_index); | 824 | const nav_val = zcu.navValue(nav_index); |
| ... | @@ -832,10 +828,12 @@ fn getNavShdrIndex( | ... | @@ -832,10 +828,12 @@ fn getNavShdrIndex( |
| 832 | .@"extern" => |@"extern"| .{ @"extern".is_const, @"extern".is_threadlocal, .none }, | 828 | .@"extern" => |@"extern"| .{ @"extern".is_const, @"extern".is_threadlocal, .none }, |
| 833 | else => .{ true, false, nav_val.toIntern() }, | 829 | else => .{ true, false, nav_val.toIntern() }, |
| 834 | }; | 830 | }; |
| 831 | const has_relocs = self.symbol(sym_index).atom(elf_file).?.relocs(elf_file).len > 0; | ||
| 835 | if (any_non_single_threaded and is_threadlocal) { | 832 | if (any_non_single_threaded and is_threadlocal) { |
| 836 | for (code) |byte| { | 833 | const is_bss = !has_relocs and for (code) |byte| { |
| 837 | if (byte != 0) break; | 834 | if (byte != 0) break false; |
| 838 | } else return elf_file.sectionByName(".tbss") orelse try elf_file.addSection(.{ | 835 | } else true; |
| 836 | if (is_bss) return elf_file.sectionByName(".tbss") orelse try elf_file.addSection(.{ | ||
| 839 | .type = elf.SHT_NOBITS, | 837 | .type = elf.SHT_NOBITS, |
| 840 | .flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS, | 838 | .flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS, |
| 841 | .name = try elf_file.insertShString(".tbss"), | 839 | .name = try elf_file.insertShString(".tbss"), |
| ... | @@ -854,9 +852,10 @@ fn getNavShdrIndex( | ... | @@ -854,9 +852,10 @@ fn getNavShdrIndex( |
| 854 | .Debug, .ReleaseSafe => elf_file.zig_data_section_index.?, | 852 | .Debug, .ReleaseSafe => elf_file.zig_data_section_index.?, |
| 855 | .ReleaseFast, .ReleaseSmall => elf_file.zig_bss_section_index.?, | 853 | .ReleaseFast, .ReleaseSmall => elf_file.zig_bss_section_index.?, |
| 856 | }; | 854 | }; |
| 857 | for (code) |byte| { | 855 | const is_bss = !has_relocs and for (code) |byte| { |
| 858 | if (byte != 0) break; | 856 | if (byte != 0) break false; |
| 859 | } else return elf_file.zig_bss_section_index.?; | 857 | } else true; |
| 858 | if (is_bss) return elf_file.zig_bss_section_index.?; | ||
| 860 | return elf_file.zig_data_section_index.?; | 859 | return elf_file.zig_data_section_index.?; |
| 861 | } | 860 | } |
| 862 | 861 | ||
| ... | @@ -909,13 +908,6 @@ fn updateNavCode( | ... | @@ -909,13 +908,6 @@ fn updateNavCode( |
| 909 | if (old_vaddr != atom_ptr.value) { | 908 | if (old_vaddr != atom_ptr.value) { |
| 910 | sym.value = 0; | 909 | sym.value = 0; |
| 911 | esym.st_value = 0; | 910 | esym.st_value = 0; |
| 912 | |||
| 913 | if (!elf_file.base.isRelocatable()) { | ||
| 914 | log.debug(" (writing new offset table entry)", .{}); | ||
| 915 | assert(sym.flags.has_zig_got); | ||
| 916 | const extra = sym.extra(elf_file); | ||
| 917 | try elf_file.zig_got.writeOne(elf_file, extra.zig_got); | ||
| 918 | } | ||
| 919 | } | 911 | } |
| 920 | } else if (code.len < old_size) { | 912 | } else if (code.len < old_size) { |
| 921 | atom_ptr.shrink(elf_file); | 913 | atom_ptr.shrink(elf_file); |
| ... | @@ -925,15 +917,11 @@ fn updateNavCode( | ... | @@ -925,15 +917,11 @@ fn updateNavCode( |
| 925 | errdefer self.freeNavMetadata(elf_file, sym_index); | 917 | errdefer self.freeNavMetadata(elf_file, sym_index); |
| 926 | 918 | ||
| 927 | sym.value = 0; | 919 | sym.value = 0; |
| 928 | sym.flags.needs_zig_got = true; | ||
| 929 | esym.st_value = 0; | 920 | esym.st_value = 0; |
| 930 | |||
| 931 | if (!elf_file.base.isRelocatable()) { | ||
| 932 | const gop = try sym.getOrCreateZigGotEntry(sym_index, elf_file); | ||
| 933 | try elf_file.zig_got.writeOne(elf_file, gop.index); | ||
| 934 | } | ||
| 935 | } | 921 | } |
| 936 | 922 | ||
| 923 | self.navs.getPtr(nav_index).?.allocated = true; | ||
| 924 | |||
| 937 | if (elf_file.base.child_pid) |pid| { | 925 | if (elf_file.base.child_pid) |pid| { |
| 938 | switch (builtin.os.tag) { | 926 | switch (builtin.os.tag) { |
| 939 | .linux => { | 927 | .linux => { |
| ... | @@ -959,6 +947,7 @@ fn updateNavCode( | ... | @@ -959,6 +947,7 @@ fn updateNavCode( |
| 959 | if (shdr.sh_type != elf.SHT_NOBITS) { | 947 | if (shdr.sh_type != elf.SHT_NOBITS) { |
| 960 | const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value)); | 948 | const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value)); |
| 961 | try elf_file.base.file.?.pwriteAll(code, file_offset); | 949 | try elf_file.base.file.?.pwriteAll(code, file_offset); |
| 950 | log.debug("writing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), file_offset, file_offset + code.len }); | ||
| 962 | } | 951 | } |
| 963 | } | 952 | } |
| 964 | 953 | ||
| ... | @@ -1001,6 +990,8 @@ fn updateTlv( | ... | @@ -1001,6 +990,8 @@ fn updateTlv( |
| 1001 | atom_ptr.alignment = required_alignment; | 990 | atom_ptr.alignment = required_alignment; |
| 1002 | atom_ptr.size = code.len; | 991 | atom_ptr.size = code.len; |
| 1003 | 992 | ||
| 993 | self.navs.getPtr(nav_index).?.allocated = true; | ||
| 994 | |||
| 1004 | { | 995 | { |
| 1005 | const gop = try self.tls_variables.getOrPut(gpa, atom_ptr.atom_index); | 996 | const gop = try self.tls_variables.getOrPut(gpa, atom_ptr.atom_index); |
| 1006 | assert(!gop.found_existing); // TODO incremental updates | 997 | assert(!gop.found_existing); // TODO incremental updates |
| ... | @@ -1065,8 +1056,21 @@ pub fn updateFunc( | ... | @@ -1065,8 +1056,21 @@ pub fn updateFunc( |
| 1065 | }, | 1056 | }, |
| 1066 | }; | 1057 | }; |
| 1067 | 1058 | ||
| 1068 | const shndx = try self.getNavShdrIndex(elf_file, zcu, func.owner_nav, code); | 1059 | const shndx = try self.getNavShdrIndex(elf_file, zcu, func.owner_nav, sym_index, code); |
| 1060 | log.debug("setting shdr({x},{s}) for {}", .{ | ||
| 1061 | shndx, | ||
| 1062 | elf_file.getShString(elf_file.shdrs.items[shndx].sh_name), | ||
| 1063 | ip.getNav(func.owner_nav).fqn.fmt(ip), | ||
| 1064 | }); | ||
| 1065 | const old_rva, const old_alignment = blk: { | ||
| 1066 | const atom_ptr = self.symbol(sym_index).atom(elf_file).?; | ||
| 1067 | break :blk .{ atom_ptr.value, atom_ptr.alignment }; | ||
| 1068 | }; | ||
| 1069 | try self.updateNavCode(elf_file, pt, func.owner_nav, sym_index, shndx, code, elf.STT_FUNC); | 1069 | try self.updateNavCode(elf_file, pt, func.owner_nav, sym_index, shndx, code, elf.STT_FUNC); |
| 1070 | const new_rva, const new_alignment = blk: { | ||
| 1071 | const atom_ptr = self.symbol(sym_index).atom(elf_file).?; | ||
| 1072 | break :blk .{ atom_ptr.value, atom_ptr.alignment }; | ||
| 1073 | }; | ||
| 1070 | 1074 | ||
| 1071 | if (dwarf_state) |*ds| { | 1075 | if (dwarf_state) |*ds| { |
| 1072 | const sym = self.symbol(sym_index); | 1076 | const sym = self.symbol(sym_index); |
| ... | @@ -1080,6 +1084,41 @@ pub fn updateFunc( | ... | @@ -1080,6 +1084,41 @@ pub fn updateFunc( |
| 1080 | } | 1084 | } |
| 1081 | 1085 | ||
| 1082 | // Exports will be updated by `Zcu.processExports` after the update. | 1086 | // Exports will be updated by `Zcu.processExports` after the update. |
| 1087 | |||
| 1088 | if (old_rva != new_rva and old_rva > 0) { | ||
| 1089 | // If we had to reallocate the function, we re-use the existing slot for a trampoline. | ||
| 1090 | // In the rare case that the function has been further overaligned we skip creating a | ||
| 1091 | // trampoline and update all symbols referring this function. | ||
| 1092 | if (old_alignment.order(new_alignment) == .lt) { | ||
| 1093 | @panic("TODO update all symbols referring this function"); | ||
| 1094 | } | ||
| 1095 | |||
| 1096 | // Create a trampoline to the new location at `old_rva`. | ||
| 1097 | if (!self.symbol(sym_index).flags.has_trampoline) { | ||
| 1098 | const name = try std.fmt.allocPrint(gpa, "{s}$trampoline", .{ | ||
| 1099 | self.symbol(sym_index).name(elf_file), | ||
| 1100 | }); | ||
| 1101 | defer gpa.free(name); | ||
| 1102 | const name_off = try self.addString(gpa, name); | ||
| 1103 | const tr_size = trampolineSize(elf_file.getTarget().cpu.arch); | ||
| 1104 | const tr_sym_index = try self.newSymbolWithAtom(gpa, name_off); | ||
| 1105 | const tr_sym = self.symbol(tr_sym_index); | ||
| 1106 | const tr_esym = &self.symtab.items(.elf_sym)[tr_sym.esym_index]; | ||
| 1107 | tr_esym.st_info |= elf.STT_OBJECT; | ||
| 1108 | tr_esym.st_size = tr_size; | ||
| 1109 | const tr_atom_ptr = tr_sym.atom(elf_file).?; | ||
| 1110 | tr_atom_ptr.value = old_rva; | ||
| 1111 | tr_atom_ptr.alive = true; | ||
| 1112 | tr_atom_ptr.alignment = old_alignment; | ||
| 1113 | tr_atom_ptr.output_section_index = elf_file.zig_text_section_index.?; | ||
| 1114 | tr_atom_ptr.size = tr_size; | ||
| 1115 | const target_sym = self.symbol(sym_index); | ||
| 1116 | target_sym.addExtra(.{ .trampoline = tr_sym_index }, elf_file); | ||
| 1117 | target_sym.flags.has_trampoline = true; | ||
| 1118 | } | ||
| 1119 | const target_sym = self.symbol(sym_index); | ||
| 1120 | try writeTrampoline(self.symbol(target_sym.extra(elf_file).trampoline).*, target_sym.*, elf_file); | ||
| 1121 | } | ||
| 1083 | } | 1122 | } |
| 1084 | 1123 | ||
| 1085 | pub fn updateNav( | 1124 | pub fn updateNav( |
| ... | @@ -1102,13 +1141,12 @@ pub fn updateNav( | ... | @@ -1102,13 +1141,12 @@ pub fn updateNav( |
| 1102 | .variable => |variable| Value.fromInterned(variable.init), | 1141 | .variable => |variable| Value.fromInterned(variable.init), |
| 1103 | .@"extern" => |@"extern"| { | 1142 | .@"extern" => |@"extern"| { |
| 1104 | if (ip.isFunctionType(@"extern".ty)) return; | 1143 | if (ip.isFunctionType(@"extern".ty)) return; |
| 1105 | // Extern variable gets a .got entry only. | ||
| 1106 | const sym_index = try self.getGlobalSymbol( | 1144 | const sym_index = try self.getGlobalSymbol( |
| 1107 | elf_file, | 1145 | elf_file, |
| 1108 | nav.name.toSlice(ip), | 1146 | nav.name.toSlice(ip), |
| 1109 | @"extern".lib_name.toSlice(ip), | 1147 | @"extern".lib_name.toSlice(ip), |
| 1110 | ); | 1148 | ); |
| 1111 | self.symbol(sym_index).flags.needs_got = true; | 1149 | self.symbol(sym_index).flags.is_extern_ptr = true; |
| 1112 | return; | 1150 | return; |
| 1113 | }, | 1151 | }, |
| 1114 | else => nav_val, | 1152 | else => nav_val, |
| ... | @@ -1142,7 +1180,12 @@ pub fn updateNav( | ... | @@ -1142,7 +1180,12 @@ pub fn updateNav( |
| 1142 | }, | 1180 | }, |
| 1143 | }; | 1181 | }; |
| 1144 | 1182 | ||
| 1145 | const shndx = try self.getNavShdrIndex(elf_file, zcu, nav_index, code); | 1183 | const shndx = try self.getNavShdrIndex(elf_file, zcu, nav_index, sym_index, code); |
| 1184 | log.debug("setting shdr({x},{s}) for {}", .{ | ||
| 1185 | shndx, | ||
| 1186 | elf_file.getShString(elf_file.shdrs.items[shndx].sh_name), | ||
| 1187 | nav.fqn.fmt(ip), | ||
| 1188 | }); | ||
| 1146 | if (elf_file.shdrs.items[shndx].sh_flags & elf.SHF_TLS != 0) | 1189 | if (elf_file.shdrs.items[shndx].sh_flags & elf.SHF_TLS != 0) |
| 1147 | try self.updateTlv(elf_file, pt, nav_index, sym_index, shndx, code) | 1190 | try self.updateTlv(elf_file, pt, nav_index, sym_index, shndx, code) |
| 1148 | else | 1191 | else |
| ... | @@ -1225,14 +1268,8 @@ fn updateLazySymbol( | ... | @@ -1225,14 +1268,8 @@ fn updateLazySymbol( |
| 1225 | errdefer self.freeNavMetadata(elf_file, symbol_index); | 1268 | errdefer self.freeNavMetadata(elf_file, symbol_index); |
| 1226 | 1269 | ||
| 1227 | local_sym.value = 0; | 1270 | local_sym.value = 0; |
| 1228 | local_sym.flags.needs_zig_got = true; | ||
| 1229 | local_esym.st_value = 0; | 1271 | local_esym.st_value = 0; |
| 1230 | 1272 | ||
| 1231 | if (!elf_file.base.isRelocatable()) { | ||
| 1232 | const gop = try local_sym.getOrCreateZigGotEntry(symbol_index, elf_file); | ||
| 1233 | try elf_file.zig_got.writeOne(elf_file, gop.index); | ||
| 1234 | } | ||
| 1235 | |||
| 1236 | const shdr = elf_file.shdrs.items[output_section_index]; | 1273 | const shdr = elf_file.shdrs.items[output_section_index]; |
| 1237 | const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value)); | 1274 | const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value)); |
| 1238 | try elf_file.base.file.?.pwriteAll(code, file_offset); | 1275 | try elf_file.base.file.?.pwriteAll(code, file_offset); |
| ... | @@ -1440,6 +1477,52 @@ pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_n | ... | @@ -1440,6 +1477,52 @@ pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_n |
| 1440 | return lookup_gop.value_ptr.*; | 1477 | return lookup_gop.value_ptr.*; |
| 1441 | } | 1478 | } |
| 1442 | 1479 | ||
| 1480 | const max_trampoline_len = 12; | ||
| 1481 | |||
| 1482 | fn trampolineSize(cpu_arch: std.Target.Cpu.Arch) u64 { | ||
| 1483 | const len = switch (cpu_arch) { | ||
| 1484 | .x86_64 => 5, // jmp rel32 | ||
| 1485 | else => @panic("TODO implement trampoline size for this CPU arch"), | ||
| 1486 | }; | ||
| 1487 | comptime assert(len <= max_trampoline_len); | ||
| 1488 | return len; | ||
| 1489 | } | ||
| 1490 | |||
| 1491 | fn writeTrampoline(tr_sym: Symbol, target: Symbol, elf_file: *Elf) !void { | ||
| 1492 | const atom_ptr = tr_sym.atom(elf_file).?; | ||
| 1493 | const shdr = elf_file.shdrs.items[atom_ptr.output_section_index]; | ||
| 1494 | const fileoff = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value)); | ||
| 1495 | const source_addr = tr_sym.address(.{}, elf_file); | ||
| 1496 | const target_addr = target.address(.{ .trampoline = false }, elf_file); | ||
| 1497 | var buf: [max_trampoline_len]u8 = undefined; | ||
| 1498 | const out = switch (elf_file.getTarget().cpu.arch) { | ||
| 1499 | .x86_64 => try x86_64.writeTrampolineCode(source_addr, target_addr, &buf), | ||
| 1500 | else => @panic("TODO implement write trampoline for this CPU arch"), | ||
| 1501 | }; | ||
| 1502 | try elf_file.base.file.?.pwriteAll(out, fileoff); | ||
| 1503 | |||
| 1504 | if (elf_file.base.child_pid) |pid| { | ||
| 1505 | switch (builtin.os.tag) { | ||
| 1506 | .linux => { | ||
| 1507 | var local_vec: [1]std.posix.iovec_const = .{.{ | ||
| 1508 | .base = out.ptr, | ||
| 1509 | .len = out.len, | ||
| 1510 | }}; | ||
| 1511 | var remote_vec: [1]std.posix.iovec_const = .{.{ | ||
| 1512 | .base = @as([*]u8, @ptrFromInt(@as(usize, @intCast(source_addr)))), | ||
| 1513 | .len = out.len, | ||
| 1514 | }}; | ||
| 1515 | const rc = std.os.linux.process_vm_writev(pid, &local_vec, &remote_vec, 0); | ||
| 1516 | switch (std.os.linux.E.init(rc)) { | ||
| 1517 | .SUCCESS => assert(rc == out.len), | ||
| 1518 | else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}), | ||
| 1519 | } | ||
| 1520 | }, | ||
| 1521 | else => return error.HotSwapUnavailableOnHostOperatingSystem, | ||
| 1522 | } | ||
| 1523 | } | ||
| 1524 | } | ||
| 1525 | |||
| 1443 | pub fn asFile(self: *ZigObject) File { | 1526 | pub fn asFile(self: *ZigObject) File { |
| 1444 | return .{ .zig_object = self }; | 1527 | return .{ .zig_object = self }; |
| 1445 | } | 1528 | } |
| ... | @@ -1662,6 +1745,8 @@ const AvMetadata = struct { | ... | @@ -1662,6 +1745,8 @@ const AvMetadata = struct { |
| 1662 | symbol_index: Symbol.Index, | 1745 | symbol_index: Symbol.Index, |
| 1663 | /// A list of all exports aliases of this Av. | 1746 | /// A list of all exports aliases of this Av. |
| 1664 | exports: std.ArrayListUnmanaged(Symbol.Index) = .{}, | 1747 | exports: std.ArrayListUnmanaged(Symbol.Index) = .{}, |
| 1748 | /// Set to true if the AV has been initialized and allocated. | ||
| 1749 | allocated: bool = false, | ||
| 1665 | 1750 | ||
| 1666 | fn @"export"(m: AvMetadata, zig_object: *ZigObject, name: []const u8) ?*u32 { | 1751 | fn @"export"(m: AvMetadata, zig_object: *ZigObject, name: []const u8) ?*u32 { |
| 1667 | for (m.exports.items) |*exp| { | 1752 | for (m.exports.items) |*exp| { |
| ... | @@ -1672,6 +1757,32 @@ const AvMetadata = struct { | ... | @@ -1672,6 +1757,32 @@ const AvMetadata = struct { |
| 1672 | } | 1757 | } |
| 1673 | }; | 1758 | }; |
| 1674 | 1759 | ||
| 1760 | fn checkNavAllocated(pt: Zcu.PerThread, index: InternPool.Nav.Index, meta: AvMetadata) void { | ||
| 1761 | if (!meta.allocated) { | ||
| 1762 | const zcu = pt.zcu; | ||
| 1763 | const ip = &zcu.intern_pool; | ||
| 1764 | const nav = ip.getNav(index); | ||
| 1765 | log.err("NAV {}({d}) assigned symbol {d} but not allocated!", .{ | ||
| 1766 | nav.fqn.fmt(ip), | ||
| 1767 | index, | ||
| 1768 | meta.symbol_index, | ||
| 1769 | }); | ||
| 1770 | } | ||
| 1771 | } | ||
| 1772 | |||
| 1773 | fn checkUavAllocated(pt: Zcu.PerThread, index: InternPool.Index, meta: AvMetadata) void { | ||
| 1774 | if (!meta.allocated) { | ||
| 1775 | const zcu = pt.zcu; | ||
| 1776 | const uav = Value.fromInterned(index); | ||
| 1777 | const ty = uav.typeOf(zcu); | ||
| 1778 | log.err("UAV {}({d}) assigned symbol {d} but not allocated!", .{ | ||
| 1779 | ty.fmt(pt), | ||
| 1780 | index, | ||
| 1781 | meta.symbol_index, | ||
| 1782 | }); | ||
| 1783 | } | ||
| 1784 | } | ||
| 1785 | |||
| 1675 | const TlsVariable = struct { | 1786 | const TlsVariable = struct { |
| 1676 | symbol_index: Symbol.Index, | 1787 | symbol_index: Symbol.Index, |
| 1677 | code: []const u8 = &[0]u8{}, | 1788 | code: []const u8 = &[0]u8{}, |
| ... | @@ -1682,12 +1793,26 @@ const TlsVariable = struct { | ... | @@ -1682,12 +1793,26 @@ const TlsVariable = struct { |
| 1682 | }; | 1793 | }; |
| 1683 | 1794 | ||
| 1684 | const AtomList = std.ArrayListUnmanaged(Atom.Index); | 1795 | const AtomList = std.ArrayListUnmanaged(Atom.Index); |
| 1685 | const NavTable = std.AutoHashMapUnmanaged(InternPool.Nav.Index, AvMetadata); | 1796 | const NavTable = std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, AvMetadata); |
| 1686 | const UavTable = std.AutoHashMapUnmanaged(InternPool.Index, AvMetadata); | 1797 | const UavTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, AvMetadata); |
| 1687 | const LazySymbolTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, LazySymbolMetadata); | 1798 | const LazySymbolTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, LazySymbolMetadata); |
| 1688 | const TlsTable = std.AutoArrayHashMapUnmanaged(Atom.Index, TlsVariable); | 1799 | const TlsTable = std.AutoArrayHashMapUnmanaged(Atom.Index, TlsVariable); |
| 1689 | 1800 | ||
| 1801 | const x86_64 = struct { | ||
| 1802 | fn writeTrampolineCode(source_addr: i64, target_addr: i64, buf: *[max_trampoline_len]u8) ![]u8 { | ||
| 1803 | const disp = @as(i64, @intCast(target_addr)) - source_addr - 5; | ||
| 1804 | var bytes = [_]u8{ | ||
| 1805 | 0xe9, 0x00, 0x00, 0x00, 0x00, // jmp rel32 | ||
| 1806 | }; | ||
| 1807 | assert(bytes.len == trampolineSize(.x86_64)); | ||
| 1808 | mem.writeInt(i32, bytes[1..][0..4], @intCast(disp), .little); | ||
| 1809 | @memcpy(buf[0..bytes.len], &bytes); | ||
| 1810 | return buf[0..bytes.len]; | ||
| 1811 | } | ||
| 1812 | }; | ||
| 1813 | |||
| 1690 | const assert = std.debug.assert; | 1814 | const assert = std.debug.assert; |
| 1815 | const build_options = @import("build_options"); | ||
| 1691 | const builtin = @import("builtin"); | 1816 | const builtin = @import("builtin"); |
| 1692 | const codegen = @import("../../codegen.zig"); | 1817 | const codegen = @import("../../codegen.zig"); |
| 1693 | const elf = std.elf; | 1818 | const elf = std.elf; |
src/link/Elf/relocation.zig+5-13| ... | @@ -112,19 +112,11 @@ fn formatRelocType( | ... | @@ -112,19 +112,11 @@ fn formatRelocType( |
| 112 | _ = unused_fmt_string; | 112 | _ = unused_fmt_string; |
| 113 | _ = options; | 113 | _ = options; |
| 114 | const r_type = ctx.r_type; | 114 | const r_type = ctx.r_type; |
| 115 | switch (r_type) { | 115 | switch (ctx.cpu_arch) { |
| 116 | Elf.R_ZIG_GOT32 => try writer.writeAll("R_ZIG_GOT32"), | 116 | .x86_64 => try writer.print("R_X86_64_{s}", .{@tagName(@as(elf.R_X86_64, @enumFromInt(r_type)))}), |
| 117 | Elf.R_ZIG_GOTPCREL => try writer.writeAll("R_ZIG_GOTPCREL"), | 117 | .aarch64 => try writer.print("R_AARCH64_{s}", .{@tagName(@as(elf.R_AARCH64, @enumFromInt(r_type)))}), |
| 118 | Elf.R_ZIG_GOT_HI20 => try writer.writeAll("R_ZIG_GOT_HI20"), | 118 | .riscv64 => try writer.print("R_RISCV_{s}", .{@tagName(@as(elf.R_RISCV, @enumFromInt(r_type)))}), |
| 119 | Elf.R_ZIG_GOT_LO12 => try writer.writeAll("R_ZIG_GOT_LO12"), | 119 | else => unreachable, |
| 120 | Elf.R_GOT_HI20_STATIC => try writer.writeAll("R_GOT_HI20_STATIC"), | ||
| 121 | Elf.R_GOT_LO12_I_STATIC => try writer.writeAll("R_GOT_LO12_I_STATIC"), | ||
| 122 | else => switch (ctx.cpu_arch) { | ||
| 123 | .x86_64 => try writer.print("R_X86_64_{s}", .{@tagName(@as(elf.R_X86_64, @enumFromInt(r_type)))}), | ||
| 124 | .aarch64 => try writer.print("R_AARCH64_{s}", .{@tagName(@as(elf.R_AARCH64, @enumFromInt(r_type)))}), | ||
| 125 | .riscv64 => try writer.print("R_RISCV_{s}", .{@tagName(@as(elf.R_RISCV, @enumFromInt(r_type)))}), | ||
| 126 | else => unreachable, | ||
| 127 | }, | ||
| 128 | } | 120 | } |
| 129 | } | 121 | } |
| 130 | 122 |
src/link/Elf/synthetic_sections.zig-209| ... | @@ -223,215 +223,6 @@ pub const DynamicSection = struct { | ... | @@ -223,215 +223,6 @@ pub const DynamicSection = struct { |
| 223 | } | 223 | } |
| 224 | }; | 224 | }; |
| 225 | 225 | ||
| 226 | pub const ZigGotSection = struct { | ||
| 227 | entries: std.ArrayListUnmanaged(Symbol.Index) = .{}, | ||
| 228 | output_symtab_ctx: Elf.SymtabCtx = .{}, | ||
| 229 | flags: Flags = .{}, | ||
| 230 | |||
| 231 | const Flags = packed struct { | ||
| 232 | needs_rela: bool = false, | ||
| 233 | dirty: bool = false, | ||
| 234 | }; | ||
| 235 | |||
| 236 | pub const Index = u32; | ||
| 237 | |||
| 238 | pub fn deinit(zig_got: *ZigGotSection, allocator: Allocator) void { | ||
| 239 | zig_got.entries.deinit(allocator); | ||
| 240 | } | ||
| 241 | |||
| 242 | fn allocateEntry(zig_got: *ZigGotSection, allocator: Allocator) !Index { | ||
| 243 | try zig_got.entries.ensureUnusedCapacity(allocator, 1); | ||
| 244 | // TODO add free list | ||
| 245 | const index = @as(Index, @intCast(zig_got.entries.items.len)); | ||
| 246 | _ = zig_got.entries.addOneAssumeCapacity(); | ||
| 247 | zig_got.flags.dirty = true; | ||
| 248 | return index; | ||
| 249 | } | ||
| 250 | |||
| 251 | pub fn addSymbol(zig_got: *ZigGotSection, sym_index: Symbol.Index, elf_file: *Elf) !Index { | ||
| 252 | const comp = elf_file.base.comp; | ||
| 253 | const gpa = comp.gpa; | ||
| 254 | const zo = elf_file.zigObjectPtr().?; | ||
| 255 | const index = try zig_got.allocateEntry(gpa); | ||
| 256 | const entry = &zig_got.entries.items[index]; | ||
| 257 | entry.* = sym_index; | ||
| 258 | const symbol = zo.symbol(sym_index); | ||
| 259 | symbol.flags.has_zig_got = true; | ||
| 260 | if (elf_file.isEffectivelyDynLib() or (elf_file.base.isExe() and comp.config.pie)) { | ||
| 261 | zig_got.flags.needs_rela = true; | ||
| 262 | } | ||
| 263 | symbol.addExtra(.{ .zig_got = index }, elf_file); | ||
| 264 | return index; | ||
| 265 | } | ||
| 266 | |||
| 267 | pub fn entryOffset(zig_got: ZigGotSection, index: Index, elf_file: *Elf) u64 { | ||
| 268 | _ = zig_got; | ||
| 269 | const entry_size = elf_file.archPtrWidthBytes(); | ||
| 270 | const shdr = elf_file.shdrs.items[elf_file.zig_got_section_index.?]; | ||
| 271 | return shdr.sh_offset + @as(u64, entry_size) * index; | ||
| 272 | } | ||
| 273 | |||
| 274 | pub fn entryAddress(zig_got: ZigGotSection, index: Index, elf_file: *Elf) i64 { | ||
| 275 | _ = zig_got; | ||
| 276 | const entry_size = elf_file.archPtrWidthBytes(); | ||
| 277 | const shdr = elf_file.shdrs.items[elf_file.zig_got_section_index.?]; | ||
| 278 | return @as(i64, @intCast(shdr.sh_addr)) + entry_size * index; | ||
| 279 | } | ||
| 280 | |||
| 281 | pub fn size(zig_got: ZigGotSection, elf_file: *Elf) usize { | ||
| 282 | return elf_file.archPtrWidthBytes() * zig_got.entries.items.len; | ||
| 283 | } | ||
| 284 | |||
| 285 | pub fn writeOne(zig_got: *ZigGotSection, elf_file: *Elf, index: Index) !void { | ||
| 286 | const zo = elf_file.zigObjectPtr().?; | ||
| 287 | if (zig_got.flags.dirty) { | ||
| 288 | const needed_size = zig_got.size(elf_file); | ||
| 289 | try elf_file.growAllocSection(elf_file.zig_got_section_index.?, needed_size); | ||
| 290 | zig_got.flags.dirty = false; | ||
| 291 | } | ||
| 292 | const entry_size: u16 = elf_file.archPtrWidthBytes(); | ||
| 293 | const target = elf_file.getTarget(); | ||
| 294 | const endian = target.cpu.arch.endian(); | ||
| 295 | const off = zig_got.entryOffset(index, elf_file); | ||
| 296 | const vaddr: u64 = @intCast(zig_got.entryAddress(index, elf_file)); | ||
| 297 | const entry = zig_got.entries.items[index]; | ||
| 298 | const value = zo.symbol(entry).address(.{}, elf_file); | ||
| 299 | switch (entry_size) { | ||
| 300 | 2 => { | ||
| 301 | var buf: [2]u8 = undefined; | ||
| 302 | std.mem.writeInt(u16, &buf, @intCast(value), endian); | ||
| 303 | try elf_file.base.file.?.pwriteAll(&buf, off); | ||
| 304 | }, | ||
| 305 | 4 => { | ||
| 306 | var buf: [4]u8 = undefined; | ||
| 307 | std.mem.writeInt(u32, &buf, @intCast(value), endian); | ||
| 308 | try elf_file.base.file.?.pwriteAll(&buf, off); | ||
| 309 | }, | ||
| 310 | 8 => { | ||
| 311 | var buf: [8]u8 = undefined; | ||
| 312 | std.mem.writeInt(u64, &buf, @intCast(value), endian); | ||
| 313 | try elf_file.base.file.?.pwriteAll(&buf, off); | ||
| 314 | |||
| 315 | if (elf_file.base.child_pid) |pid| { | ||
| 316 | switch (builtin.os.tag) { | ||
| 317 | .linux => { | ||
| 318 | var local_vec: [1]std.posix.iovec_const = .{.{ | ||
| 319 | .base = &buf, | ||
| 320 | .len = buf.len, | ||
| 321 | }}; | ||
| 322 | var remote_vec: [1]std.posix.iovec_const = .{.{ | ||
| 323 | .base = @as([*]u8, @ptrFromInt(@as(usize, @intCast(vaddr)))), | ||
| 324 | .len = buf.len, | ||
| 325 | }}; | ||
| 326 | const rc = std.os.linux.process_vm_writev(pid, &local_vec, &remote_vec, 0); | ||
| 327 | switch (std.os.linux.E.init(rc)) { | ||
| 328 | .SUCCESS => assert(rc == buf.len), | ||
| 329 | else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}), | ||
| 330 | } | ||
| 331 | }, | ||
| 332 | else => return error.HotSwapUnavailableOnHostOperatingSystem, | ||
| 333 | } | ||
| 334 | } | ||
| 335 | }, | ||
| 336 | else => unreachable, | ||
| 337 | } | ||
| 338 | } | ||
| 339 | |||
| 340 | pub fn writeAll(zig_got: ZigGotSection, elf_file: *Elf, writer: anytype) !void { | ||
| 341 | const zo = elf_file.zigObjectPtr().?; | ||
| 342 | for (zig_got.entries.items) |entry| { | ||
| 343 | const symbol = zo.symbol(entry); | ||
| 344 | const value = symbol.address(.{ .plt = false }, elf_file); | ||
| 345 | try writeInt(value, elf_file, writer); | ||
| 346 | } | ||
| 347 | } | ||
| 348 | |||
| 349 | pub fn numRela(zig_got: ZigGotSection) usize { | ||
| 350 | return zig_got.entries.items.len; | ||
| 351 | } | ||
| 352 | |||
| 353 | pub fn addRela(zig_got: ZigGotSection, elf_file: *Elf) !void { | ||
| 354 | const comp = elf_file.base.comp; | ||
| 355 | const gpa = comp.gpa; | ||
| 356 | const cpu_arch = elf_file.getTarget().cpu.arch; | ||
| 357 | const zo = elf_file.zigObjectPtr().?; | ||
| 358 | try elf_file.rela_dyn.ensureUnusedCapacity(gpa, zig_got.numRela()); | ||
| 359 | for (zig_got.entries.items) |entry| { | ||
| 360 | const symbol = zo.symbol(entry); | ||
| 361 | const offset = symbol.zigGotAddress(elf_file); | ||
| 362 | elf_file.addRelaDynAssumeCapacity(.{ | ||
| 363 | .offset = @intCast(offset), | ||
| 364 | .type = relocation.encode(.rel, cpu_arch), | ||
| 365 | .addend = symbol.address(.{ .plt = false }, elf_file), | ||
| 366 | }); | ||
| 367 | } | ||
| 368 | } | ||
| 369 | |||
| 370 | pub fn updateSymtabSize(zig_got: *ZigGotSection, elf_file: *Elf) void { | ||
| 371 | const zo = elf_file.zigObjectPtr().?; | ||
| 372 | zig_got.output_symtab_ctx.nlocals = @as(u32, @intCast(zig_got.entries.items.len)); | ||
| 373 | for (zig_got.entries.items) |entry| { | ||
| 374 | const name = zo.symbol(entry).name(elf_file); | ||
| 375 | zig_got.output_symtab_ctx.strsize += @as(u32, @intCast(name.len + "$ziggot".len)) + 1; | ||
| 376 | } | ||
| 377 | } | ||
| 378 | |||
| 379 | pub fn writeSymtab(zig_got: ZigGotSection, elf_file: *Elf) void { | ||
| 380 | const zo = elf_file.zigObjectPtr().?; | ||
| 381 | for (zig_got.entries.items, zig_got.output_symtab_ctx.ilocal.., 0..) |entry, ilocal, index| { | ||
| 382 | const symbol = zo.symbol(entry); | ||
| 383 | const symbol_name = symbol.name(elf_file); | ||
| 384 | const st_name = @as(u32, @intCast(elf_file.strtab.items.len)); | ||
| 385 | elf_file.strtab.appendSliceAssumeCapacity(symbol_name); | ||
| 386 | elf_file.strtab.appendSliceAssumeCapacity("$ziggot"); | ||
| 387 | elf_file.strtab.appendAssumeCapacity(0); | ||
| 388 | const st_value = zig_got.entryAddress(@intCast(index), elf_file); | ||
| 389 | const st_size = elf_file.archPtrWidthBytes(); | ||
| 390 | elf_file.symtab.items[ilocal] = .{ | ||
| 391 | .st_name = st_name, | ||
| 392 | .st_info = elf.STT_OBJECT, | ||
| 393 | .st_other = 0, | ||
| 394 | .st_shndx = @intCast(elf_file.zig_got_section_index.?), | ||
| 395 | .st_value = @intCast(st_value), | ||
| 396 | .st_size = st_size, | ||
| 397 | }; | ||
| 398 | } | ||
| 399 | } | ||
| 400 | |||
| 401 | const FormatCtx = struct { | ||
| 402 | zig_got: ZigGotSection, | ||
| 403 | elf_file: *Elf, | ||
| 404 | }; | ||
| 405 | |||
| 406 | pub fn fmt(zig_got: ZigGotSection, elf_file: *Elf) std.fmt.Formatter(format2) { | ||
| 407 | return .{ .data = .{ .zig_got = zig_got, .elf_file = elf_file } }; | ||
| 408 | } | ||
| 409 | |||
| 410 | pub fn format2( | ||
| 411 | ctx: FormatCtx, | ||
| 412 | comptime unused_fmt_string: []const u8, | ||
| 413 | options: std.fmt.FormatOptions, | ||
| 414 | writer: anytype, | ||
| 415 | ) !void { | ||
| 416 | _ = options; | ||
| 417 | _ = unused_fmt_string; | ||
| 418 | const zig_got = ctx.zig_got; | ||
| 419 | const elf_file = ctx.elf_file; | ||
| 420 | try writer.writeAll(".zig.got\n"); | ||
| 421 | for (zig_got.entries.items, 0..) |entry, index| { | ||
| 422 | const zo = elf_file.zigObjectPtr().?; | ||
| 423 | const symbol = zo.symbol(entry); | ||
| 424 | try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{ | ||
| 425 | index, | ||
| 426 | zig_got.entryAddress(@intCast(index), elf_file), | ||
| 427 | entry, | ||
| 428 | symbol.address(.{}, elf_file), | ||
| 429 | symbol.name(elf_file), | ||
| 430 | }); | ||
| 431 | } | ||
| 432 | } | ||
| 433 | }; | ||
| 434 | |||
| 435 | pub const GotSection = struct { | 226 | pub const GotSection = struct { |
| 436 | entries: std.ArrayListUnmanaged(Entry) = .{}, | 227 | entries: std.ArrayListUnmanaged(Entry) = .{}, |
| 437 | output_symtab_ctx: Elf.SymtabCtx = .{}, | 228 | output_symtab_ctx: Elf.SymtabCtx = .{}, |
test/behavior/basic.zig-1| ... | @@ -733,7 +733,6 @@ test "extern variable with non-pointer opaque type" { | ... | @@ -733,7 +733,6 @@ test "extern variable with non-pointer opaque type" { |
| 733 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | 733 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 734 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; | 734 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; |
| 735 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO | 735 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO |
| 736 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 737 | 736 | ||
| 738 | @export(var_to_export, .{ .name = "opaque_extern_var" }); | 737 | @export(var_to_export, .{ .name = "opaque_extern_var" }); |
| 739 | try expect(@as(*align(1) u32, @ptrCast(&opaque_extern_var)).* == 42); | 738 | try expect(@as(*align(1) u32, @ptrCast(&opaque_extern_var)).* == 42); |
test/behavior/export_builtin.zig-2| ... | @@ -48,7 +48,6 @@ test "exporting using field access" { | ... | @@ -48,7 +48,6 @@ test "exporting using field access" { |
| 48 | test "exporting comptime-known value" { | 48 | test "exporting comptime-known value" { |
| 49 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | 49 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 50 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 50 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 51 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 52 | if (builtin.zig_backend == .stage2_x86_64 and | 51 | if (builtin.zig_backend == .stage2_x86_64 and |
| 53 | (builtin.target.ofmt != .elf and | 52 | (builtin.target.ofmt != .elf and |
| 54 | builtin.target.ofmt != .macho and | 53 | builtin.target.ofmt != .macho and |
| ... | @@ -68,7 +67,6 @@ test "exporting comptime-known value" { | ... | @@ -68,7 +67,6 @@ test "exporting comptime-known value" { |
| 68 | test "exporting comptime var" { | 67 | test "exporting comptime var" { |
| 69 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | 68 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 70 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 69 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 71 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 72 | if (builtin.zig_backend == .stage2_x86_64 and | 70 | if (builtin.zig_backend == .stage2_x86_64 and |
| 73 | (builtin.target.ofmt != .elf and | 71 | (builtin.target.ofmt != .elf and |
| 74 | builtin.target.ofmt != .macho and | 72 | builtin.target.ofmt != .macho and |
test/behavior/extern.zig-1| ... | @@ -7,7 +7,6 @@ test "anyopaque extern symbol" { | ... | @@ -7,7 +7,6 @@ test "anyopaque extern symbol" { |
| 7 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | 7 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 8 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; | 8 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; |
| 9 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | 9 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 10 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 11 | 10 | ||
| 12 | const a = @extern(*anyopaque, .{ .name = "a_mystery_symbol" }); | 11 | const a = @extern(*anyopaque, .{ .name = "a_mystery_symbol" }); |
| 13 | const b: *i32 = @alignCast(@ptrCast(a)); | 12 | const b: *i32 = @alignCast(@ptrCast(a)); |
test/behavior/fn.zig-1| ... | @@ -429,7 +429,6 @@ test "implicit cast function to function ptr" { | ... | @@ -429,7 +429,6 @@ test "implicit cast function to function ptr" { |
| 429 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 429 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 430 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | 430 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 431 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; | 431 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; |
| 432 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 433 | 432 | ||
| 434 | const S1 = struct { | 433 | const S1 = struct { |
| 435 | export fn someFunctionThatReturnsAValue() c_int { | 434 | export fn someFunctionThatReturnsAValue() c_int { |
test/behavior/pointers.zig-1| ... | @@ -45,7 +45,6 @@ test "pointer-integer arithmetic" { | ... | @@ -45,7 +45,6 @@ test "pointer-integer arithmetic" { |
| 45 | 45 | ||
| 46 | test "pointer subtraction" { | 46 | test "pointer subtraction" { |
| 47 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 47 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 48 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 49 | 48 | ||
| 50 | { | 49 | { |
| 51 | const a: *u8 = @ptrFromInt(100); | 50 | const a: *u8 = @ptrFromInt(100); |
test/link/elf.zig+20-4| ... | @@ -1773,25 +1773,41 @@ fn testImportingDataDynamic(b: *Build, opts: Options) *Step { | ... | @@ -1773,25 +1773,41 @@ fn testImportingDataDynamic(b: *Build, opts: Options) *Step { |
| 1773 | .use_llvm = true, | 1773 | .use_llvm = true, |
| 1774 | }, .{ | 1774 | }, .{ |
| 1775 | .name = "a", | 1775 | .name = "a", |
| 1776 | .c_source_bytes = "int foo = 42;", | 1776 | .c_source_bytes = |
| 1777 | \\#include <stdio.h> | ||
| 1778 | \\int foo = 42; | ||
| 1779 | \\void printFoo() { fprintf(stderr, "lib foo=%d\n", foo); } | ||
| 1780 | , | ||
| 1777 | }); | 1781 | }); |
| 1782 | dso.linkLibC(); | ||
| 1778 | 1783 | ||
| 1779 | const main = addExecutable(b, opts, .{ | 1784 | const main = addExecutable(b, opts, .{ |
| 1780 | .name = "main", | 1785 | .name = "main", |
| 1781 | .zig_source_bytes = | 1786 | .zig_source_bytes = |
| 1787 | \\const std = @import("std"); | ||
| 1782 | \\extern var foo: i32; | 1788 | \\extern var foo: i32; |
| 1789 | \\extern fn printFoo() void; | ||
| 1783 | \\pub fn main() void { | 1790 | \\pub fn main() void { |
| 1784 | \\ @import("std").debug.print("{d}\n", .{foo}); | 1791 | \\ std.debug.print("exe foo={d}\n", .{foo}); |
| 1792 | \\ printFoo(); | ||
| 1793 | \\ foo += 1; | ||
| 1794 | \\ std.debug.print("exe foo={d}\n", .{foo}); | ||
| 1795 | \\ printFoo(); | ||
| 1785 | \\} | 1796 | \\} |
| 1786 | , | 1797 | , |
| 1787 | .strip = true, // TODO temp hack | 1798 | .strip = true, // TODO temp hack |
| 1788 | }); | 1799 | }); |
| 1789 | main.pie = true; | 1800 | main.pie = true; |
| 1790 | main.linkLibrary(dso); | 1801 | main.linkLibrary(dso); |
| 1791 | main.linkLibC(); | ||
| 1792 | 1802 | ||
| 1793 | const run = addRunArtifact(main); | 1803 | const run = addRunArtifact(main); |
| 1794 | run.expectStdErrEqual("42\n"); | 1804 | run.expectStdErrEqual( |
| 1805 | \\exe foo=42 | ||
| 1806 | \\lib foo=42 | ||
| 1807 | \\exe foo=43 | ||
| 1808 | \\lib foo=43 | ||
| 1809 | \\ | ||
| 1810 | ); | ||
| 1795 | test_step.dependOn(&run.step); | 1811 | test_step.dependOn(&run.step); |
| 1796 | 1812 | ||
| 1797 | return test_step; | 1813 | return test_step; |