Skip to documentation
SLOP

tiny.isa.x86

Reference tiny.isa x86

Defined in tiny.isa.

API (52)

Actions

Public operations.

Types and contracts

Public types and contracts.

Values and defaults

Public values and defaults.

No direct callersNo direct callstiny.isax86
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Source: lib/isa/src/x86/decode.zig:4

zig
pub const Error = error{    AmbiguousPrefix,    InstructionTooLong,    InvalidEncoding,    TruncatedInstruction,    UnsupportedAddressSize,    UnsupportedOpcode,    UnsupportedPrefix,};

Source: lib/isa/src/x86/form.zig:214

zig
pub const Access = enum(u2) {    none = 0,    read = 1,    write = 2,    read_write = 3,};

Source: lib/isa/src/x86/form.zig:205

zig
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

zig
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

zig
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

zig
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

zig
pub const Map = enum(u1) {    one = 0,    two = 1,};

Source: lib/isa/src/x86/form.zig:190

zig
pub const Mode = enum(u3) {    none = 0,    memory = 1,    displacement8 = 2,    displacement32 = 3,    register = 4,};

Source: lib/isa/src/x86/form.zig:5

zig
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

zig
pub const Role = enum(u2) {    none = 0,    ordinary = 1,    rsp = 2,    rbp = 3,};

Source: lib/isa/src/x86/form.zig:154

zig
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

zig
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

zig
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

zig
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

zig
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

zig
pub const ImmediateExtension = enum(u1) {    none = 0,    sign = 1,};

Source: lib/isa/src/x86/operand.zig:81

zig
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

zig
pub const Operand = union(enum) {    none,    register: Register,    memory: Memory,};

Source: lib/isa/src/x86/operand.zig:28

zig
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

zig
pub const RegisterAccess = struct {    register: Register = .{},    access: x86.Access = .none,};

Source: lib/isa/src/x86/operand.zig:4

zig
pub const RegisterBank = enum(u1) {    gpr = 0,    vector = 1,};

Source: lib/isa/src/x86/operand.zig:9

zig
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

zig
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

zig
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

zig
pub fn decode(code: []const u8) Error!x86.Instruction {    var diagnostic: x86.Diagnostic = .{};    return decodeWithDiagnostic(code, &diagnostic);}
Called byCallsNo direct callersx86decodeWithDiagnosticx86decode
Static calls · unresolved targets: 0 · external targets: 0.

Source: lib/isa/src/x86/decode.zig:96

zig
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;}
Called byCallsx86decodeprivate sourcelib.isa.src.x86.decodeaddImplicitOperandsprivate sourcelib.isa.src.x86.decodecreateFormprivate sourcelib.isa.src.x86.decodecreateInstructionprivate sourcelib.isa.src.x86.decodeencodingprivate sourcelib.isa.src.x86.decodeoperationFor+5 morex86decodeWithDiagnostic
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callersx86.Formkeyx86.FormencodedKey
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsx86.FormencodedKeyx86.Formkey
Static calls · unresolved targets: 0 · external targets: 0.

Source: lib/isa/src/x86/form.zig:3

zig
pub const FormKey = u64;
Called byCallsNo direct callsx86.PrefixfromBytesx86.Prefixbytes
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersx86.Prefixbytesx86.PrefixfromBytes
Static calls · unresolved targets: 0 · external targets: 0.

Source: lib/isa/src/x86/form.zig:285

zig
pub fn modeled(value: Form) bool {    if (value.reserved != 0) return false;    return switch (value.map) {        .one => modeledOne(value.opcode),        .two => modeledTwo(value.opcode),    };}
Called byCallsNo direct callersprivate sourcelib.isa.src.x86.formmodeledOneprivate sourcelib.isa.src.x86.formmodeledTwox86formModeled
Static calls · unresolved targets: 0 · external targets: 0.

Source: lib/isa/src/x86/instruction.zig:160

zig
pub const implicit_registers_max: usize = 4;

Source: lib/isa/src/root.zig:43

zig
pub const x86 = @import("x86/root.zig");

Source: lib/isa/src/x86/root.zig

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.

Audit

Definitions53
Public names53
Members250
Version26.7.0
Revisiondaab053ee433