1 /* disasm.c where all the _work_ gets done in the Netwide Disassembler
3 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
4 * Julian Hall. All rights reserved. The software is
5 * redistributable under the licence given in the file "Licence"
6 * distributed in the NASM archive.
8 * initial version 27/iii/95 by Simon Tatham
17 /* names.c included source file defining instruction and register
18 * names for the Netwide [Dis]Assembler
20 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
21 * Julian Hall. All rights reserved. The software is
22 * redistributable under the licence given in the file "Licence"
23 * distributed in the NASM archive.
26 static const char *conditions
[] = { /* condition code names */
27 "a", "ae", "b", "be", "c", "e", "g", "ge", "l", "le", "na", "nae",
28 "nb", "nbe", "nc", "ne", "ng", "nge", "nl", "nle", "no", "np",
29 "ns", "nz", "o", "p", "pe", "po", "s", "z"
32 /* Register names automatically generated from regs.dat */
33 /* automatically generated from ./regs.dat - do not edit */
34 static const char *reg_names
[] = {
117 /* Instruction names automatically generated from insns.dat */
118 /* This file is auto-generated from insns.dat by insns.pl - don't edit it */
119 /* This file in included by names.c */
120 static const char *insn_names
[] = {
683 /* Conditional instructions */
684 static const char *icn
[] = {
690 /* and the corresponding opcodes */
697 #define INSN_MAX 32 /* one instruction can't be longer than this */
698 long disasm (unsigned char *data
, char *output
, int segsize
, long offset
);
699 extern struct itemplate
**itable
[];
702 * Flags that go into the `segment' field of `insn' structures
703 * during disassembly.
705 #define SEG_RELATIVE 1
709 #define SEG_DISP16 16
710 #define SEG_DISP32 32
711 #define SEG_NODISP 64
712 #define SEG_SIGNED 128
714 static int whichreg(long regflags
, int regval
)
716 /* automatically generated from ./regs.dat - do not edit */
717 static const int creg
[] = {R_CR0
,R_CR1
,R_CR2
,R_CR3
,R_CR4
,R_CR5
,R_CR6
,R_CR7
};
718 static const int dreg
[] = {R_DR0
,R_DR1
,R_DR2
,R_DR3
,R_DR4
,R_DR5
,R_DR6
,R_DR7
};
719 static const int fpureg
[] = {R_ST0
,R_ST1
,R_ST2
,R_ST3
,R_ST4
,R_ST5
,R_ST6
,R_ST7
};
720 static const int mmxreg
[] = {R_MM0
,R_MM1
,R_MM2
,R_MM3
,R_MM4
,R_MM5
,R_MM6
,R_MM7
};
721 static const int reg16
[] = {R_AX
,R_CX
,R_DX
,R_BX
,R_SP
,R_BP
,R_SI
,R_DI
};
722 static const int reg32
[] = {R_EAX
,R_ECX
,R_EDX
,R_EBX
,R_ESP
,R_EBP
,R_ESI
,R_EDI
};
723 static const int reg8
[] = {R_AL
,R_CL
,R_DL
,R_BL
,R_AH
,R_CH
,R_DH
,R_BH
};
724 static const int sreg
[] = {R_ES
,R_CS
,R_SS
,R_DS
,R_FS
,R_GS
,R_SEGR6
,R_SEGR7
};
725 static const int treg
[] = {R_TR0
,R_TR1
,R_TR2
,R_TR3
,R_TR4
,R_TR5
,R_TR6
,R_TR7
};
726 static const int xmmreg
[] = {R_XMM0
,R_XMM1
,R_XMM2
,R_XMM3
,R_XMM4
,R_XMM5
,R_XMM6
,R_XMM7
};
728 if (!(REG_AL
& ~regflags
))
730 if (!(REG_AX
& ~regflags
))
732 if (!(REG_EAX
& ~regflags
))
734 if (!(REG_DL
& ~regflags
))
736 if (!(REG_DX
& ~regflags
))
738 if (!(REG_EDX
& ~regflags
))
740 if (!(REG_CL
& ~regflags
))
742 if (!(REG_CX
& ~regflags
))
744 if (!(REG_ECX
& ~regflags
))
746 if (!(FPU0
& ~regflags
))
748 if (!(REG_CS
& ~regflags
))
749 return (regval
== 1) ? R_CS
: 0;
750 if (!(REG_DESS
& ~regflags
))
751 return (regval
== 0 || regval
== 2 || regval
== 3 ? sreg
[regval
] : 0);
752 if (!(REG_FSGS
& ~regflags
))
753 return (regval
== 4 || regval
== 5 ? sreg
[regval
] : 0);
754 if (!(REG_SEG67
& ~regflags
))
755 return (regval
== 6 || regval
== 7 ? sreg
[regval
] : 0);
757 /* All the entries below look up regval in an 8-entry array */
758 if (regval
< 0 || regval
> 7)
761 if (!((REGMEM
|BITS8
) & ~regflags
))
763 if (!((REGMEM
|BITS16
) & ~regflags
))
764 return reg16
[regval
];
765 if (!((REGMEM
|BITS32
) & ~regflags
))
766 return reg32
[regval
];
767 if (!(REG_SREG
& ~regflags
))
769 if (!(REG_CREG
& ~regflags
))
771 if (!(REG_DREG
& ~regflags
))
773 if (!(REG_TREG
& ~regflags
))
775 if (!(FPUREG
& ~regflags
))
776 return fpureg
[regval
];
777 if (!(MMXREG
& ~regflags
))
778 return mmxreg
[regval
];
779 if (!(XMMREG
& ~regflags
))
780 return xmmreg
[regval
];
785 static const char *whichcond(int condval
)
787 static int conds
[] = {
788 C_O
, C_NO
, C_C
, C_NC
, C_Z
, C_NZ
, C_NA
, C_A
,
789 C_S
, C_NS
, C_PE
, C_PO
, C_L
, C_NL
, C_NG
, C_G
791 return conditions
[conds
[condval
]];
795 * Process an effective address (ModRM) specification.
797 static unsigned char *do_ea (unsigned char *data
, int modrm
, int asize
,
798 int segsize
, operand
*op
)
800 int mod
, rm
, scale
, index
, base
;
802 mod
= (modrm
>> 6) & 03;
805 if (mod
== 3) { /* pure register version */
807 op
->segment
|= SEG_RMREG
;
815 * <mod> specifies the displacement size (none, byte or
816 * word), and <rm> specifies the register combination.
817 * Exception: mod=0,rm=6 does not specify [BP] as one might
818 * expect, but instead specifies [disp16].
820 op
->indexreg
= op
->basereg
= -1;
821 op
->scale
= 1; /* always, in 16 bits */
823 case 0: op
->basereg
= R_BX
; op
->indexreg
= R_SI
; break;
824 case 1: op
->basereg
= R_BX
; op
->indexreg
= R_DI
; break;
825 case 2: op
->basereg
= R_BP
; op
->indexreg
= R_SI
; break;
826 case 3: op
->basereg
= R_BP
; op
->indexreg
= R_DI
; break;
827 case 4: op
->basereg
= R_SI
; break;
828 case 5: op
->basereg
= R_DI
; break;
829 case 6: op
->basereg
= R_BP
; break;
830 case 7: op
->basereg
= R_BX
; break;
832 if (rm
== 6 && mod
== 0) { /* special case */
836 mod
= 2; /* fake disp16 */
840 op
->segment
|= SEG_NODISP
;
843 op
->segment
|= SEG_DISP8
;
844 op
->offset
= (signed char) *data
++;
847 op
->segment
|= SEG_DISP16
;
848 op
->offset
= *data
++;
849 op
->offset
|= ((unsigned) *data
++) << 8;
855 * Once again, <mod> specifies displacement size (this time
856 * none, byte or *dword*), while <rm> specifies the base
857 * register. Again, [EBP] is missing, replaced by a pure
858 * disp32 (this time that's mod=0,rm=*5*). However, rm=4
859 * indicates not a single base register, but instead the
860 * presence of a SIB byte...
864 case 0: op
->basereg
= R_EAX
; break;
865 case 1: op
->basereg
= R_ECX
; break;
866 case 2: op
->basereg
= R_EDX
; break;
867 case 3: op
->basereg
= R_EBX
; break;
868 case 5: op
->basereg
= R_EBP
; break;
869 case 6: op
->basereg
= R_ESI
; break;
870 case 7: op
->basereg
= R_EDI
; break;
872 if (rm
== 5 && mod
== 0) {
876 mod
= 2; /* fake disp32 */
878 if (rm
== 4) { /* process SIB */
879 scale
= (*data
>> 6) & 03;
880 index
= (*data
>> 3) & 07;
884 op
->scale
= 1 << scale
;
886 case 0: op
->indexreg
= R_EAX
; break;
887 case 1: op
->indexreg
= R_ECX
; break;
888 case 2: op
->indexreg
= R_EDX
; break;
889 case 3: op
->indexreg
= R_EBX
; break;
890 case 4: op
->indexreg
= -1; break;
891 case 5: op
->indexreg
= R_EBP
; break;
892 case 6: op
->indexreg
= R_ESI
; break;
893 case 7: op
->indexreg
= R_EDI
; break;
897 case 0: op
->basereg
= R_EAX
; break;
898 case 1: op
->basereg
= R_ECX
; break;
899 case 2: op
->basereg
= R_EDX
; break;
900 case 3: op
->basereg
= R_EBX
; break;
901 case 4: op
->basereg
= R_ESP
; break;
902 case 6: op
->basereg
= R_ESI
; break;
903 case 7: op
->basereg
= R_EDI
; break;
915 op
->segment
|= SEG_NODISP
;
918 op
->segment
|= SEG_DISP8
;
919 op
->offset
= (signed char) *data
++;
922 op
->segment
|= SEG_DISP32
;
923 op
->offset
= *data
++;
924 op
->offset
|= ((unsigned) *data
++) << 8;
925 op
->offset
|= ((long) *data
++) << 16;
926 op
->offset
|= ((long) *data
++) << 24;
934 * Determine whether the instruction template in t corresponds to the data
935 * stream in data. Return the number of bytes matched if so.
937 static int matches (struct itemplate
*t
, unsigned char *data
, int asize
,
938 int osize
, int segsize
, int rep
, insn
*ins
)
940 unsigned char * r
= (unsigned char *)(t
->code
);
941 unsigned char * origdata
= data
;
942 int a_used
= FALSE
, o_used
= FALSE
;
947 else if ( rep
== 0xF3 )
953 if (c
>= 01 && c
<= 03) {
960 case 0x07: ins
->oprs
[0].basereg
= 0; break;
961 case 0x17: ins
->oprs
[0].basereg
= 2; break;
962 case 0x1F: ins
->oprs
[0].basereg
= 3; break;
963 default: return FALSE
;
968 case 0xA1: ins
->oprs
[0].basereg
= 4; break;
969 case 0xA9: ins
->oprs
[0].basereg
= 5; break;
970 default: return FALSE
;
975 case 0x06: ins
->oprs
[0].basereg
= 0; break;
976 case 0x0E: ins
->oprs
[0].basereg
= 1; break;
977 case 0x16: ins
->oprs
[0].basereg
= 2; break;
978 case 0x1E: ins
->oprs
[0].basereg
= 3; break;
979 default: return FALSE
;
984 case 0xA0: ins
->oprs
[0].basereg
= 4; break;
985 case 0xA8: ins
->oprs
[0].basereg
= 5; break;
986 default: return FALSE
;
989 if (c
>= 010 && c
<= 012) {
990 int t
= *r
++, d
= *data
++;
991 if (d
< t
|| d
> t
+7)
994 ins
->oprs
[c
-010].basereg
= d
-t
;
995 ins
->oprs
[c
-010].segment
|= SEG_RMREG
;
1001 if (c
>= 014 && c
<= 016) {
1002 ins
->oprs
[c
-014].offset
= (signed char) *data
++;
1003 ins
->oprs
[c
-014].segment
|= SEG_SIGNED
;
1005 if (c
>= 020 && c
<= 022)
1006 ins
->oprs
[c
-020].offset
= *data
++;
1007 if (c
>= 024 && c
<= 026)
1008 ins
->oprs
[c
-024].offset
= *data
++;
1009 if (c
>= 030 && c
<= 032) {
1010 ins
->oprs
[c
-030].offset
= *data
++;
1011 ins
->oprs
[c
-030].offset
|= (((unsigned) *data
++) << 8);
1013 if (c
>= 034 && c
<= 036) {
1014 ins
->oprs
[c
-034].offset
= *data
++;
1015 ins
->oprs
[c
-034].offset
|= (((unsigned) *data
++) << 8);
1017 ins
->oprs
[c
-034].offset
|= (((long) *data
++) << 16);
1018 ins
->oprs
[c
-034].offset
|= (((long) *data
++) << 24);
1020 if (segsize
!= asize
)
1021 ins
->oprs
[c
-034].addr_size
= asize
;
1023 if (c
>= 040 && c
<= 042) {
1024 ins
->oprs
[c
-040].offset
= *data
++;
1025 ins
->oprs
[c
-040].offset
|= (((unsigned) *data
++) << 8);
1026 ins
->oprs
[c
-040].offset
|= (((long) *data
++) << 16);
1027 ins
->oprs
[c
-040].offset
|= (((long) *data
++) << 24);
1029 if (c
>= 044 && c
<= 046) {
1030 ins
->oprs
[c
-044].offset
= *data
++;
1031 ins
->oprs
[c
-044].offset
|= (((unsigned) *data
++) << 8);
1033 ins
->oprs
[c
-044].offset
|= (((long) *data
++) << 16);
1034 ins
->oprs
[c
-044].offset
|= (((long) *data
++) << 24);
1036 if (segsize
!= asize
)
1037 ins
->oprs
[c
-044].addr_size
= asize
;
1039 if (c
>= 050 && c
<= 052) {
1040 ins
->oprs
[c
-050].offset
= (signed char) *data
++;
1041 ins
->oprs
[c
-050].segment
|= SEG_RELATIVE
;
1043 if (c
>= 060 && c
<= 062) {
1044 ins
->oprs
[c
-060].offset
= *data
++;
1045 ins
->oprs
[c
-060].offset
|= (((unsigned) *data
++) << 8);
1046 ins
->oprs
[c
-060].segment
|= SEG_RELATIVE
;
1047 ins
->oprs
[c
-060].segment
&= ~SEG_32BIT
;
1049 if (c
>= 064 && c
<= 066) {
1050 ins
->oprs
[c
-064].offset
= *data
++;
1051 ins
->oprs
[c
-064].offset
|= (((unsigned) *data
++) << 8);
1053 ins
->oprs
[c
-064].offset
|= (((long) *data
++) << 16);
1054 ins
->oprs
[c
-064].offset
|= (((long) *data
++) << 24);
1055 ins
->oprs
[c
-064].segment
|= SEG_32BIT
;
1057 ins
->oprs
[c
-064].segment
&= ~SEG_32BIT
;
1058 ins
->oprs
[c
-064].segment
|= SEG_RELATIVE
;
1059 if (segsize
!= osize
) {
1060 ins
->oprs
[c
-064].type
=
1061 (ins
->oprs
[c
-064].type
& NON_SIZE
)
1062 | ((osize
== 16) ? BITS16
: BITS32
);
1065 if (c
>= 070 && c
<= 072) {
1066 ins
->oprs
[c
-070].offset
= *data
++;
1067 ins
->oprs
[c
-070].offset
|= (((unsigned) *data
++) << 8);
1068 ins
->oprs
[c
-070].offset
|= (((long) *data
++) << 16);
1069 ins
->oprs
[c
-070].offset
|= (((long) *data
++) << 24);
1070 ins
->oprs
[c
-070].segment
|= SEG_32BIT
| SEG_RELATIVE
;
1072 if (c
>= 0100 && c
< 0130) {
1073 int modrm
= *data
++;
1074 ins
->oprs
[c
& 07].basereg
= (modrm
>> 3) & 07;
1075 ins
->oprs
[c
& 07].segment
|= SEG_RMREG
;
1076 data
= do_ea (data
, modrm
, asize
, segsize
,
1077 &ins
->oprs
[(c
>> 3) & 07]);
1079 if (c
>= 0130 && c
<= 0132) {
1080 ins
->oprs
[c
-0130].offset
= *data
++;
1081 ins
->oprs
[c
-0130].offset
|= (((unsigned) *data
++) << 8);
1083 if (c
>= 0140 && c
<= 0142) {
1084 ins
->oprs
[c
-0140].offset
= *data
++;
1085 ins
->oprs
[c
-0140].offset
|= (((unsigned) *data
++) << 8);
1086 ins
->oprs
[c
-0140].offset
|= (((long) *data
++) << 16);
1087 ins
->oprs
[c
-0140].offset
|= (((long) *data
++) << 24);
1089 if (c
>= 0200 && c
<= 0277) {
1090 int modrm
= *data
++;
1091 if (((modrm
>> 3) & 07) != (c
& 07))
1092 return FALSE
; /* spare field doesn't match up */
1093 data
= do_ea (data
, modrm
, asize
, segsize
,
1094 &ins
->oprs
[(c
>> 3) & 07]);
1096 if (c
>= 0300 && c
<= 0302) {
1098 ins
->oprs
[c
-0300].segment
|= SEG_32BIT
;
1100 ins
->oprs
[c
-0300].segment
&= ~SEG_32BIT
;
1116 if (asize
!= segsize
)
1134 if (osize
!= segsize
)
1140 int t
= *r
++, d
= *data
++;
1141 if (d
< t
|| d
> t
+15)
1144 ins
->condition
= d
- t
;
1162 * Check for unused rep or a/o prefixes.
1166 ins
->prefixes
[ins
->nprefix
++] = drep
;
1167 if (!a_used
&& asize
!= segsize
)
1168 ins
->prefixes
[ins
->nprefix
++] = (asize
== 16 ? P_A16
: P_A32
);
1169 if (!o_used
&& osize
!= segsize
)
1170 ins
->prefixes
[ins
->nprefix
++] = (osize
== 16 ? P_O16
: P_O32
);
1172 return data
- origdata
;
1175 long disasm (unsigned char *data
, char *output
, int segsize
, long offset
)
1177 struct itemplate
**p
, **best_p
;
1178 int length
, best_length
= 0;
1180 int rep
, lock
, asize
, osize
, i
, slen
, colon
;
1181 unsigned char *origdata
;
1184 unsigned long goodness
, best
;
1187 * Scan for prefixes.
1189 asize
= osize
= segsize
;
1191 ins
.condition
= ins
.nprefix
= rep
= lock
= 0;
1194 if (*data
== 0xF3 || *data
== 0xF2)
1196 else if (*data
== 0xF0)
1198 else if (*data
== 0x2E || *data
== 0x36 || *data
== 0x3E ||
1199 *data
== 0x26 || *data
== 0x64 || *data
== 0x65) {
1201 case 0x2E: segover
= "cs"; break;
1202 case 0x36: segover
= "ss"; break;
1203 case 0x3E: segover
= "ds"; break;
1204 case 0x26: segover
= "es"; break;
1205 case 0x64: segover
= "fs"; break;
1206 case 0x65: segover
= "gs"; break;
1208 } else if (*data
== 0x66)
1209 osize
= 48 - segsize
, data
++;
1210 else if (*data
== 0x67)
1211 asize
= 48 - segsize
, data
++;
1216 tmp_ins
.oprs
[0].segment
= tmp_ins
.oprs
[1].segment
=
1217 tmp_ins
.oprs
[2].segment
=
1218 tmp_ins
.oprs
[0].addr_size
= tmp_ins
.oprs
[1].addr_size
=
1219 tmp_ins
.oprs
[2].addr_size
= (segsize
== 16 ? 0 : SEG_32BIT
);
1220 tmp_ins
.condition
= -1;
1221 best
= ~0UL; /* Worst possible */
1223 for (p
= itable
[*data
]; *p
; p
++) {
1224 if ( (length
= matches(*p
, data
, asize
, osize
,
1225 segsize
, rep
, &tmp_ins
)) ) {
1228 * Final check to make sure the types of r/m match up.
1230 for (i
= 0; i
< (*p
)->operands
; i
++) {
1232 /* If it's a mem-only EA but we have a register, die. */
1233 ((tmp_ins
.oprs
[i
].segment
& SEG_RMREG
) &&
1234 !(MEMORY
& ~(*p
)->opd
[i
])) ||
1236 /* If it's a reg-only EA but we have a memory ref, die. */
1237 (!(tmp_ins
.oprs
[i
].segment
& SEG_RMREG
) &&
1238 !(REGNORM
& ~(*p
)->opd
[i
]) &&
1239 !((*p
)->opd
[i
] & REG_SMASK
)) ||
1241 /* Register type mismatch (eg FS vs REG_DESS): die. */
1242 ((((*p
)->opd
[i
] & (REGISTER
| FPUREG
)) ||
1243 (tmp_ins
.oprs
[i
].segment
& SEG_RMREG
)) &&
1244 !whichreg ((*p
)->opd
[i
], tmp_ins
.oprs
[i
].basereg
))) {
1251 goodness
= (*p
)->flags
& IF_PFMASK
;
1252 if ( goodness
< best
) {
1253 /* This is the best one found so far */
1256 best_length
= length
;
1264 return 0; /* no instruction was matched */
1266 /* Pick the best match */
1268 length
= best_length
;
1273 slen
+= sprintf(output
+slen
, "lock ");
1274 for (i
= 0; i
< ins
.nprefix
; i
++)
1275 switch (ins
.prefixes
[i
]) {
1276 case P_REP
: slen
+= sprintf(output
+slen
, "rep "); break;
1277 case P_REPE
: slen
+= sprintf(output
+slen
, "repe "); break;
1278 case P_REPNE
: slen
+= sprintf(output
+slen
, "repne "); break;
1279 case P_A16
: slen
+= sprintf(output
+slen
, "a16 "); break;
1280 case P_A32
: slen
+= sprintf(output
+slen
, "a32 "); break;
1281 case P_O16
: slen
+= sprintf(output
+slen
, "o16 "); break;
1282 case P_O32
: slen
+= sprintf(output
+slen
, "o32 "); break;
1285 for (i
= 0; i
< elements(ico
); i
++)
1286 if ((*p
)->opcode
== ico
[i
]) {
1287 slen
+= sprintf(output
+slen
, "%s%s", icn
[i
],
1288 whichcond(ins
.condition
));
1291 if (i
>= elements(ico
))
1292 slen
+= sprintf(output
+slen
, "%s", insn_names
[(*p
)->opcode
]);
1294 length
+= data
- origdata
; /* fix up for prefixes */
1295 for (i
=0; i
<(*p
)->operands
; i
++) {
1296 output
[slen
++] = (colon
? ':' : i
==0 ? ' ' : ',');
1298 if (ins
.oprs
[i
].segment
& SEG_RELATIVE
) {
1299 ins
.oprs
[i
].offset
+= offset
+ length
;
1301 * sort out wraparound
1303 if (!(ins
.oprs
[i
].segment
& SEG_32BIT
))
1304 ins
.oprs
[i
].offset
&= 0xFFFF;
1307 if ((*p
)->opd
[i
] & COLON
)
1312 if (((*p
)->opd
[i
] & (REGISTER
| FPUREG
)) ||
1313 (ins
.oprs
[i
].segment
& SEG_RMREG
))
1315 ins
.oprs
[i
].basereg
= whichreg ((*p
)->opd
[i
],
1316 ins
.oprs
[i
].basereg
);
1317 if ( (*p
)->opd
[i
] & TO
)
1318 slen
+= sprintf(output
+slen
, "to ");
1319 slen
+= sprintf(output
+slen
, "%s",
1320 reg_names
[ins
.oprs
[i
].basereg
-EXPR_REG_START
]);
1321 } else if (!(UNITY
& ~(*p
)->opd
[i
])) {
1322 output
[slen
++] = '1';
1323 } else if ( (*p
)->opd
[i
] & IMMEDIATE
) {
1324 if ( (*p
)->opd
[i
] & BITS8
) {
1325 slen
+= sprintf(output
+slen
, "byte ");
1326 if (ins
.oprs
[i
].segment
& SEG_SIGNED
) {
1327 if (ins
.oprs
[i
].offset
< 0) {
1328 ins
.oprs
[i
].offset
*= -1;
1329 output
[slen
++] = '-';
1331 output
[slen
++] = '+';
1333 } else if ( (*p
)->opd
[i
] & BITS16
) {
1334 slen
+= sprintf(output
+slen
, "word ");
1335 } else if ( (*p
)->opd
[i
] & BITS32
) {
1336 slen
+= sprintf(output
+slen
, "dword ");
1337 } else if ( (*p
)->opd
[i
] & NEAR
) {
1338 slen
+= sprintf(output
+slen
, "near ");
1339 } else if ( (*p
)->opd
[i
] & SHORT
) {
1340 slen
+= sprintf(output
+slen
, "short ");
1342 slen
+= sprintf(output
+slen
, "0x%lx", ins
.oprs
[i
].offset
);
1343 } else if ( !(MEM_OFFS
& ~(*p
)->opd
[i
]) ) {
1344 slen
+= sprintf(output
+slen
, "[%s%s%s0x%lx]",
1345 (segover
? segover
: ""),
1346 (segover
? ":" : ""),
1347 (ins
.oprs
[i
].addr_size
== 32 ? "dword " :
1348 ins
.oprs
[i
].addr_size
== 16 ? "word " : ""),
1349 ins
.oprs
[i
].offset
);
1351 } else if ( !(REGMEM
& ~(*p
)->opd
[i
]) ) {
1352 int started
= FALSE
;
1353 if ( (*p
)->opd
[i
] & BITS8
)
1354 slen
+= sprintf(output
+slen
, "byte ");
1355 if ( (*p
)->opd
[i
] & BITS16
)
1356 slen
+= sprintf(output
+slen
, "word ");
1357 if ( (*p
)->opd
[i
] & BITS32
)
1358 slen
+= sprintf(output
+slen
, "dword ");
1359 if ( (*p
)->opd
[i
] & BITS64
)
1360 slen
+= sprintf(output
+slen
, "qword ");
1361 if ( (*p
)->opd
[i
] & BITS80
)
1362 slen
+= sprintf(output
+slen
, "tword ");
1363 if ( (*p
)->opd
[i
] & FAR
)
1364 slen
+= sprintf(output
+slen
, "far ");
1365 if ( (*p
)->opd
[i
] & NEAR
)
1366 slen
+= sprintf(output
+slen
, "near ");
1367 output
[slen
++] = '[';
1368 if (ins
.oprs
[i
].addr_size
)
1369 slen
+= sprintf(output
+slen
, "%s",
1370 (ins
.oprs
[i
].addr_size
== 32 ? "dword " :
1371 ins
.oprs
[i
].addr_size
== 16 ? "word " : ""));
1373 slen
+= sprintf(output
+slen
, "%s:", segover
);
1376 if (ins
.oprs
[i
].basereg
!= -1) {
1377 slen
+= sprintf(output
+slen
, "%s",
1378 reg_names
[(ins
.oprs
[i
].basereg
-
1382 if (ins
.oprs
[i
].indexreg
!= -1) {
1384 output
[slen
++] = '+';
1385 slen
+= sprintf(output
+slen
, "%s",
1386 reg_names
[(ins
.oprs
[i
].indexreg
-
1388 if (ins
.oprs
[i
].scale
> 1)
1389 slen
+= sprintf(output
+slen
, "*%d", ins
.oprs
[i
].scale
);
1392 if (ins
.oprs
[i
].segment
& SEG_DISP8
) {
1394 if (ins
.oprs
[i
].offset
& 0x80) {
1395 ins
.oprs
[i
].offset
= - (signed char) ins
.oprs
[i
].offset
;
1398 slen
+= sprintf(output
+slen
, "%c0x%lx", sign
,
1399 ins
.oprs
[i
].offset
);
1400 } else if (ins
.oprs
[i
].segment
& SEG_DISP16
) {
1402 output
[slen
++] = '+';
1403 slen
+= sprintf(output
+slen
, "0x%lx", ins
.oprs
[i
].offset
);
1404 } else if (ins
.oprs
[i
].segment
& SEG_DISP32
) {
1406 output
[slen
++] = '+';
1407 slen
+= sprintf(output
+slen
, "0x%lx", ins
.oprs
[i
].offset
);
1409 output
[slen
++] = ']';
1411 slen
+= sprintf(output
+slen
, "<operand%d>", i
);
1414 output
[slen
] = '\0';
1415 if (segover
) { /* unused segment override */
1419 p
[count
+3] = p
[count
];
1420 strncpy (output
, segover
, 2);