tiny.isa.x86
Defined in tiny.isa.
API (52)
Actions
Public operations.
Diagnostic.captureFormDiagnostic.capturePrefixDiagnostic.normalizedFormDiagnostic.prefixBytesExtension.fromRawForm.encodedKeyForm.keyImmediate.signedInstruction.implicitRegistersOperation.familyPrefix.bytesPrefix.fromBytesPrefix.hasOperand16Prefix.lockedPrefix.repeatedPrefix.repeatedOperand16Prefix.rexBytePrefix.wideRegister.roleRegisterLane.bytesScale.factorSegment.prefixByteWidth.bytesdecodedecodeWithDiagnosticformModeled
Types and contracts
Public types and contracts.
AccessAddressKindDecodeErrorDiagnosticExtensionFamilyFormFormKeyImmediateImmediateExtensionInstructionMapMemoryModeOperandOperationPrefixRegisterRegisterAccessRegisterBankRegisterLaneRoleScaleSegmentWidth
Values and defaults
Public values and defaults.
Source
Source: lib/isa/src/x86/decode.zig:4
pub const Error = error{ AmbiguousPrefix, InstructionTooLong, InvalidEncoding, TruncatedInstruction, UnsupportedAddressSize, UnsupportedOpcode, UnsupportedPrefix,};Source: lib/isa/src/x86/form.zig:214
pub const Access = enum(u2) { none = 0, read = 1, write = 2, read_write = 3,};Source: lib/isa/src/x86/form.zig:205
pub const AddressKind = enum(u3) { none = 0, base = 1, base_indexed = 2, rip_relative = 3, absolute = 4, absolute_indexed = 5,};Source: lib/isa/src/x86/form.zig:251
pub const Diagnostic = struct { candidate: Form = .{}, prefix: [15]u8 = @splat(0), prefix_count: u4 = 0, active: bool = false, normalized: bool = false, pub fn captureForm(self: *Diagnostic, value: Form) void { self.* = .{ .candidate = value, .active = true, .normalized = true, }; } pub fn capturePrefix(self: *Diagnostic, value: []const u8) void { std.debug.assert(value.len <= self.prefix.len); self.* = .{ .prefix_count = @intCast(value.len), .active = true, }; @memcpy(self.prefix[0..value.len], value); } pub fn normalizedForm(self: Diagnostic) ?Form { if (!self.active or !self.normalized) return null; return self.candidate; } pub fn prefixBytes(self: *const Diagnostic) []const u8 { return self.prefix[0..self.prefix_count]; }};Source: lib/isa/src/x86/form.zig:174
pub const Extension = enum(u4) { zero = 0, one = 1, two = 2, three = 3, four = 4, five = 5, six = 6, seven = 7, none = 8, pub fn fromRaw(value: u3) Extension { return @fromBackingInt(@intCast(value)); }};Source: lib/isa/src/x86/form.zig:221
pub const Form = packed struct(u64) { prefix: Prefix = .none, map: Map = .one, opcode: u8 = 0, width: Width = .none, extension: Extension = .none, mode: Mode = .none, register_role: Role = .none, register_access: Access = .none, operand_role: Role = .none, operand_access: Access = .none, address: AddressKind = .none, base_role: Role = .none, index_role: Role = .none, embedded_role: Role = .none, embedded_access: Access = .none, immediate: u8 = 0, reserved: u13 = 0, pub fn key(self: Form) FormKey { return @bitCast(self); } pub fn encodedKey(self: Form) [8]u8 { var result: [8]u8 = undefined; std.mem.writeInt(u64, &result, self.key(), .little); return result; }};Source: lib/isa/src/x86/form.zig:149
pub const Map = enum(u1) { one = 0, two = 1,};Source: lib/isa/src/x86/form.zig:190
pub const Mode = enum(u3) { none = 0, memory = 1, displacement8 = 2, displacement32 = 3, register = 4,};Source: lib/isa/src/x86/form.zig:5
pub const Prefix = enum(u5) { none = 0, rex = 1, rex_b = 2, rex_r = 3, rex_rb = 4, rex_rxb = 5, rex_w = 6, rex_wb = 7, rex_wr = 8, rex_wrb = 9, operand16 = 10, operand16_cs = 11, operand16_rex_b = 12, operand16_rex_r = 13, operand16_rex_rb = 14, lock_rex = 15, lock_rex_b = 16, lock_rex_w = 17, repeat = 18, repeat_rex_b = 19, rex_x = 20, rex_xb = 21, rex_rx = 22, rex_wx = 23, rex_wxb = 24, rex_wrx = 25, rex_wrxb = 26, repeat_rex_w = 27, operand16_2_cs = 28, operand16_4_cs = 29, operand16_5_cs = 30, operand16_3_cs = 31, pub fn bytes(self: Prefix) []const u8 { return switch (self) { .none => &.{}, .rex => &.{0x40}, .rex_b => &.{0x41}, .rex_r => &.{0x44}, .rex_rb => &.{0x45}, .rex_rxb => &.{0x47}, .rex_w => &.{0x48}, .rex_wb => &.{0x49}, .rex_wr => &.{0x4c}, .rex_wrb => &.{0x4d}, .operand16 => &.{0x66}, .operand16_cs => &.{ 0x66, 0x2e }, .operand16_rex_b => &.{ 0x66, 0x41 }, .operand16_rex_r => &.{ 0x66, 0x44 }, .operand16_rex_rb => &.{ 0x66, 0x45 }, .lock_rex => &.{ 0xf0, 0x40 }, .lock_rex_b => &.{ 0xf0, 0x41 }, .lock_rex_w => &.{ 0xf0, 0x48 }, .repeat => &.{0xf3}, .repeat_rex_b => &.{ 0xf3, 0x41 }, .rex_x => &.{0x42}, .rex_xb => &.{0x43}, .rex_rx => &.{0x46}, .rex_wx => &.{0x4a}, .rex_wxb => &.{0x4b}, .rex_wrx => &.{0x4e}, .rex_wrxb => &.{0x4f}, .repeat_rex_w => &.{ 0xf3, 0x48 }, .operand16_2_cs => &.{ 0x66, 0x66, 0x2e }, .operand16_4_cs => &.{ 0x66, 0x66, 0x66, 0x66, 0x2e }, .operand16_5_cs => &.{ 0x66, 0x66, 0x66, 0x66, 0x66, 0x2e }, .operand16_3_cs => &.{ 0x66, 0x66, 0x66, 0x2e }, }; } pub fn fromBytes(value: []const u8) ?Prefix { inline for (@typeInfo(Prefix).@"enum".field_names) |name| { const candidate: Prefix = @fromBackingInt(@intCast(@backingInt(@field(Prefix, name)))); if (std.mem.eql(u8, value, candidate.bytes())) return candidate; } return null; } pub fn rexByte(self: Prefix) u8 { return switch (self) { .rex, .lock_rex => 0x40, .rex_b, .operand16_rex_b, .lock_rex_b, .repeat_rex_b => 0x41, .rex_x => 0x42, .rex_xb => 0x43, .rex_r, .operand16_rex_r => 0x44, .rex_rb, .operand16_rex_rb => 0x45, .rex_rx => 0x46, .rex_rxb => 0x47, .rex_w, .lock_rex_w => 0x48, .rex_wb => 0x49, .rex_wx => 0x4a, .rex_wxb => 0x4b, .rex_wr => 0x4c, .rex_wrb => 0x4d, .rex_wrx => 0x4e, .rex_wrxb => 0x4f, .repeat_rex_w => 0x48, else => 0, }; } pub fn wide(self: Prefix) bool { return self.rexByte() & 0x08 != 0; } pub fn hasOperand16(self: Prefix) bool { return switch (self) { .operand16, .operand16_cs, .operand16_rex_b, .operand16_rex_r, .operand16_rex_rb, .operand16_2_cs, .operand16_4_cs, .operand16_5_cs, .operand16_3_cs, => true, else => false, }; } pub fn repeatedOperand16(self: Prefix) bool { return self == .operand16_2_cs or self == .operand16_4_cs or self == .operand16_5_cs or self == .operand16_3_cs; } pub fn locked(self: Prefix) bool { return switch (self) { .lock_rex, .lock_rex_b, .lock_rex_w => true, else => false, }; } pub fn repeated(self: Prefix) bool { return switch (self) { .repeat, .repeat_rex_b, .repeat_rex_w => true, else => false, }; }};Source: lib/isa/src/x86/form.zig:198
pub const Role = enum(u2) { none = 0, ordinary = 1, rsp = 2, rbp = 3,};Source: lib/isa/src/x86/form.zig:154
pub const Width = enum(u3) { none = 0, byte = 1, word = 2, dword = 3, qword = 4, vector128 = 5, pub fn bytes(self: Width) u8 { return switch (self) { .none => 0, .byte => 1, .word => 2, .dword => 4, .qword => 8, .vector128 => 16, }; }};Source: lib/isa/src/x86/instruction.zig:4
pub const Family = enum(u5) { move = 0, extend = 1, address = 2, string = 3, arithmetic = 4, logic = 5, unary = 6, shift = 7, multiply = 8, divide = 9, condition = 10, control = 11, stack = 12, swap = 13, carry = 14, nop = 15, boundary = 16, system = 17, vector = 18, exchange = 19, interrupt = 20,};Source: lib/isa/src/x86/instruction.zig:162
pub const Instruction = struct { form: x86.Form, operation: Operation, family: Family, bytes: u4, register: ?x86.Register = null, register_access: x86.Access = .none, operand: x86.Operand = .none, operand_access: x86.Access = .none, embedded: ?x86.Register = null, embedded_access: x86.Access = .none, immediate: ?x86.Immediate = null, relative: ?i32 = null, modrm_mode: ?u2 = null, modrm_operand: ?u4 = null, implicit: [implicit_registers_max]x86.RegisterAccess = @splat(.{}), implicit_count: u3 = 0, pub fn implicitRegisters(self: *const Instruction) []const x86.RegisterAccess { std.debug.assert(self.implicit_count <= self.implicit.len); return self.implicit[0..self.implicit_count]; }};Source: lib/isa/src/x86/instruction.zig:28
pub const Operation = enum(u8) { add = 0, and_ = 1, bswap = 2, call = 3, cmc = 4, cmovae = 5, cmove = 6, cmovne = 7, cmp = 8, dec = 9, div = 10, hlt = 11, imul = 12, inc = 13, ja = 14, jae = 15, jb = 16, jbe = 17, je = 18, jmp = 19, jne = 20, lea = 21, mov = 22, movs = 23, movsx = 24, movzx = 25, mul = 26, nop = 27, not_ = 28, or_ = 29, out = 30, pop = 31, push = 32, ret = 33, rol = 34, sbb = 35, seta = 36, setae = 37, setb = 38, setbe = 39, sete = 40, setne = 41, shl = 42, shr = 43, stos = 44, sub = 45, test_ = 46, ud2 = 47, xor_ = 48, adc = 49, cli = 50, cmova = 51, cmovb = 52, cmpxchg = 53, cpuid = 54, idiv = 55, int_ = 56, movdqu = 57, movups = 58, neg = 59, pshufd = 60, pushf = 61, rdmsr = 62, ror = 63, sar = 64, sti = 65, wrmsr = 66, xchg = 67, seto = 68, jl = 69, jge = 70, jle = 71, jg = 72, setl = 73, setge = 74, setle = 75, setg = 76, pub fn family(self: Operation) Family { return switch (self) { .mov => .move, .movsx, .movzx => .extend, .lea => .address, .movs, .stos => .string, .add, .adc, .cmp, .sbb, .sub => .arithmetic, .and_, .or_, .test_, .xor_ => .logic, .dec, .inc, .neg, .not_ => .unary, .rol, .ror, .sar, .shl, .shr => .shift, .imul, .mul => .multiply, .div, .idiv => .divide, .cmova, .cmovae, .cmovb, .cmove, .cmovne, .ja, .jae, .jb, .jbe, .je, .jne, .seta, .setae, .setb, .setbe, .sete, .setne, .seto, .jl, .jge, .jle, .jg, .setl, .setge, .setle, .setg, => .condition, .call, .jmp, .ret => .control, .pop, .push, .pushf => .stack, .bswap => .swap, .cmc => .carry, .nop => .nop, .hlt, .out, .ud2 => .boundary, .cli, .cpuid, .rdmsr, .sti, .wrmsr => .system, .movdqu, .movups, .pshufd => .vector, .cmpxchg, .xchg => .exchange, .int_ => .interrupt, }; }};Source: lib/isa/src/x86/operand.zig:102
pub const Immediate = struct { value: u64, encoded_bytes: u4, extension: ImmediateExtension, pub fn signed(self: Immediate) i64 { std.debug.assert(std.math.isPowerOfTwo(self.encoded_bytes)); std.debug.assert(self.encoded_bytes <= 8); return switch (self.encoded_bytes) { 1 => @as(i8, @bitCast(@as(u8, @truncate(self.value)))), 2 => @as(i16, @bitCast(@as(u16, @truncate(self.value)))), 4 => @as(i32, @bitCast(@as(u32, @truncate(self.value)))), 8 => @bitCast(self.value), else => unreachable, }; }};Source: lib/isa/src/x86/operand.zig:97
pub const ImmediateExtension = enum(u1) { none = 0, sign = 1,};Source: lib/isa/src/x86/operand.zig:81
pub const Memory = struct { kind: x86.AddressKind, width: x86.Width = .none, base: ?Register = null, index: ?Register = null, scale: Scale = .one, displacement: i32 = 0, segment: Segment = .none,};Source: lib/isa/src/x86/operand.zig:91
Source: lib/isa/src/x86/operand.zig:28
pub const Register = struct { bank: RegisterBank = .gpr, number: u4 = 0, lane: RegisterLane = .qword, pub fn role(self: Register) x86.Role { if (self.bank == .vector or self.lane == .high8) return .ordinary; return switch (self.number) { 4 => .rsp, 5 => .rbp, else => .ordinary, }; }};Source: lib/isa/src/x86/operand.zig:43
Source: lib/isa/src/x86/operand.zig:4
pub const RegisterBank = enum(u1) { gpr = 0, vector = 1,};Source: lib/isa/src/x86/operand.zig:9
pub const RegisterLane = enum(u3) { low8 = 0, high8 = 1, word = 2, dword = 3, qword = 4, vector128 = 5, pub fn bytes(self: RegisterLane) u8 { return switch (self) { .low8, .high8 => 1, .word => 2, .dword => 4, .qword => 8, .vector128 => 16, }; }};Source: lib/isa/src/x86/operand.zig:70
pub const Scale = enum(u2) { one = 0, two = 1, four = 2, eight = 3, pub fn factor(self: Scale) u4 { return @as(u4, 1) << @backingInt(self); }};Source: lib/isa/src/x86/operand.zig:48
pub const Segment = enum(u3) { none = 0, es = 1, cs = 2, ss = 3, ds = 4, fs = 5, gs = 6, pub fn prefixByte(self: Segment) u8 { return switch (self) { .none => 0, .es => 0x26, .cs => 0x2e, .ss => 0x36, .ds => 0x3e, .fs => 0x64, .gs => 0x65, }; }};Source: lib/isa/src/x86/decode.zig:91
pub fn decode(code: []const u8) Error!x86.Instruction { var diagnostic: x86.Diagnostic = .{}; return decodeWithDiagnostic(code, &diagnostic);}Source: lib/isa/src/x86/decode.zig:96
pub fn decodeWithDiagnostic( code: []const u8, diagnostic: *x86.Diagnostic,) Error!x86.Instruction { diagnostic.* = .{}; var cursor: usize = 0; const prefix = try parsePrefix(code, &cursor, diagnostic); const first = try takeByte(code, &cursor); const map: x86.Map = if (first == 0x0f) .two else .one; const opcode = if (map == .two) try takeByte(code, &cursor) else first; const instruction_encoding = encoding(map, opcode) orelse { const candidate = x86.Form{ .prefix = prefix.form, .map = map, .opcode = opcode }; diagnostic.captureForm(candidate); return error.UnsupportedOpcode; }; var modrm = if (instruction_encoding.modrm) try parseModRm(code, &cursor, prefix) else null; var form = createForm(prefix, map, opcode, instruction_encoding, modrm); const operation = operationFor(prefix, map, opcode, modrm) orelse { diagnostic.captureForm(form); return error.UnsupportedOpcode; }; if (modrm) |*value| { parseDisplacement(code, &cursor, value) catch |failure| { diagnostic.captureForm(form); return failure; }; } const payload = parsePayload(code, &cursor, prefix, map, opcode, modrm) catch |failure| { if (!(map == .one and opcode == 0xcd)) diagnostic.captureForm(form); return failure; }; if (map == .one and opcode == 0xcd) { form.immediate = @truncate(payload.immediate.?.value); } if (cursor > 15) return error.InstructionTooLong; var result = createInstruction(form, operation, cursor, prefix, modrm, payload); addImplicitOperands(&result, prefix); return result;}Source: lib/isa/src/x86/form.zig:3
pub const FormKey = u64;Source: lib/isa/src/x86/form.zig:285
pub fn modeled(value: Form) bool { if (value.reserved != 0) return false; return switch (value.map) { .one => modeledOne(value.opcode), .two => modeledTwo(value.opcode), };}Source: lib/isa/src/x86/instruction.zig:160
pub const implicit_registers_max: usize = 4;Source: lib/isa/src/root.zig:43
pub const x86 = @import("x86/root.zig");Source: lib/isa/src/x86/root.zig
const decode_owner = @import("decode.zig");const form = @import("form.zig");const instruction = @import("instruction.zig");const operand = @import("operand.zig");pub const Access = form.Access;pub const AddressKind = form.AddressKind;pub const Diagnostic = form.Diagnostic;pub const Extension = form.Extension;pub const Form = form.Form;pub const FormKey = form.FormKey;pub const Map = form.Map;pub const Mode = form.Mode;pub const Prefix = form.Prefix;pub const Role = form.Role;pub const Width = form.Width;pub const formModeled = form.modeled;pub const Family = instruction.Family;pub const Instruction = instruction.Instruction;pub const Operation = instruction.Operation;pub const implicit_registers_max = instruction.implicit_registers_max;pub const Immediate = operand.Immediate;pub const ImmediateExtension = operand.ImmediateExtension;pub const Memory = operand.Memory;pub const Operand = operand.Operand;pub const Register = operand.Register;pub const RegisterAccess = operand.RegisterAccess;pub const RegisterBank = operand.RegisterBank;pub const RegisterLane = operand.RegisterLane;pub const Scale = operand.Scale;pub const Segment = operand.Segment;pub const DecodeError = decode_owner.Error;pub const decode = decode_owner.decode;pub const decodeWithDiagnostic = decode_owner.decodeWithDiagnostic;Complete call list for x86.decodeWithDiagnostic
10 direct calls.
lib.isa.src.x86.decode.addImplicitOperands[function] — private source atlib/isa/src/x86/decode.zig:1225in nearest public ownerlib.isa.src.x86.decodelib.isa.src.x86.decode.createForm[function] — private source atlib/isa/src/x86/decode.zig:413in nearest public ownerlib.isa.src.x86.decodelib.isa.src.x86.decode.createInstruction[function] — private source atlib/isa/src/x86/decode.zig:1065in nearest public ownerlib.isa.src.x86.decodelib.isa.src.x86.decode.encoding[function] — private source atlib/isa/src/x86/decode.zig:244in nearest public ownerlib.isa.src.x86.decodelib.isa.src.x86.decode.operationFor[function] — private source atlib/isa/src/x86/decode.zig:748in nearest public ownerlib.isa.src.x86.decodelib.isa.src.x86.decode.parseDisplacement[function] — private source atlib/isa/src/x86/decode.zig:400in nearest public ownerlib.isa.src.x86.decodelib.isa.src.x86.decode.parseModRm[function] — private source atlib/isa/src/x86/decode.zig:336in nearest public ownerlib.isa.src.x86.decodelib.isa.src.x86.decode.parsePayload[function] — private source atlib/isa/src/x86/decode.zig:965in nearest public ownerlib.isa.src.x86.decodelib.isa.src.x86.decode.parsePrefix[function] — private source atlib/isa/src/x86/decode.zig:139in nearest public ownerlib.isa.src.x86.decodelib.isa.src.x86.decode.takeByte[function] — private source atlib/isa/src/x86/decode.zig:1331in nearest public ownerlib.isa.src.x86.decode
Audit
| Definitions | 53 |
|---|---|
| Public names | 53 |
| Members | 250 |
| Version | 26.7.0 |
| Revision | daab053ee433 |