
no need to read this if you won't use dislib

        This file documents all the features in dis:proc/__dis:proc
        You can also read dislib.inc and __dislib.inc

#ifdef __cplusplus
        I've made it to work with Borland C++ (v4.00). All you
        have to do is to assemble it with "Clib" defined and
        define a memory model (/dmdl=XXXX):
                tasm /dmdl=small /dClib /mx dislib.asm
                tasm /dmdl=small /dClib /mx __dislib.asm
        and then link them with your program. See the .h files for
        more info and distest.cc for an example C++ program.
        /mx must also be on the command line! Add /zi if you
        want debugging info.
        You can also run "Clib.bat <MEMORY_MODEL>"

  #if (sizeof (int) == 4)
        The 32-bit code will destroy EAX,ECX,EDX.
        It will not destroy any other registers, not even the seg regs.
        if near data: assume es=ds=@data,ss:@stack
        else: assume ds=@data,ss:@stack
  #else //if sizeof (int) == 2
        The 16-bit code will destroy EAX,ECX,EDX,EBX
        If far data, it will also destroy ES,GS
  #endif
#endif //__cplusplus

;All of the procedures outside dis.asm assumes this:
if @datasize ;far data?
__dis_gs        equ     gs
_es             equ     es
        assume  es:nothing,ds:@data
else
__dis_gs        equ     ds
_es             equ     ds
        ;NOTE: es must also be equal to ds!!! gs can be anything!
        assume  es=ds:@data
