diff options
Diffstat (limited to 'src/ortho/mcode/disa_x86.adb')
-rw-r--r-- | src/ortho/mcode/disa_x86.adb | 997 |
1 files changed, 997 insertions, 0 deletions
diff --git a/src/ortho/mcode/disa_x86.adb b/src/ortho/mcode/disa_x86.adb new file mode 100644 index 0000000..1d2d485 --- /dev/null +++ b/src/ortho/mcode/disa_x86.adb @@ -0,0 +1,997 @@ +-- X86 disassembler. +-- Copyright (C) 2006 Tristan Gingold +-- +-- GHDL is free software; you can redistribute it and/or modify it under +-- the terms of the GNU General Public License as published by the Free +-- Software Foundation; either version 2, or (at your option) any later +-- version. +-- +-- GHDL is distributed in the hope that it will be useful, but WITHOUT ANY +-- WARRANTY; without even the implied warranty of MERCHANTABILITY or +-- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +-- for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with GCC; see the file COPYING. If not, write to the Free +-- Software Foundation, 59 Temple Place - Suite 330, Boston, MA +-- 02111-1307, USA. +with System.Address_To_Access_Conversions; + +package body Disa_X86 is + type Byte is new Interfaces.Unsigned_8; + type Bf_2 is mod 2 ** 2; + type Bf_3 is mod 2 ** 3; + type Byte_Vector is array (Natural) of Byte; + package Bv_Addr2acc is new System.Address_To_Access_Conversions + (Object => Byte_Vector); + use Bv_Addr2acc; + + type Cstring_Acc is access constant String; + type Index_Type is + ( + N_None, + N_Push, + N_Pop, + N_Ret, + N_Mov, + N_Add, + N_Or, + N_Adc, + N_Sbb, + N_And, + N_Sub, + N_Xor, + N_Cmp, + N_Into, + N_Jmp, + N_Jcc, + N_Setcc, + N_Call, + N_Int, + N_Cdq, + N_Imul, + N_Mul, + N_Leave, + N_Test, + N_Lea, + N_O, + N_No, + N_B, + N_AE, + N_E, + N_Ne, + N_Be, + N_A, + N_S, + N_Ns, + N_P, + N_Np, + N_L, + N_Ge, + N_Le, + N_G, + N_Not, + N_Neg, + N_Cbw, + N_Div, + N_Idiv, + N_Movsx, + N_Movzx, + N_Nop, + N_Hlt, + N_Inc, + N_Dec, + N_Rol, + N_Ror, + N_Rcl, + N_Rcr, + N_Shl, + N_Shr, + N_Sar, + N_Fadd, + N_Fmul, + N_Fcom, + N_Fcomp, + N_Fsub, + N_Fsubr, + N_Fdiv, + N_Fdivr, + + G_1, + G_2, + G_3, + G_5 + ); + + type Names_Type is array (Index_Type range <>) of Cstring_Acc; + subtype S is String; + Names : constant Names_Type := + (N_None => new S'("none"), + N_Push => new S'("push"), + N_Pop => new S'("pop"), + N_Ret => new S'("ret"), + N_Mov => new S'("mov"), + N_Add => new S'("add"), + N_Or => new S'("or"), + N_Adc => new S'("adc"), + N_Sbb => new S'("sbb"), + N_And => new S'("and"), + N_Sub => new S'("sub"), + N_Xor => new S'("xor"), + N_Cmp => new S'("cmp"), + N_Into => new S'("into"), + N_Jmp => new S'("jmp"), + N_Jcc => new S'("j"), + N_Int => new S'("int"), + N_Cdq => new S'("cdq"), + N_Call => new S'("call"), + N_Imul => new S'("imul"), + N_Mul => new S'("mul"), + N_Leave => new S'("leave"), + N_Test => new S'("test"), + N_Setcc => new S'("set"), + N_Lea => new S'("lea"), + N_O => new S'("o"), + N_No => new S'("no"), + N_B => new S'("b"), + N_AE => new S'("ae"), + N_E => new S'("e"), + N_Ne => new S'("ne"), + N_Be => new S'("be"), + N_A => new S'("a"), + N_S => new S'("s"), + N_Ns => new S'("ns"), + N_P => new S'("p"), + N_Np => new S'("np"), + N_L => new S'("l"), + N_Ge => new S'("ge"), + N_Le => new S'("le"), + N_G => new S'("g"), + N_Not => new S'("not"), + N_Neg => new S'("neg"), + N_Cbw => new S'("cbw"), + N_Div => new S'("div"), + N_Idiv => new S'("idiv"), + N_Movsx => new S'("movsx"), + N_Movzx => new S'("movzx"), + N_Nop => new S'("nop"), + N_Hlt => new S'("hlt"), + N_Inc => new S'("inc"), + N_Dec => new S'("dec"), + N_Rol => new S'("rol"), + N_Ror => new S'("ror"), + N_Rcl => new S'("rcl"), + N_Rcr => new S'("rcr"), + N_Shl => new S'("shl"), + N_Shr => new S'("shr"), + N_Sar => new S'("sar"), + N_Fadd => new S'("fadd"), + N_Fmul => new S'("fmul"), + N_Fcom => new S'("fcom"), + N_Fcomp => new S'("fcomp"), + N_Fsub => new S'("fsub"), + N_Fsubr => new S'("fsubr"), + N_Fdiv => new S'("fdiv"), + N_Fdivr => new S'("fdivr") + ); + + + + -- Format of an instruction. + -- MODRM_SRC_8 : modrm byte follow, and modrm is source, witdh = 8bits + -- MODRM_DST_8 : modrm byte follow, and modrm is dest, width = 8 bits. + -- MODRM_SRC_W : modrm byte follow, and modrm is source, width = 16/32 bits + -- MODRM_DST_W : modrm byte follow, and modrm is dest, width =16/32 bits. + -- MODRM_IMM_W : modrm byte follow, with an opcode in the reg field, + -- followed by an immediat, width = 16/32 bits. + -- MODRM_IMM_8 : modrm byte follow, with an opcode in the reg field, + -- followed by an immediat, width = 8 bits. + -- IMM : the opcode is followed by an immediate value. + -- PREFIX : the opcode is a prefix (1 byte). + -- OPCODE : inherent addressing. + -- OPCODE2 : a second byte specify the instruction. + -- REG_IMP : register is in the 3 LSB of the opcode. + -- REG_IMM_W : register is in the 3 LSB of the opcode, followed by an + -- immediat, width = 16/32 bits. + -- DISP_W : a wide displacement (16/32 bits). + -- DISP_8 : short displacement (8 bits). + -- INVALID : bad opcode. + type Format_Type is (Modrm_Src, Modrm_Dst, + Modrm_Imm, Modrm_Imm_S, + Modrm, + Modrm_Ax, + Modrm_Imm8, + Imm, Imm_S, Imm_8, + Eax_Imm, + Prefix, Opcode, Opcode2, Reg_Imp, + Reg_Imm, + Imp, + Disp_W, Disp_8, + Cond_Disp_W, Cond_Disp_8, + Cond_Modrm, + Ax_Off_Src, Ax_Off_Dst, + Invalid); + + type Width_Type is (W_None, W_8, W_16, W_32, W_Data); + + -- Description for one instruction. + type Insn_Desc_Type is record + -- Name of the operation. + Name : Index_Type; + + -- Width of the instruction. + -- This is used to add a suffix (b,w,l) to the instruction. + -- This may also be the size of a data. + Width : Width_Type; + + -- Format of the instruction. + Format : Format_Type; + end record; + + Desc_Invalid : constant Insn_Desc_Type := (N_None, W_None, Invalid); + + type Insn_Desc_Array_Type is array (Byte) of Insn_Desc_Type; + type Group_Desc_Array_Type is array (Bf_3) of Insn_Desc_Type; + Insn_Desc : constant Insn_Desc_Array_Type := + ( + 2#00_000_000# => (N_Add, W_8, Modrm_Dst), + 2#00_000_001# => (N_Add, W_Data, Modrm_Dst), + 2#00_000_010# => (N_Add, W_8, Modrm_Src), + 2#00_000_011# => (N_Add, W_Data, Modrm_Src), + + 2#00_001_000# => (N_Or, W_8, Modrm_Dst), + 2#00_001_001# => (N_Or, W_Data, Modrm_Dst), + 2#00_001_010# => (N_Or, W_8, Modrm_Src), + 2#00_001_011# => (N_Or, W_Data, Modrm_Src), + + 2#00_011_000# => (N_Sbb, W_8, Modrm_Dst), + 2#00_011_001# => (N_Sbb, W_Data, Modrm_Dst), + 2#00_011_010# => (N_Sbb, W_8, Modrm_Src), + 2#00_011_011# => (N_Sbb, W_Data, Modrm_Src), + + 2#00_100_000# => (N_And, W_8, Modrm_Dst), + 2#00_100_001# => (N_And, W_Data, Modrm_Dst), + 2#00_100_010# => (N_And, W_8, Modrm_Src), + 2#00_100_011# => (N_And, W_Data, Modrm_Src), + + 2#00_101_000# => (N_Sub, W_8, Modrm_Dst), + 2#00_101_001# => (N_Sub, W_Data, Modrm_Dst), + 2#00_101_010# => (N_Sub, W_8, Modrm_Src), + 2#00_101_011# => (N_Sub, W_Data, Modrm_Src), + + 2#00_110_000# => (N_Xor, W_8, Modrm_Dst), + 2#00_110_001# => (N_Xor, W_Data, Modrm_Dst), + 2#00_110_010# => (N_Xor, W_8, Modrm_Src), + 2#00_110_011# => (N_Xor, W_Data, Modrm_Src), + + 2#00_111_000# => (N_Cmp, W_8, Modrm_Dst), + 2#00_111_001# => (N_Cmp, W_Data, Modrm_Dst), + 2#00_111_010# => (N_Cmp, W_8, Modrm_Src), + 2#00_111_011# => (N_Cmp, W_Data, Modrm_Src), + + 2#00_111_100# => (N_Cmp, W_8, Eax_Imm), + 2#00_111_101# => (N_Cmp, W_Data, Eax_Imm), + + 2#0101_0_000# => (N_Push, W_Data, Reg_Imp), + 2#0101_0_001# => (N_Push, W_Data, Reg_Imp), + 2#0101_0_010# => (N_Push, W_Data, Reg_Imp), + 2#0101_0_011# => (N_Push, W_Data, Reg_Imp), + 2#0101_0_100# => (N_Push, W_Data, Reg_Imp), + 2#0101_0_101# => (N_Push, W_Data, Reg_Imp), + 2#0101_0_110# => (N_Push, W_Data, Reg_Imp), + 2#0101_0_111# => (N_Push, W_Data, Reg_Imp), + + 2#0101_1_000# => (N_Pop, W_Data, Reg_Imp), + 2#0101_1_001# => (N_Pop, W_Data, Reg_Imp), + 2#0101_1_010# => (N_Pop, W_Data, Reg_Imp), + 2#0101_1_011# => (N_Pop, W_Data, Reg_Imp), + 2#0101_1_100# => (N_Pop, W_Data, Reg_Imp), + 2#0101_1_101# => (N_Pop, W_Data, Reg_Imp), + 2#0101_1_110# => (N_Pop, W_Data, Reg_Imp), + 2#0101_1_111# => (N_Pop, W_Data, Reg_Imp), + + 2#0110_1000# => (N_Push, W_Data, Imm), + 2#0110_1010# => (N_Push, W_Data, Imm_S), + + 2#0111_0000# => (N_Jcc, W_None, Cond_Disp_8), + 2#0111_0001# => (N_Jcc, W_None, Cond_Disp_8), + 2#0111_0010# => (N_Jcc, W_None, Cond_Disp_8), + 2#0111_0011# => (N_Jcc, W_None, Cond_Disp_8), + 2#0111_0100# => (N_Jcc, W_None, Cond_Disp_8), + 2#0111_0101# => (N_Jcc, W_None, Cond_Disp_8), + 2#0111_0110# => (N_Jcc, W_None, Cond_Disp_8), + 2#0111_0111# => (N_Jcc, W_None, Cond_Disp_8), + 2#0111_1000# => (N_Jcc, W_None, Cond_Disp_8), + 2#0111_1001# => (N_Jcc, W_None, Cond_Disp_8), + 2#0111_1010# => (N_Jcc, W_None, Cond_Disp_8), + 2#0111_1011# => (N_Jcc, W_None, Cond_Disp_8), + 2#0111_1100# => (N_Jcc, W_None, Cond_Disp_8), + 2#0111_1101# => (N_Jcc, W_None, Cond_Disp_8), + 2#0111_1110# => (N_Jcc, W_None, Cond_Disp_8), + 2#0111_1111# => (N_Jcc, W_None, Cond_Disp_8), + + 2#1000_0000# => (G_1, W_8, Modrm_Imm), + 2#1000_0001# => (G_1, W_Data, Modrm_Imm), + 2#1000_0011# => (G_1, W_Data, Modrm_Imm_S), + + 2#1000_0101# => (N_Test, W_Data, Modrm_Src), + 2#1000_1101# => (N_Lea, W_Data, Modrm_Src), + + 2#1000_1010# => (N_Mov, W_8, Modrm_Src), + 2#1000_1011# => (N_Mov, W_Data, Modrm_Src), + 2#1000_1000# => (N_Mov, W_8, Modrm_Dst), + 2#1000_1001# => (N_Mov, W_Data, Modrm_Dst), + + 2#1001_0000# => (N_Nop, W_None, Opcode), + 2#1001_1001# => (N_Cdq, W_Data, Imp), + + 2#1010_0000# => (N_Mov, W_8, Ax_Off_Src), + 2#1010_0001# => (N_Mov, W_Data, Ax_Off_Src), + 2#1010_0010# => (N_Mov, W_8, Ax_Off_Dst), + 2#1010_0011# => (N_Mov, W_Data, Ax_Off_Dst), + + 2#1011_0000# => (N_Mov, W_8, Reg_Imm), + + 2#1011_1000# => (N_Mov, W_Data, Reg_Imm), + 2#1011_1001# => (N_Mov, W_Data, Reg_Imm), + 2#1011_1010# => (N_Mov, W_Data, Reg_Imm), + 2#1011_1011# => (N_Mov, W_Data, Reg_Imm), + 2#1011_1100# => (N_Mov, W_Data, Reg_Imm), + 2#1011_1101# => (N_Mov, W_Data, Reg_Imm), + 2#1011_1110# => (N_Mov, W_Data, Reg_Imm), + 2#1011_1111# => (N_Mov, W_Data, Reg_Imm), + + 2#1100_0000# => (G_2, W_8, Modrm_Imm8), + 2#1100_0001# => (G_2, W_Data, Modrm_Imm8), + + 2#1100_0011# => (N_Ret, W_None, Opcode), + 2#1100_0110# => (N_Mov, W_8, Modrm_Imm), + 2#1100_0111# => (N_Mov, W_Data, Modrm_Imm), + 2#1100_1001# => (N_Leave, W_None, Opcode), + 2#1100_1101# => (N_Int, W_None, Imm_8), + 2#1100_1110# => (N_Into, W_None, Opcode), + + 2#1110_1000# => (N_Call, W_None, Disp_W), + 2#1110_1001# => (N_Jmp, W_None, Disp_W), + 2#1110_1011# => (N_Jmp, W_None, Disp_8), + + 2#1111_0100# => (N_Hlt, W_None, Opcode), + + 2#1111_0110# => (G_3, W_None, Invalid), + 2#1111_0111# => (G_3, W_None, Invalid), + + 2#1111_1111# => (G_5, W_None, Invalid), + --2#1111_1111# => (N_Push, W_Data, Modrm), + others => (N_None, W_None, Invalid)); + + Insn_Desc_0F : constant Insn_Desc_Array_Type := + (2#1000_0000# => (N_Jcc, W_None, Cond_Disp_W), + 2#1000_0001# => (N_Jcc, W_None, Cond_Disp_W), + 2#1000_0010# => (N_Jcc, W_None, Cond_Disp_W), + 2#1000_0011# => (N_Jcc, W_None, Cond_Disp_W), + 2#1000_0100# => (N_Jcc, W_None, Cond_Disp_W), + 2#1000_0101# => (N_Jcc, W_None, Cond_Disp_W), + 2#1000_0110# => (N_Jcc, W_None, Cond_Disp_W), + 2#1000_0111# => (N_Jcc, W_None, Cond_Disp_W), + 2#1000_1000# => (N_Jcc, W_None, Cond_Disp_W), + 2#1000_1001# => (N_Jcc, W_None, Cond_Disp_W), + 2#1000_1010# => (N_Jcc, W_None, Cond_Disp_W), + 2#1000_1011# => (N_Jcc, W_None, Cond_Disp_W), + 2#1000_1100# => (N_Jcc, W_None, Cond_Disp_W), + 2#1000_1101# => (N_Jcc, W_None, Cond_Disp_W), + 2#1000_1110# => (N_Jcc, W_None, Cond_Disp_W), + 2#1000_1111# => (N_Jcc, W_None, Cond_Disp_W), + + 2#1001_0000# => (N_Setcc, W_8, Cond_Modrm), + 2#1001_0001# => (N_Setcc, W_8, Cond_Modrm), + 2#1001_0010# => (N_Setcc, W_8, Cond_Modrm), + 2#1001_0011# => (N_Setcc, W_8, Cond_Modrm), + 2#1001_0100# => (N_Setcc, W_8, Cond_Modrm), + 2#1001_0101# => (N_Setcc, W_8, Cond_Modrm), + 2#1001_0110# => (N_Setcc, W_8, Cond_Modrm), + 2#1001_0111# => (N_Setcc, W_8, Cond_Modrm), + 2#1001_1000# => (N_Setcc, W_8, Cond_Modrm), + 2#1001_1001# => (N_Setcc, W_8, Cond_Modrm), + 2#1001_1010# => (N_Setcc, W_8, Cond_Modrm), + 2#1001_1011# => (N_Setcc, W_8, Cond_Modrm), + 2#1001_1100# => (N_Setcc, W_8, Cond_Modrm), + 2#1001_1101# => (N_Setcc, W_8, Cond_Modrm), + 2#1001_1110# => (N_Setcc, W_8, Cond_Modrm), + 2#1001_1111# => (N_Setcc, W_8, Cond_Modrm), + + 2#1011_0110# => (N_Movzx, W_Data, Modrm_Dst), + 2#1011_1110# => (N_Movsx, W_Data, Modrm_Dst), + others => (N_None, W_None, Invalid)); + + -- 16#F7# + Insn_Desc_G3 : constant Group_Desc_Array_Type := + (2#000# => (N_Test, W_Data, Reg_Imm), + 2#010# => (N_Not, W_Data, Modrm_Dst), + 2#011# => (N_Neg, W_Data, Modrm_Dst), + 2#100# => (N_Mul, W_Data, Modrm_Ax), + 2#101# => (N_Imul, W_Data, Modrm_Ax), + 2#110# => (N_Div, W_Data, Modrm_Ax), + 2#111# => (N_Idiv, W_Data, Modrm_Ax), + others => (N_None, W_None, Invalid)); + + Insn_Desc_G5 : constant Group_Desc_Array_Type := + (2#000# => (N_Inc, W_Data, Modrm), + 2#001# => (N_Dec, W_Data, Modrm), + 2#010# => (N_Call, W_Data, Modrm), + --2#011# => (N_Call, W_Data, Modrm_Ax), + 2#100# => (N_Jmp, W_Data, Modrm), + --2#101# => (N_Jmp, W_Data, Modrm_Ax), + 2#110# => (N_Push, W_Data, Modrm_Ax), + others => (N_None, W_None, Invalid)); + + type Group_Name_Array_Type is array (Index_Type range G_1 .. G_2, Bf_3) + of Index_Type; + Group_Name : constant Group_Name_Array_Type := + ( + G_1 => (N_Add, N_Or, N_Adc, N_Sbb, N_And, N_Sub, N_Xor, N_Cmp), + G_2 => (N_Rol, N_Ror, N_Rcl, N_Rcr, N_Shl, N_Shr, N_None, N_Sar) + ); + + -- Standard widths of operations. + type Width_Array_Type is array (Width_Type) of Character; + Width_Char : constant Width_Array_Type := + (W_None => '-', W_8 => 'b', W_16 => 'w', W_32 => 'l', W_Data => '?'); + type Width_Len_Type is array (Width_Type) of Natural; + Width_Len : constant Width_Len_Type := + (W_None => 0, W_8 => 1, W_16 => 2, W_32 => 4, W_Data => 0); + + -- Registers. +-- type Reg_Type is (Reg_Ax, Reg_Bx, Reg_Cx, Reg_Dx, +-- Reg_Bp, Reg_Sp, Reg_Si, Reg_Di, +-- Reg_Al, Reg_Ah, Reg_Bl, Reg_Bh, +-- Reg_Cl, Reg_Ch, Reg_Dl, Reg_Dh); + + -- Bits extraction from byte functions. + -- For a byte, MSB (most significant bit) is bit 7 while + -- LSB (least significant bit) is bit 0. + + -- Extract bits 2, 1 and 0. + function Ext_210 (B : Byte) return Bf_3; + pragma Inline (Ext_210); + + -- Extract bits 5-3 of byte B. + function Ext_543 (B : Byte) return Bf_3; + pragma Inline (Ext_543); + + -- Extract bits 7-6 of byte B. + function Ext_76 (B : Byte) return Bf_2; + pragma Inline (Ext_76); + + function Ext_210 (B : Byte) return Bf_3 is + begin + return Bf_3 (B and 2#111#); + end Ext_210; + + function Ext_543 (B : Byte) return Bf_3 is + begin + return Bf_3 (Shift_Right (B, 3) and 2#111#); + end Ext_543; + + function Ext_76 (B : Byte) return Bf_2 is + begin + return Bf_2 (Shift_Right (B, 6) and 2#11#); + end Ext_76; + + function Ext_Modrm_Mod (B : Byte) return Bf_2 renames Ext_76; + function Ext_Modrm_Rm (B : Byte) return Bf_3 renames Ext_210; + function Ext_Modrm_Reg (B : Byte) return Bf_3 renames Ext_543; + function Ext_Sib_Base (B : Byte) return Bf_3 renames Ext_210; + function Ext_Sib_Index (B : Byte) return Bf_3 renames Ext_543; + function Ext_Sib_Scale (B : Byte) return Bf_2 renames Ext_76; + + procedure Disassemble_Insn (Addr : System.Address; + Pc : Unsigned_32; + Line : in out String; + Line_Len : out Natural; + Insn_Len : out Natural; + Proc_Cb : Symbol_Proc_Type) + is + -- Index in LINE of the next character to be written. + Lo : Natural; + + -- Default width. + W_Default : constant Width_Type := W_32; + + -- The instruction memory, 0 based. + Mem : Bv_Addr2acc.Object_Pointer; + + -- Add NAME to the line. + procedure Add_Name (Name : Index_Type); + pragma Inline (Add_Name); + + -- Add CHAR to the line. + procedure Add_Char (C : Character); + pragma Inline (Add_Char); + + -- Add STR to the line. + procedure Add_String (Str : String) is + begin + Line (Lo .. Lo + Str'Length - 1) := Str; + Lo := Lo + Str'Length; + end Add_String; + + -- Add BYTE to the line. + procedure Add_Byte (V : Byte) is + type My_Str is array (Natural range 0 .. 15) of Character; + Hex_Digit : constant My_Str := "0123456789abcdef"; + begin + Add_Char (Hex_Digit (Natural (Shift_Right (V, 4) and 16#0f#))); + Add_Char (Hex_Digit (Natural (Shift_Right (V, 0) and 16#0f#))); + end Add_Byte; + + procedure Add_Name (Name : Index_Type) is + begin + Add_String (Names (Name).all); + end Add_Name; + + procedure Add_Char (C : Character) is + begin + Line (Lo) := C; + Lo := Lo + 1; + end Add_Char; + + procedure Add_Comma is + begin + Add_String (", "); + end Add_Comma; + + procedure Name_Align (Orig : Natural) is + begin + Add_Char (' '); + while Lo - Orig < 8 loop + Add_Char (' '); + end loop; + end Name_Align; + + procedure Add_Opcode (Name : Index_Type; Width : Width_Type) + is + L : constant Natural := Lo; + begin + Add_Name (Name); + if False and Width /= W_None then + Add_Char (Width_Char (Width)); + end if; + Name_Align (L); + end Add_Opcode; + + procedure Add_Cond_Opcode (Name : Index_Type; B : Byte) + is + L : constant Natural := Lo; + begin + Add_Name (Name); + Add_Name (Index_Type'Val (Index_Type'Pos (N_O) + + Byte'Pos (B and 16#0f#))); + Name_Align (L); + end Add_Cond_Opcode; + + procedure Decode_Reg_Field (F : Bf_3; W : Width_Type) is + type Reg_Name2_Array is array (Bf_3) of String (1 .. 2); + type Reg_Name3_Array is array (Bf_3) of String (1 .. 3); + Regs_8 : constant Reg_Name2_Array := + ("al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"); + Regs_16 : constant Reg_Name2_Array := + ("ax", "cx", "dx", "bx", "sp", "bp", "si", "di"); + Regs_32 : constant Reg_Name3_Array := + ("eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"); + begin + Add_Char ('%'); + case W is + when W_8 => + Add_String (Regs_8 (F)); + when W_16 => + Add_String (Regs_16 (F)); + when W_32 => + Add_String (Regs_32 (F)); + when W_None + | W_Data => + raise Program_Error; + end case; + end Decode_Reg_Field; + + procedure Decode_Val (Off : Natural; Width : Width_Type) + is + begin + case Width is + when W_8 => + Add_Byte (Mem (Off)); + when W_16 => + Add_Byte (Mem (Off + 1)); + Add_Byte (Mem (Off)); + when W_32 => + Add_Byte (Mem (Off + 3)); + Add_Byte (Mem (Off + 2)); + Add_Byte (Mem (Off + 1)); + Add_Byte (Mem (Off + 0)); + when W_None + | W_Data => + raise Program_Error; + end case; + end Decode_Val; + + function Decode_Val (Off : Natural; Width : Width_Type) + return Unsigned_32 + is + V : Unsigned_32; + begin + case Width is + when W_8 => + V := Unsigned_32 (Mem (Off)); + -- Sign extension. + if V >= 16#80# then + V := 16#Ffff_Ff00# or V; + end if; + return V; + when W_16 => + return Shift_Left (Unsigned_32 (Mem (Off + 1)), 8) + or Unsigned_32 (Mem (Off)); + when W_32 => + return Shift_Left (Unsigned_32 (Mem (Off + 3)), 24) + or Shift_Left (Unsigned_32 (Mem (Off + 2)), 16) + or Shift_Left (Unsigned_32 (Mem (Off + 1)), 8) + or Shift_Left (Unsigned_32 (Mem (Off + 0)), 0); + when W_None + | W_Data => + raise Program_Error; + end case; + end Decode_Val; + + procedure Decode_Imm (Off : in out Natural; Width : Width_Type) + is + begin + Add_String ("$0x"); + Decode_Val (Off, Width); + Off := Off + Width_Len (Width); + end Decode_Imm; + + procedure Decode_Disp (Off : in out Natural; + Width : Width_Type; + Offset : Unsigned_32 := 0) + is + L : Natural; + V : Unsigned_32; + Off_Orig : constant Natural := Off; + begin + L := Lo; + V := Decode_Val (Off, Width) + Offset; + Off := Off + Width_Len (Width); + if Proc_Cb /= null then + Proc_Cb.all (Mem (Off)'Address, + Line (Lo .. Line'Last), Lo); + end if; + if L /= Lo then + if V = 0 then + return; + end if; + Add_String (" + "); + end if; + Add_String ("0x"); + if Offset = 0 then + Decode_Val (Off_Orig, Width); + else + Add_Byte (Byte (Shift_Right (V, 24) and 16#Ff#)); + Add_Byte (Byte (Shift_Right (V, 16) and 16#Ff#)); + Add_Byte (Byte (Shift_Right (V, 8) and 16#Ff#)); + Add_Byte (Byte (Shift_Right (V, 0) and 16#Ff#)); + end if; + end Decode_Disp; + + procedure Decode_Modrm_Reg (B : Byte; Width : Width_Type) is + begin + Decode_Reg_Field (Ext_Modrm_Reg (B), Width); + end Decode_Modrm_Reg; + + procedure Decode_Sib (Sib : Byte; B_Mod : Bf_2) + is + S : Bf_2; + I : Bf_3; + B : Bf_3; + begin + S := Ext_Sib_Scale (Sib); + B := Ext_Sib_Base (Sib); + I := Ext_Sib_Index (Sib); + Add_Char ('('); + if B = 2#101# and then B_Mod /= 0 then + Decode_Reg_Field (B, W_32); + Add_Char (','); + end if; + if I /= 2#100# then + Decode_Reg_Field (I, W_32); + case S is + when 2#00# => + null; + when 2#01# => + Add_String (",2"); + when 2#10# => + Add_String (",4"); + when 2#11# => + Add_String (",8"); + end case; + end if; + Add_Char (')'); + end Decode_Sib; + + procedure Decode_Modrm_Mem (Off : in out Natural; Width : Width_Type) + is + B : Byte; + B_Mod : Bf_2; + B_Rm : Bf_3; + Off_Orig : Natural; + begin + B := Mem (Off); + B_Mod := Ext_Modrm_Mod (B); + B_Rm := Ext_Modrm_Rm (B); + Off_Orig := Off; + case B_Mod is + when 2#11# => + Decode_Reg_Field (B_Rm, Width); + Off := Off + 1; + when 2#10# => + if B_Rm = 2#100# then + Off := Off + 2; + Decode_Disp (Off, W_32); + Decode_Sib (Mem (Off_Orig + 1), B_Mod); + else + Off := Off + 1; + Decode_Disp (Off, W_32); + Add_Char ('('); + Decode_Reg_Field (B_Rm, W_32); + Add_Char (')'); + end if; + when 2#01# => + if B_Rm = 2#100# then + Off := Off + 2; + Decode_Disp (Off, W_8); + Decode_Sib (Mem (Off_Orig + 1), B_Mod); + else + Off := Off + 1; + Decode_Disp (Off, W_8); + Add_Char ('('); + Decode_Reg_Field (B_Rm, W_32); + Add_Char (')'); + end if; + when 2#00# => + if B_Rm = 2#100# then + Off := Off + 2; + Decode_Sib (Mem (Off_Orig + 1), B_Mod); + elsif B_Rm = 2#101# then + Off := Off + 1; + Decode_Disp (Off, W_32); + else + Add_Char ('('); + Decode_Reg_Field (B_Rm, W_32); + Add_Char (')'); + Off := Off + 1; + end if; + end case; + end Decode_Modrm_Mem; + + -- Return the length of the modrm bytes. + -- At least 1 (mod/rm), at most 6 (mod/rm + SUB + disp32). + function Decode_Modrm_Len (Off : Natural) return Natural + is + B : Byte; + M_Mod : Bf_2; + M_Rm : Bf_3; + begin + B := Mem (Off); + M_Mod := Ext_Modrm_Mod (B); + M_Rm := Ext_Modrm_Rm (B); + case M_Mod is + when 2#11# => + return 1; + when 2#10# => + if M_Rm = 2#100# then + return 1 + 1 + 4; + else + return 1 + 4; + end if; + when 2#01# => + if M_Rm = 2#100# then + return 1 + 1 + 1; + else + return 1 + 1; + end if; + when 2#00# => + if M_Rm = 2#101# then + -- disp32. + return 1 + 4; + elsif M_Rm = 2#100# then + -- SIB + return 1 + 1; + else + return 1; + end if; + end case; + end Decode_Modrm_Len; + + + Off : Natural; + B : Byte; + B1 : Byte; + Desc : Insn_Desc_Type; + Name : Index_Type; + W : Width_Type; + begin + Mem := To_Pointer (Addr); + Off := 0; + Lo := Line'First; + + B := Mem (0); + if B = 2#0000_1111# then + B := Mem (1); + Off := 2; + Insn_Len := 2; + Desc := Insn_Desc_0F (B); + else + Off := 1; + Insn_Len := 1; + Desc := Insn_Desc (B); + end if; + + if Desc.Name >= G_1 then + B1 := Mem (Off); + case Desc.Name is + when G_1 + | G_2 => + Name := Group_Name (Desc.Name, Ext_543 (B1)); + when G_3 => + Desc := Insn_Desc_G3 (Ext_543 (B1)); + Name := Desc.Name; + when G_5 => + Desc := Insn_Desc_G5 (Ext_543 (B1)); + Name := Desc.Name; + when others => + Desc := Desc_Invalid; + end case; + else + Name := Desc.Name; + end if; + + case Desc.Width is + when W_Data => + W := W_Default; + when W_8 + | W_16 + | W_32 => + W := Desc.Width; + when W_None => + case Desc.Format is + when Disp_8 + | Cond_Disp_8 + | Imm_8 => + W := W_8; + when Disp_W + | Cond_Disp_W => + W := W_Default; + when Invalid + | Opcode => + W := W_None; + when others => + raise Program_Error; + end case; + end case; + + case Desc.Format is + when Reg_Imp => + Add_Opcode (Desc.Name, W_Default); + Decode_Reg_Field (Ext_210 (B), W_Default); + when Opcode => + Add_Opcode (Desc.Name, W_None); + when Modrm => + Add_Opcode (Desc.Name, W); + Decode_Modrm_Mem (Insn_Len, W); + when Modrm_Src => + Add_Opcode (Desc.Name, W); + -- Disp source first. + Decode_Modrm_Mem (Insn_Len, W); + Add_Comma; + B := Mem (Off); + Decode_Modrm_Reg (Mem (Off), W); + when Modrm_Dst => + Add_Opcode (Desc.Name, W); + -- Disp source first. + B := Mem (Off); + Decode_Modrm_Reg (B, W); + Add_Comma; + Decode_Modrm_Mem (Insn_Len, W); + when Modrm_Imm => + Add_Opcode (Name, W); + Insn_Len := Off + Decode_Modrm_Len (Off); + Decode_Imm (Insn_Len, W); + Add_Comma; + Decode_Modrm_Mem (Off, W); + when Modrm_Imm_S => + Add_Opcode (Name, W); + Insn_Len := Off + Decode_Modrm_Len (Off); + Decode_Imm (Insn_Len, W_8); + Add_Comma; + Decode_Modrm_Mem (Off, W); + when Modrm_Imm8 => + Add_Opcode (Name, W); + Decode_Modrm_Mem (Off, W); + Add_Comma; + Decode_Imm (Off, W_8); + + when Reg_Imm => + Add_Opcode (Desc.Name, W); + Decode_Imm (Insn_Len, W); + Add_Comma; + Decode_Reg_Field (Ext_210 (B), W); + when Eax_Imm => + Add_Opcode (Desc.Name, W); + Decode_Imm (Insn_Len, W); + Add_Comma; + Decode_Reg_Field (2#000#, W); + + when Disp_W + | Disp_8 => + Add_Opcode (Desc.Name, W_None); + Decode_Disp (Insn_Len, W, + Pc + Unsigned_32 (Insn_Len + Width_Len (W))); + + when Cond_Disp_8 + | Cond_Disp_W => + Add_Cond_Opcode (Desc.Name, B); + Decode_Disp (Insn_Len, W, + Pc + Unsigned_32 (Insn_Len + Width_Len (W))); + + when Cond_Modrm => + Add_Cond_Opcode (Desc.Name, B); + Decode_Modrm_Mem (Insn_Len, W); + + when Imm => + Add_Opcode (Desc.Name, W); + Decode_Imm (Insn_Len, W); + + when Imm_S + | Imm_8 => + Add_Opcode (Desc.Name, W); + Decode_Imm (Insn_Len, W_8); + + when Modrm_Ax => + if (B and 2#1#) = 2#0# then + W := W_8; + else + W := W_Default; + end if; + Add_Opcode (Desc.Name, W); + Decode_Reg_Field (0, W); + Add_Comma; + Decode_Modrm_Mem (Off, W); + + when Ax_Off_Src => + Add_Opcode (Desc.Name, W); + Decode_Disp (Insn_Len, W); + Add_Comma; + Decode_Reg_Field (0, W); + + when Ax_Off_Dst => + Add_Opcode (Desc.Name, W); + Decode_Reg_Field (0, W); + Add_Comma; + Decode_Disp (Insn_Len, W); + + when Imp => + Add_Opcode (Desc.Name, W_Default); + + when Invalid + | Prefix + | Opcode2 => + Add_String ("invalid "); + if Insn_Len = 2 then + Add_Byte (Mem (0)); + end if; + Add_Byte (B); + Insn_Len := 1; + end case; + + Line_Len := Lo - Line'First; + end Disassemble_Insn; +end Disa_X86; + + |