authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-12-22 23:07:46+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-12-22 23:07:46+01:00
log362eccf539db6bb89e222916f3c4a45b0eb2bece
treeffb37c893f424f29589dcba0926d0df0562abad4
parentb40e5adf54de878c2745bcf6e266239b7f5c40b6

stage2: handle RIP relative addressing in MI, RM and MR


1 files changed, 47 insertions(+), 47 deletions(-)

src/arch/x86_64/Emit.zig+47-47
...@@ -581,6 +581,7 @@ inline fn getOpCode(tag: Mir.Inst.Tag, enc: Encoding) u8 {...@@ -581,6 +581,7 @@ inline fn getOpCode(tag: Mir.Inst.Tag, enc: Encoding) u8 {
581 .sbb => 0x1b,581 .sbb => 0x1b,
582 .cmp => 0x3b,582 .cmp => 0x3b,
583 .mov => 0x8b,583 .mov => 0x8b,
584 .lea => 0x8d,
584 else => unreachable,585 else => unreachable,
585 },586 },
586 .oi => return switch (tag) {587 .oi => return switch (tag) {
...@@ -621,6 +622,7 @@ const ScaleIndexBase = struct {...@@ -621,6 +622,7 @@ const ScaleIndexBase = struct {
621622
622const Memory = struct {623const Memory = struct {
623 reg: ?Register,624 reg: ?Register,
625 rip: bool = false,
624 disp: i32,626 disp: i32,
625 sib: ?ScaleIndexBase = null,627 sib: ?ScaleIndexBase = null,
626};628};
...@@ -641,6 +643,16 @@ const RegisterOrMemory = union(enum) {...@@ -641,6 +643,16 @@ const RegisterOrMemory = union(enum) {
641 },643 },
642 };644 };
643 }645 }
646
647 fn rip(disp: i32) RegisterOrMemory {
648 return .{
649 .memory = .{
650 .reg = null,
651 .rip = true,
652 .disp = disp,
653 },
654 };
655 }
644};656};
645657
646fn lowerToTdEnc(658fn lowerToTdEnc(
...@@ -813,8 +825,12 @@ fn lowerToMiEnc(...@@ -813,8 +825,12 @@ fn lowerToMiEnc(
813 }825 }
814 } else {826 } else {
815 encoder.opcode_1byte(opc);827 encoder.opcode_1byte(opc);
816 encoder.modRm_SIBDisp0(modrm_ext);828 if (dst_mem.rip) {
817 encoder.sib_disp32();829 encoder.modRm_RIPDisp32(modrm_ext);
830 } else {
831 encoder.modRm_SIBDisp0(modrm_ext);
832 encoder.sib_disp32();
833 }
818 encoder.disp32(dst_mem.disp);834 encoder.disp32(dst_mem.disp);
819 }835 }
820 encoder.imm32(imm);836 encoder.imm32(imm);
...@@ -880,8 +896,12 @@ fn lowerToRmEnc(...@@ -880,8 +896,12 @@ fn lowerToRmEnc(
880 .r = reg.isExtended(),896 .r = reg.isExtended(),
881 });897 });
882 encoder.opcode_1byte(opc);898 encoder.opcode_1byte(opc);
883 encoder.modRm_SIBDisp0(reg.lowId());899 if (src_mem.rip) {
884 encoder.sib_disp32();900 encoder.modRm_RIPDisp32(reg.lowId());
901 } else {
902 encoder.modRm_SIBDisp0(reg.lowId());
903 encoder.sib_disp32();
904 }
885 encoder.disp32(src_mem.disp);905 encoder.disp32(src_mem.disp);
886 }906 }
887 },907 },
...@@ -950,8 +970,12 @@ fn lowerToMrEnc(...@@ -950,8 +970,12 @@ fn lowerToMrEnc(
950 .r = reg.isExtended(),970 .r = reg.isExtended(),
951 });971 });
952 encoder.opcode_1byte(opc);972 encoder.opcode_1byte(opc);
953 encoder.modRm_SIBDisp0(reg.lowId());973 if (dst_mem.rip) {
954 encoder.sib_disp32();974 encoder.modRm_RIPDisp32(reg.lowId());
975 } else {
976 encoder.modRm_SIBDisp0(reg.lowId());
977 encoder.sib_disp32();
978 }
955 encoder.disp32(dst_mem.disp);979 encoder.disp32(dst_mem.disp);
956 }980 }
957 },981 },
...@@ -1206,37 +1230,7 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -1206,37 +1230,7 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
1206 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);1230 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
1207 assert(ops.flags == 0b01);1231 assert(ops.flags == 0b01);
1208 const imm = emit.mir.instructions.items(.data)[inst].imm;1232 const imm = emit.mir.instructions.items(.data)[inst].imm;
12091233 return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.mem(ops.reg2, imm), emit.code);
1210 if (imm == 0) {
1211 const encoder = try Encoder.init(emit.code, 3);
1212 encoder.rex(.{
1213 .w = ops.reg1.size() == 64,
1214 .r = ops.reg1.isExtended(),
1215 .b = ops.reg2.isExtended(),
1216 });
1217 encoder.opcode_1byte(0x8d);
1218 encoder.modRm_indirectDisp0(ops.reg1.lowId(), ops.reg2.lowId());
1219 } else if (imm <= math.maxInt(i8)) {
1220 const encoder = try Encoder.init(emit.code, 4);
1221 encoder.rex(.{
1222 .w = ops.reg1.size() == 64,
1223 .r = ops.reg1.isExtended(),
1224 .b = ops.reg2.isExtended(),
1225 });
1226 encoder.opcode_1byte(0x8d);
1227 encoder.modRm_indirectDisp8(ops.reg1.lowId(), ops.reg2.lowId());
1228 encoder.disp8(@intCast(i8, imm));
1229 } else {
1230 const encoder = try Encoder.init(emit.code, 7);
1231 encoder.rex(.{
1232 .w = ops.reg1.size() == 64,
1233 .r = ops.reg1.isExtended(),
1234 .b = ops.reg2.isExtended(),
1235 });
1236 encoder.opcode_1byte(0x8d);
1237 encoder.modRm_indirectDisp32(ops.reg1.lowId(), ops.reg2.lowId());
1238 encoder.disp32(imm);
1239 }
1240}1234}
12411235
1242fn mirLeaRip(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {1236fn mirLeaRip(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
...@@ -1244,26 +1238,22 @@ fn mirLeaRip(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -1244,26 +1238,22 @@ fn mirLeaRip(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
1244 assert(tag == .lea_rip);1238 assert(tag == .lea_rip);
1245 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);1239 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
1246 const start_offset = emit.code.items.len;1240 const start_offset = emit.code.items.len;
1247 const encoder = try Encoder.init(emit.code, 7);1241 try lowerToRmEnc(.lea, ops.reg1, RegisterOrMemory.rip(0), emit.code);
1248 encoder.rex(.{
1249 .w = ops.reg1.size() == 64,
1250 .r = ops.reg1.isExtended(),
1251 });
1252 encoder.opcode_1byte(0x8d);
1253 encoder.modRm_RIPDisp32(ops.reg1.lowId());
1254 const end_offset = emit.code.items.len;1242 const end_offset = emit.code.items.len;
1255 if (@truncate(u1, ops.flags) == 0b0) {1243 if (@truncate(u1, ops.flags) == 0b0) {
1244 // Backpatch the displacement
1245 // TODO figure out if this can be simplified
1256 const payload = emit.mir.instructions.items(.data)[inst].payload;1246 const payload = emit.mir.instructions.items(.data)[inst].payload;
1257 const imm = emit.mir.extraData(Mir.Imm64, payload).data.decode();1247 const imm = emit.mir.extraData(Mir.Imm64, payload).data.decode();
1258 encoder.disp32(@intCast(i32, @intCast(i64, imm) - @intCast(i64, end_offset - start_offset + 4)));1248 const disp = @intCast(i32, @intCast(i64, imm) - @intCast(i64, end_offset - start_offset));
1249 mem.writeIntLittle(i32, emit.code.items[end_offset - 4 ..][0..4], disp);
1259 } else {1250 } else {
1260 const got_entry = emit.mir.instructions.items(.data)[inst].got_entry;1251 const got_entry = emit.mir.instructions.items(.data)[inst].got_entry;
1261 encoder.disp32(0);
1262 if (emit.bin_file.cast(link.File.MachO)) |macho_file| {1252 if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
1263 // TODO I think the reloc might be in the wrong place.1253 // TODO I think the reloc might be in the wrong place.
1264 const decl = macho_file.active_decl.?;1254 const decl = macho_file.active_decl.?;
1265 try decl.link.macho.relocs.append(emit.bin_file.allocator, .{1255 try decl.link.macho.relocs.append(emit.bin_file.allocator, .{
1266 .offset = @intCast(u32, end_offset),1256 .offset = @intCast(u32, end_offset - 4),
1267 .target = .{ .local = got_entry },1257 .target = .{ .local = got_entry },
1268 .addend = 0,1258 .addend = 0,
1269 .subtractor = null,1259 .subtractor = null,
...@@ -1530,6 +1520,12 @@ test "lower MI encoding" {...@@ -1530,6 +1520,12 @@ test "lower MI encoding" {
1530 code.emitted(),1520 code.emitted(),
1531 "and dword ptr [r12 + 0x10000000], 0x10",1521 "and dword ptr [r12 + 0x10000000], 0x10",
1532 );1522 );
1523 try lowerToMiEnc(.mov, RegisterOrMemory.rip(0x10), 0x10, code.buffer());
1524 try expectEqualHexStrings(
1525 "\xC7\x05\x10\x00\x00\x00\x10\x00\x00\x00",
1526 code.emitted(),
1527 "mov [rip + 0x10], 0x10",
1528 );
1533}1529}
15341530
1535test "lower RM encoding" {1531test "lower RM encoding" {
...@@ -1565,6 +1561,8 @@ test "lower RM encoding" {...@@ -1565,6 +1561,8 @@ test "lower RM encoding" {
1565 );1561 );
1566 try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.rbp, -4), code.buffer());1562 try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.rbp, -4), code.buffer());
1567 try expectEqualHexStrings("\x48\x8B\x45\xFC", code.emitted(), "mov rax, qword ptr [rbp - 4]");1563 try expectEqualHexStrings("\x48\x8B\x45\xFC", code.emitted(), "mov rax, qword ptr [rbp - 4]");
1564 try lowerToRmEnc(.lea, .rax, RegisterOrMemory.rip(0x10), code.buffer());
1565 try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", code.emitted(), "lea rax, [rip + 0x10]");
1568}1566}
15691567
1570test "lower MR encoding" {1568test "lower MR encoding" {
...@@ -1592,6 +1590,8 @@ test "lower MR encoding" {...@@ -1592,6 +1590,8 @@ test "lower MR encoding" {
1592 code.emitted(),1590 code.emitted(),
1593 "sub qword ptr [r11 + 0x10000000], r12",1591 "sub qword ptr [r11 + 0x10000000], r12",
1594 );1592 );
1593 try lowerToMrEnc(.mov, RegisterOrMemory.rip(0x10), .r12, code.buffer());
1594 try expectEqualHexStrings("\x4C\x89\x25\x10\x00\x00\x00", code.emitted(), "mov qword ptr [rip + 0x10], r12");
1595}1595}
15961596
1597test "lower OI encoding" {1597test "lower OI encoding" {