| ... | ... | @@ -227,89 +227,81 @@ pub const Instruction = struct { |
| 227 | 227 | }; |
| 228 | 228 | } |
| 229 | 229 | |
| 230 | | fn format(op: Operand, bw: *Writer, comptime unused_format_string: []const u8) !void { |
| 231 | | _ = op; |
| 232 | | _ = bw; |
| 233 | | _ = unused_format_string; |
| 234 | | @compileError("do not format Operand directly; use fmt() instead"); |
| 235 | | } |
| 236 | | |
| 237 | | const FormatContext = struct { |
| 230 | const Format = struct { |
| 238 | 231 | op: Operand, |
| 239 | 232 | enc_op: Encoding.Op, |
| 240 | | }; |
| 241 | 233 | |
| 242 | | fn fmtContext(ctx: FormatContext, bw: *Writer, comptime unused_format_string: []const u8) Writer.Error!void { |
| 243 | | _ = unused_format_string; |
| 244 | | const op = ctx.op; |
| 245 | | const enc_op = ctx.enc_op; |
| 246 | | switch (op) { |
| 247 | | .none => {}, |
| 248 | | .reg => |reg| try bw.writeAll(@tagName(reg)), |
| 249 | | .mem => |mem| switch (mem) { |
| 250 | | .rip => |rip| { |
| 251 | | try bw.print("{f} [rip", .{rip.ptr_size}); |
| 252 | | if (rip.disp != 0) try bw.print(" {c} 0x{x}", .{ |
| 253 | | @as(u8, if (rip.disp < 0) '-' else '+'), |
| 254 | | @abs(rip.disp), |
| 255 | | }); |
| 256 | | try bw.writeByte(']'); |
| 257 | | }, |
| 258 | | .sib => |sib| { |
| 259 | | try bw.print("{f} ", .{sib.ptr_size}); |
| 234 | fn default(f: Format, w: *Writer) Writer.Error!void { |
| 235 | const op = f.op; |
| 236 | const enc_op = f.enc_op; |
| 237 | switch (op) { |
| 238 | .none => {}, |
| 239 | .reg => |reg| try w.writeAll(@tagName(reg)), |
| 240 | .mem => |mem| switch (mem) { |
| 241 | .rip => |rip| { |
| 242 | try w.print("{f} [rip", .{rip.ptr_size}); |
| 243 | if (rip.disp != 0) try w.print(" {c} 0x{x}", .{ |
| 244 | @as(u8, if (rip.disp < 0) '-' else '+'), |
| 245 | @abs(rip.disp), |
| 246 | }); |
| 247 | try w.writeByte(']'); |
| 248 | }, |
| 249 | .sib => |sib| { |
| 250 | try w.print("{f} ", .{sib.ptr_size}); |
| 260 | 251 | |
| 261 | | if (mem.isSegmentRegister()) { |
| 262 | | return bw.print("{s}:0x{x}", .{ @tagName(sib.base.reg), sib.disp }); |
| 263 | | } |
| 252 | if (mem.isSegmentRegister()) { |
| 253 | return w.print("{s}:0x{x}", .{ @tagName(sib.base.reg), sib.disp }); |
| 254 | } |
| 264 | 255 | |
| 265 | | try bw.writeByte('['); |
| 266 | | |
| 267 | | var any = true; |
| 268 | | switch (sib.base) { |
| 269 | | .none => any = false, |
| 270 | | .reg => |reg| try bw.print("{s}", .{@tagName(reg)}), |
| 271 | | .frame => |frame_index| try bw.print("{}", .{frame_index}), |
| 272 | | .table => try bw.print("Table", .{}), |
| 273 | | .rip_inst => |inst_index| try bw.print("RipInst({d})", .{inst_index}), |
| 274 | | .nav => |nav| try bw.print("Nav({d})", .{@intFromEnum(nav)}), |
| 275 | | .uav => |uav| try bw.print("Uav({d})", .{@intFromEnum(uav.val)}), |
| 276 | | .lazy_sym => |lazy_sym| try bw.print("LazySym({s}, {d})", .{ |
| 277 | | @tagName(lazy_sym.kind), |
| 278 | | @intFromEnum(lazy_sym.ty), |
| 279 | | }), |
| 280 | | .extern_func => |extern_func| try bw.print("ExternFunc({d})", .{@intFromEnum(extern_func)}), |
| 281 | | } |
| 282 | | if (mem.scaleIndex()) |si| { |
| 283 | | if (any) try bw.writeAll(" + "); |
| 284 | | try bw.print("{s} * {d}", .{ @tagName(si.index), si.scale }); |
| 285 | | any = true; |
| 286 | | } |
| 287 | | if (sib.disp != 0 or !any) { |
| 288 | | if (any) |
| 289 | | try bw.print(" {c} ", .{@as(u8, if (sib.disp < 0) '-' else '+')}) |
| 290 | | else if (sib.disp < 0) |
| 291 | | try bw.writeByte('-'); |
| 292 | | try bw.print("0x{x}", .{@abs(sib.disp)}); |
| 293 | | any = true; |
| 294 | | } |
| 256 | try w.writeByte('['); |
| 257 | |
| 258 | var any = true; |
| 259 | switch (sib.base) { |
| 260 | .none => any = false, |
| 261 | .reg => |reg| try w.print("{s}", .{@tagName(reg)}), |
| 262 | .frame => |frame_index| try w.print("{}", .{frame_index}), |
| 263 | .table => try w.print("Table", .{}), |
| 264 | .rip_inst => |inst_index| try w.print("RipInst({d})", .{inst_index}), |
| 265 | .nav => |nav| try w.print("Nav({d})", .{@intFromEnum(nav)}), |
| 266 | .uav => |uav| try w.print("Uav({d})", .{@intFromEnum(uav.val)}), |
| 267 | .lazy_sym => |lazy_sym| try w.print("LazySym({s}, {d})", .{ |
| 268 | @tagName(lazy_sym.kind), |
| 269 | @intFromEnum(lazy_sym.ty), |
| 270 | }), |
| 271 | .extern_func => |extern_func| try w.print("ExternFunc({d})", .{@intFromEnum(extern_func)}), |
| 272 | } |
| 273 | if (mem.scaleIndex()) |si| { |
| 274 | if (any) try w.writeAll(" + "); |
| 275 | try w.print("{s} * {d}", .{ @tagName(si.index), si.scale }); |
| 276 | any = true; |
| 277 | } |
| 278 | if (sib.disp != 0 or !any) { |
| 279 | if (any) |
| 280 | try w.print(" {c} ", .{@as(u8, if (sib.disp < 0) '-' else '+')}) |
| 281 | else if (sib.disp < 0) |
| 282 | try w.writeByte('-'); |
| 283 | try w.print("0x{x}", .{@abs(sib.disp)}); |
| 284 | any = true; |
| 285 | } |
| 295 | 286 | |
| 296 | | try bw.writeByte(']'); |
| 287 | try w.writeByte(']'); |
| 288 | }, |
| 289 | .moffs => |moffs| try w.print("{s}:0x{x}", .{ |
| 290 | @tagName(moffs.seg), |
| 291 | moffs.offset, |
| 292 | }), |
| 297 | 293 | }, |
| 298 | | .moffs => |moffs| try bw.print("{s}:0x{x}", .{ |
| 299 | | @tagName(moffs.seg), |
| 300 | | moffs.offset, |
| 301 | | }), |
| 302 | | }, |
| 303 | | .imm => |imm| if (enc_op.isSigned()) { |
| 304 | | const imms = imm.asSigned(enc_op.immBitSize()); |
| 305 | | if (imms < 0) try bw.writeByte('-'); |
| 306 | | try bw.print("0x{x}", .{@abs(imms)}); |
| 307 | | } else try bw.print("0x{x}", .{imm.asUnsigned(enc_op.immBitSize())}), |
| 308 | | .bytes => unreachable, |
| 294 | .imm => |imm| if (enc_op.isSigned()) { |
| 295 | const imms = imm.asSigned(enc_op.immBitSize()); |
| 296 | if (imms < 0) try w.writeByte('-'); |
| 297 | try w.print("0x{x}", .{@abs(imms)}); |
| 298 | } else try w.print("0x{x}", .{imm.asUnsigned(enc_op.immBitSize())}), |
| 299 | .bytes => unreachable, |
| 300 | } |
| 309 | 301 | } |
| 310 | | } |
| 302 | }; |
| 311 | 303 | |
| 312 | | pub fn fmt(op: Operand, enc_op: Encoding.Op) std.fmt.Formatter(fmtContext) { |
| 304 | pub fn fmt(op: Operand, enc_op: Encoding.Op) std.fmt.Formatter(Format, Format.default) { |
| 313 | 305 | return .{ .data = .{ .op = op, .enc_op = enc_op } }; |
| 314 | 306 | } |
| 315 | 307 | }; |
| ... | ... | @@ -361,23 +353,23 @@ pub const Instruction = struct { |
| 361 | 353 | return inst; |
| 362 | 354 | } |
| 363 | 355 | |
| 364 | | pub fn format(inst: Instruction, bw: *Writer, comptime unused_format_string: []const u8) Writer.Error!void { |
| 365 | | _ = unused_format_string; |
| 356 | pub fn format(inst: Instruction, w: *Writer, comptime unused_format_string: []const u8) Writer.Error!void { |
| 357 | comptime assert(unused_format_string.len == 0); |
| 366 | 358 | switch (inst.prefix) { |
| 367 | 359 | .none, .directive => {}, |
| 368 | | else => try bw.print("{s} ", .{@tagName(inst.prefix)}), |
| 360 | else => try w.print("{s} ", .{@tagName(inst.prefix)}), |
| 369 | 361 | } |
| 370 | | try bw.print("{s}", .{@tagName(inst.encoding.mnemonic)}); |
| 362 | try w.print("{s}", .{@tagName(inst.encoding.mnemonic)}); |
| 371 | 363 | for (inst.ops, inst.encoding.data.ops, 0..) |op, enc, i| { |
| 372 | 364 | if (op == .none) break; |
| 373 | | if (i > 0) try bw.writeByte(','); |
| 374 | | try bw.print(" {f}", .{op.fmt(enc)}); |
| 365 | if (i > 0) try w.writeByte(','); |
| 366 | try w.print(" {f}", .{op.fmt(enc)}); |
| 375 | 367 | } |
| 376 | 368 | } |
| 377 | 369 | |
| 378 | | pub fn encode(inst: Instruction, bw: *Writer, comptime opts: Options) !void { |
| 370 | pub fn encode(inst: Instruction, w: *Writer, comptime opts: Options) !void { |
| 379 | 371 | assert(inst.prefix != .directive); |
| 380 | | const encoder: Encoder(opts) = .{ .bw = bw }; |
| 372 | const encoder: Encoder(opts) = .{ .w = w }; |
| 381 | 373 | const enc = inst.encoding; |
| 382 | 374 | const data = enc.data; |
| 383 | 375 | |
| ... | ... | @@ -785,7 +777,7 @@ pub const Options = struct { allow_frame_locs: bool = false, allow_symbols: bool |
| 785 | 777 | |
| 786 | 778 | fn Encoder(comptime opts: Options) type { |
| 787 | 779 | return struct { |
| 788 | | bw: *Writer, |
| 780 | w: *Writer, |
| 789 | 781 | |
| 790 | 782 | const Self = @This(); |
| 791 | 783 | pub const options = opts; |
| ... | ... | @@ -800,31 +792,31 @@ fn Encoder(comptime opts: Options) type { |
| 800 | 792 | // Hopefully this path isn't taken very often, so we'll do it the slow way for now |
| 801 | 793 | |
| 802 | 794 | // LOCK |
| 803 | | if (prefixes.prefix_f0) try self.bw.writeByte(0xf0); |
| 795 | if (prefixes.prefix_f0) try self.w.writeByte(0xf0); |
| 804 | 796 | // REPNZ, REPNE, REP, Scalar Double-precision |
| 805 | | if (prefixes.prefix_f2) try self.bw.writeByte(0xf2); |
| 797 | if (prefixes.prefix_f2) try self.w.writeByte(0xf2); |
| 806 | 798 | // REPZ, REPE, REP, Scalar Single-precision |
| 807 | | if (prefixes.prefix_f3) try self.bw.writeByte(0xf3); |
| 799 | if (prefixes.prefix_f3) try self.w.writeByte(0xf3); |
| 808 | 800 | |
| 809 | 801 | // CS segment override or Branch not taken |
| 810 | | if (prefixes.prefix_2e) try self.bw.writeByte(0x2e); |
| 802 | if (prefixes.prefix_2e) try self.w.writeByte(0x2e); |
| 811 | 803 | // DS segment override |
| 812 | | if (prefixes.prefix_36) try self.bw.writeByte(0x36); |
| 804 | if (prefixes.prefix_36) try self.w.writeByte(0x36); |
| 813 | 805 | // ES segment override |
| 814 | | if (prefixes.prefix_26) try self.bw.writeByte(0x26); |
| 806 | if (prefixes.prefix_26) try self.w.writeByte(0x26); |
| 815 | 807 | // FS segment override |
| 816 | | if (prefixes.prefix_64) try self.bw.writeByte(0x64); |
| 808 | if (prefixes.prefix_64) try self.w.writeByte(0x64); |
| 817 | 809 | // GS segment override |
| 818 | | if (prefixes.prefix_65) try self.bw.writeByte(0x65); |
| 810 | if (prefixes.prefix_65) try self.w.writeByte(0x65); |
| 819 | 811 | |
| 820 | 812 | // Branch taken |
| 821 | | if (prefixes.prefix_3e) try self.bw.writeByte(0x3e); |
| 813 | if (prefixes.prefix_3e) try self.w.writeByte(0x3e); |
| 822 | 814 | |
| 823 | 815 | // Operand size override |
| 824 | | if (prefixes.prefix_66) try self.bw.writeByte(0x66); |
| 816 | if (prefixes.prefix_66) try self.w.writeByte(0x66); |
| 825 | 817 | |
| 826 | 818 | // Address size override |
| 827 | | if (prefixes.prefix_67) try self.bw.writeByte(0x67); |
| 819 | if (prefixes.prefix_67) try self.w.writeByte(0x67); |
| 828 | 820 | } |
| 829 | 821 | } |
| 830 | 822 | |
| ... | ... | @@ -832,7 +824,7 @@ fn Encoder(comptime opts: Options) type { |
| 832 | 824 | /// |
| 833 | 825 | /// Note that this flag is overridden by REX.W, if both are present. |
| 834 | 826 | pub fn prefix16BitMode(self: Self) !void { |
| 835 | | try self.bw.writeByte(0x66); |
| 827 | try self.w.writeByte(0x66); |
| 836 | 828 | } |
| 837 | 829 | |
| 838 | 830 | /// Encodes a REX prefix byte given all the fields |
| ... | ... | @@ -851,7 +843,7 @@ fn Encoder(comptime opts: Options) type { |
| 851 | 843 | if (fields.x) byte |= 0b0010; |
| 852 | 844 | if (fields.b) byte |= 0b0001; |
| 853 | 845 | |
| 854 | | try self.bw.writeByte(byte); |
| 846 | try self.w.writeByte(byte); |
| 855 | 847 | } |
| 856 | 848 | |
| 857 | 849 | /// Encodes a VEX prefix given all the fields |
| ... | ... | @@ -859,24 +851,24 @@ fn Encoder(comptime opts: Options) type { |
| 859 | 851 | /// See struct `Vex` for a description of each field. |
| 860 | 852 | pub fn vex(self: Self, fields: Vex) !void { |
| 861 | 853 | if (fields.is3Byte()) { |
| 862 | | try self.bw.writeByte(0b1100_0100); |
| 854 | try self.w.writeByte(0b1100_0100); |
| 863 | 855 | |
| 864 | | try self.bw.writeByte( |
| 856 | try self.w.writeByte( |
| 865 | 857 | @as(u8, ~@intFromBool(fields.r)) << 7 | |
| 866 | 858 | @as(u8, ~@intFromBool(fields.x)) << 6 | |
| 867 | 859 | @as(u8, ~@intFromBool(fields.b)) << 5 | |
| 868 | 860 | @as(u8, @intFromEnum(fields.m)) << 0, |
| 869 | 861 | ); |
| 870 | 862 | |
| 871 | | try self.bw.writeByte( |
| 863 | try self.w.writeByte( |
| 872 | 864 | @as(u8, @intFromBool(fields.w)) << 7 | |
| 873 | 865 | @as(u8, ~@as(u4, @intCast(fields.v.enc()))) << 3 | |
| 874 | 866 | @as(u8, @intFromBool(fields.l)) << 2 | |
| 875 | 867 | @as(u8, @intFromEnum(fields.p)) << 0, |
| 876 | 868 | ); |
| 877 | 869 | } else { |
| 878 | | try self.bw.writeByte(0b1100_0101); |
| 879 | | try self.bw.writeByte( |
| 870 | try self.w.writeByte(0b1100_0101); |
| 871 | try self.w.writeByte( |
| 880 | 872 | @as(u8, ~@intFromBool(fields.r)) << 7 | |
| 881 | 873 | @as(u8, ~@as(u4, @intCast(fields.v.enc()))) << 3 | |
| 882 | 874 | @as(u8, @intFromBool(fields.l)) << 2 | |
| ... | ... | @@ -891,7 +883,7 @@ fn Encoder(comptime opts: Options) type { |
| 891 | 883 | |
| 892 | 884 | /// Encodes a 1 byte opcode |
| 893 | 885 | pub fn opcode_1byte(self: Self, opcode: u8) !void { |
| 894 | | try self.bw.writeByte(opcode); |
| 886 | try self.w.writeByte(opcode); |
| 895 | 887 | } |
| 896 | 888 | |
| 897 | 889 | /// Encodes a 2 byte opcode |
| ... | ... | @@ -900,7 +892,7 @@ fn Encoder(comptime opts: Options) type { |
| 900 | 892 | /// |
| 901 | 893 | /// encoder.opcode_2byte(0x0f, 0xaf); |
| 902 | 894 | pub fn opcode_2byte(self: Self, prefix: u8, opcode: u8) !void { |
| 903 | | try self.bw.writeAll(&.{ prefix, opcode }); |
| 895 | try self.w.writeAll(&.{ prefix, opcode }); |
| 904 | 896 | } |
| 905 | 897 | |
| 906 | 898 | /// Encodes a 3 byte opcode |
| ... | ... | @@ -909,7 +901,7 @@ fn Encoder(comptime opts: Options) type { |
| 909 | 901 | /// |
| 910 | 902 | /// encoder.opcode_3byte(0xf2, 0x0f, 0x10); |
| 911 | 903 | pub fn opcode_3byte(self: Self, prefix_1: u8, prefix_2: u8, opcode: u8) !void { |
| 912 | | try self.bw.writeAll(&.{ prefix_1, prefix_2, opcode }); |
| 904 | try self.w.writeAll(&.{ prefix_1, prefix_2, opcode }); |
| 913 | 905 | } |
| 914 | 906 | |
| 915 | 907 | /// Encodes a 1 byte opcode with a reg field |
| ... | ... | @@ -917,7 +909,7 @@ fn Encoder(comptime opts: Options) type { |
| 917 | 909 | /// Remember to add a REX prefix byte if reg is extended! |
| 918 | 910 | pub fn opcode_withReg(self: Self, opcode: u8, reg: u3) !void { |
| 919 | 911 | assert(opcode & 0b111 == 0); |
| 920 | | try self.bw.writeByte(opcode | reg); |
| 912 | try self.w.writeByte(opcode | reg); |
| 921 | 913 | } |
| 922 | 914 | |
| 923 | 915 | // ------ |
| ... | ... | @@ -928,7 +920,7 @@ fn Encoder(comptime opts: Options) type { |
| 928 | 920 | /// |
| 929 | 921 | /// Remember to add a REX prefix byte if reg or rm are extended! |
| 930 | 922 | pub fn modRm(self: Self, mod: u2, reg_or_opx: u3, rm: u3) !void { |
| 931 | | try self.bw.writeByte(@as(u8, mod) << 6 | @as(u8, reg_or_opx) << 3 | rm); |
| 923 | try self.w.writeByte(@as(u8, mod) << 6 | @as(u8, reg_or_opx) << 3 | rm); |
| 932 | 924 | } |
| 933 | 925 | |
| 934 | 926 | /// Construct a ModR/M byte using direct r/m addressing |
| ... | ... | @@ -1014,7 +1006,7 @@ fn Encoder(comptime opts: Options) type { |
| 1014 | 1006 | /// |
| 1015 | 1007 | /// Remember to add a REX prefix byte if index or base are extended! |
| 1016 | 1008 | pub fn sib(self: Self, scale: u2, index: u3, base: u3) !void { |
| 1017 | | try self.bw.writeByte(@as(u8, scale) << 6 | @as(u8, index) << 3 | base); |
| 1009 | try self.w.writeByte(@as(u8, scale) << 6 | @as(u8, index) << 3 | base); |
| 1018 | 1010 | } |
| 1019 | 1011 | |
| 1020 | 1012 | /// Construct a SIB byte with scale * index + base, no frills. |
| ... | ... | @@ -1106,42 +1098,42 @@ fn Encoder(comptime opts: Options) type { |
| 1106 | 1098 | /// |
| 1107 | 1099 | /// It is sign-extended to 64 bits by the cpu. |
| 1108 | 1100 | pub fn disp8(self: Self, disp: i8) !void { |
| 1109 | | try self.bw.writeByte(@as(u8, @bitCast(disp))); |
| 1101 | try self.w.writeByte(@as(u8, @bitCast(disp))); |
| 1110 | 1102 | } |
| 1111 | 1103 | |
| 1112 | 1104 | /// Encode an 32 bit displacement |
| 1113 | 1105 | /// |
| 1114 | 1106 | /// It is sign-extended to 64 bits by the cpu. |
| 1115 | 1107 | pub fn disp32(self: Self, disp: i32) !void { |
| 1116 | | try self.bw.writeInt(i32, disp, .little); |
| 1108 | try self.w.writeInt(i32, disp, .little); |
| 1117 | 1109 | } |
| 1118 | 1110 | |
| 1119 | 1111 | /// Encode an 8 bit immediate |
| 1120 | 1112 | /// |
| 1121 | 1113 | /// It is sign-extended to 64 bits by the cpu. |
| 1122 | 1114 | pub fn imm8(self: Self, imm: u8) !void { |
| 1123 | | try self.bw.writeByte(imm); |
| 1115 | try self.w.writeByte(imm); |
| 1124 | 1116 | } |
| 1125 | 1117 | |
| 1126 | 1118 | /// Encode an 16 bit immediate |
| 1127 | 1119 | /// |
| 1128 | 1120 | /// It is sign-extended to 64 bits by the cpu. |
| 1129 | 1121 | pub fn imm16(self: Self, imm: u16) !void { |
| 1130 | | try self.bw.writeInt(u16, imm, .little); |
| 1122 | try self.w.writeInt(u16, imm, .little); |
| 1131 | 1123 | } |
| 1132 | 1124 | |
| 1133 | 1125 | /// Encode an 32 bit immediate |
| 1134 | 1126 | /// |
| 1135 | 1127 | /// It is sign-extended to 64 bits by the cpu. |
| 1136 | 1128 | pub fn imm32(self: Self, imm: u32) !void { |
| 1137 | | try self.bw.writeInt(u32, imm, .little); |
| 1129 | try self.w.writeInt(u32, imm, .little); |
| 1138 | 1130 | } |
| 1139 | 1131 | |
| 1140 | 1132 | /// Encode an 64 bit immediate |
| 1141 | 1133 | /// |
| 1142 | 1134 | /// It is sign-extended to 64 bits by the cpu. |
| 1143 | 1135 | pub fn imm64(self: Self, imm: u64) !void { |
| 1144 | | try self.bw.writeInt(u64, imm, .little); |
| 1136 | try self.w.writeInt(u64, imm, .little); |
| 1145 | 1137 | } |
| 1146 | 1138 | }; |
| 1147 | 1139 | } |
| ... | ... | @@ -2199,10 +2191,10 @@ const Assembler = struct { |
| 2199 | 2191 | }; |
| 2200 | 2192 | } |
| 2201 | 2193 | |
| 2202 | | pub fn assemble(as: *Assembler, bw: *Writer) !void { |
| 2194 | pub fn assemble(as: *Assembler, w: *Writer) !void { |
| 2203 | 2195 | while (try as.next()) |parsed_inst| { |
| 2204 | 2196 | const inst: Instruction = try .new(.none, parsed_inst.mnemonic, &parsed_inst.ops); |
| 2205 | | try inst.encode(bw, .{}); |
| 2197 | try inst.encode(w, .{}); |
| 2206 | 2198 | } |
| 2207 | 2199 | } |
| 2208 | 2200 | |