endif

        dis:proc disassembles one instruction and prints it in a string
        input: __dis_gs:si dis_input_t struc
               _es:di   string to print the opcode and operands
        output: cf=1=__dis_gs:si.__dis_input.opcode.getbyte returned cf=1
                cf=0=_es:di is an asciiz string
        registers: none

        dis_printinstruction:proc is the same as dis:proc (and the same
        input too) but it doesn't call __dis:proc to decode the instruction.
        It assumes __dis:proc has already been called and
        __dis_gs:si.__dis_input.opcode is updated with info about the opcode.

        dis_changenumberbase:proc changes the number base we should print
        all of the numbers in. You must always call this procedure when you
        change the number base or the right # of digits will not be printed.
        input: __dis_gs:si dis_input_t struc
               bh       new number base
        output: bh is saved in __dis_gs:si.numberbase
        registers: none

        dis_input_t (struc) input to dis:proc
                .__dis_input    __dis_input_t struc
                .flags          see df_XXXX equates in dislib.inc
                .checkoperand   procedure to check the operand and possibly
                                put in a debugging name instead of just a
                                number. See dislib.inc for more details
                .octalbasechar  octal base # character. must be lowercase.
                                Usually o or q
                .tabsize        # of bytes between the first character in
                                the mnemonic to the first character in
                                the first operand
                .numberbase     # base. Must be changed by calling
                                dis_changenumberbase:proc
                .maxdigitsbyte/word/dword set by dis_changenumberbase:proc
                                to the max # of digits in a byte/word/dword
                                for this number base

        __dis:proc decodes one instruction and saves the result in a struc.
        opcode.flags, opcode.noperands and opcode.prefixes are set to 0000h
        at the start of the procedure and may be changed before we return.
        opsize and adrsize is initialized to the default codesize and may
        also be changed before we return to the caller
        NOTE: If opcode.noperands is 00h, ALL OTHER DATA IN opcode IS
        UNDEFINED!!!! You must always check if opcode.noperands is > 0
        before accessing the other data in opcode.op1/2/3
        input: __dis_gs:si __dis_input_t struc
        output: cf=1=__dis_gs:si.opcode.getbyte returned cf=1
                cf=0=ok
        registers: none

        dis_immoperand_t (struc) is for immediate operands
                .immediate      has the immediate byte/word/dword
                                It is zero-extended to a dword if
                                it's not already a dword, that is
                .__flags        di_signextended is set if the immediate
                                is signextended from byte to default
                                size (word/dword). If it's sign-extended
                                to a word, the msw is zero.
                dis_operand_t.size is the immediate's size (byte/word/dword)
                                If it's sign-extended, the size is word or
                                dword, depending on the default size.

        dis_regoperand_t (struc) is for all register operands
                .register       has the register equate (dr_ax,dr_ecx,dr_etc)
                dis_operand_t.size is the register's size
                                (byte/word/dword/tbyte)

        dis_memoperand_t (struc) is for all memory operands
                .displ          has the displacement (if any)
                .baseindex      has the base AND index register.
                                The index register is .baseindex[0:3]
                                and the base register is .baseindex[7:4].
                                (if we have a base and/or index)
                .scale          index scale (0,1,2 or 3)
                .__flags        info about the memory operand:
                        dm_displbyte/word/dword if the displacement is a
                                byte/word/dword
                        dm_displsignextended if the displacement is
                                sign-extended to default size (word/dword)
                                If it's sign-extended to a word,
                                .displ[31:16] is 0000h
                        dm_segoverride set if we have a segment override
                        dm_hasdispl set if we have a displacement
                        dm_hasbase set if we have a base register
                        dm_hasindex set if we have an index register
                        dm_hasscale set if we have a scale
                .segoverride    segoverride[3:0] has the current segment
                                override (if dm_segoverride is set in __flags)
                                and segoverride[7:4] has the default segment
                                override for the memory operand
                                The segment override equates is
                                dm_seges/dm_segcs/dm_segetc
                dis_operand_t.size is the memory's size (byte/word/dword)

        dis_nearoperand_t (struc) has the offset of a call/jmp near/short
                .ofs            the offset. If opcode.opsize=10h,
                                ofs=0000XXXXh, else ofs is 32-bit
                .__flags        dn_short set if it's a short jmp/jcc

        dis_faroperand_t (struc) has the seg:ofs of a call/jmp far
                .ofs            the offset (the same as dis_nearoperand_t.ofs)
                .seg            the segment

        dis_operands_t (union) has all operand strucs

        dis_operand_t (struc) has info about one operand
                .ops            dis_operands_t union
                .flags  dop_mem memory operand (.ops.mem)
                        dop_imm immediate operand (.ops.imm)
                        dop_reg register operand (.ops.reg)
                        dop_nearofs near/short offset (.ops.nearptr)
                        dop_farofs far seg:ofs (.ops.farptr)
                        dop_small print "small" before the operand
                        dop_large print "large" before the operand
                .size   dop_sizebyte    byte operand
                        dop_sizeword    word operand
                        dop_sizedword   dword operand
                        dop_sizepword   pword operand (sgdt [0])
                        dop_sizeqword   qword operand
                        dop_sizetbyte   tbyte operand
                        dop_sizewordofs word offset (ofs=16-bit)
                        dop_sizedwordsegofs dword seg:ofs (ofs=16-bit)
                        dop_sizedwordofs dword offset (ofs=32-bit)
                        dop_sizefwordsegofs fword seg:ofs (ofs=32-bit)
                        dop_sizetwowords two words in memory (bound)
                        dop_sizetwodwords two dwords in memory (bound)

        dis_opcode_t (struc) holds info about the opcode and its operands
                .op1            the first operand (if any)
                .op2            the second operand (if any)
                .op3            the third operand (if any)
                .flags  do_hasmodrm     if the opcode has a modR/M byte
                        do_hassib       if the opcode has a sib byte
                        do_showmemsize  if we should print the memory's size
                        do_dontshowmemsize if we shouldn't
                        do_dontprintops don't print any of the opcode's
                                        operands. This one's usually set if
                                        it's a string instruction/xlat/aam/aad
                        do_hasreg       if one of the operands is a register
                        do_hassegreg    if one of the operands is a seg reg
                .opcodeword     the opcode 00XXh for normal opcodes
                                0FXXh for operands with 0Fh escape
                .opcodeid       the opcode id. See opid_XXX equates
                                in __dislib.inc for details
                .opsize         the opcode's operand size (16/32-bit)
                .adrsize        the opcode's address size (16/32-bit)
                .rm             rm field in modR/M (if modR/M)
                .modrm          modR/M (if do_hasmodrm is set in flags)
                .reg            reg field in modR/M (if modR/M)
                .mod            mod field in modR/M (if modR/M)
                .sib            sib byte (if do_hassib is set in flags)
                .noperands      # of operands. NOTE!!! You should ALWAYS
                                CHECK THIS FIRST BEFORE CHECKING ANY OTHER
                                DATA IN THIS STRUC, since all other data
                                is undefined if there's no operands for
                                this opcode.
                .prefixes       see __dis_XXprefix equates in __dislib.inc

        __dis_input_t (struc) input to __dis:proc
                .opcode         dis_opcode_t struc (will be changed)
                                All other data in this struc will not
                                be changed by __dis:proc
                .eip            the current eip
                .flags          see __df_XXXX equates in __dislib.inc
                .getbyte        get-the-next-byte procedure (where .eip is)
                                See __dislib.inc for input/output/register
                .codesize       default codesize (16 or 32)
