2
; Here is the start of the disassembly part of the program.
4
;--- flag bits preflags/preused
6
PRESEG equ 1 ;segment prefix
7
PREREP equ 2 ;rep prefixes
8
PREREPZ equ 4 ;f3, not f2
9
PRELOCK equ 8 ;lock prefix
10
PRE32D equ 10h ;flag for operand size (66h)
11
PRE32A equ 20h ;flag for address size (67h)
12
PREWAIT equ 40h ;prefix wait (not really a prefix)
13
GOTREGM equ 80h ;preused only: set if we have the reg/mem part
15
;--- equates for disflags:
17
DIS_F_REPT equ 1 ;repeat after pop ss, etc.
18
DIS_F_SHOW equ 2 ;show memory contents
19
DIS_I_SHOW equ 4 ;there are memory contents to show
20
DIS_I_UNUSED equ 8 ;(internal) print " (unused)"
21
DIS_I_SHOWSIZ equ 10h ;(internal) always show the operand size
22
DIS_I_KNOWSIZ equ 20h ;(internal) we know the operand size of instr.
23
DIS_I_MEMACC equ 80h ;(internal) we're just accessing a mem ref ( dumpreg )
26
exitm <num&h+OPTYPES_BASE>
29
;--- define "general purpose register"
31
REG_®ist& equ ($ - rgnam816)/2
36
;--- 0- 7: 8-bit registers
37
;--- 8-15: 16-bit registers
38
;--- 16-23: 32-bit registers
42
;--- define "segment register"
44
REG_®ist& equ REG_NO_GPR + ($ - segrgnam)/2
50
dis_n dw 0 ;number of bytes in instruction so far
51
dw 0 ;must follow dis_n (will always remain 0)
52
idxins dw 0 ;index of the instruction (unsqueezed)
53
addrr dw 0 ;address in mod r/m byte (16bit only)
54
sizeloc dw 0 ;address of size words in output line
56
;--- preflags and preused must be consecutive
57
preflags db 0 ;flags for prefixes found so far
58
preused db 0 ;flags for prefixes used so far
60
bInstr db 0 ;the main instruction byte
61
rmsize db 0 ;<0 or 0 or >0 means mod r/m is 8 or 16 or 32
62
segmnt db 0 ;segment determined by prefix (or otherwise)
63
disflags db 0 ;flags for the disassembler
64
disflags2 db 0 ;another copy of DIS_I_KNOWSIZ
72
;--- table of obsolete-instruction values.
73
;--- instructions are FENI, FDISI, FSETPM, MOV to/from TRx
74
obsinst dw SFPGROUP3, SFPGROUP3+1, SFPGROUP3+4
75
dw SPARSE_BASE+24h, SPARSE_BASE+26h
77
;--- Table for 16-bit mod r/m addressing. 8 = BX, 4 = BP, 2 = SI, 1 = DI.
79
rmtab db 8+2, 8+1, 4+2, 4+1, 2, 1, 4, 8
81
;--- Tables of register names.
82
;--- rgnam816/rgnam16/segrgnam must be consecutive.
83
;--- also used by the line assembler
103
N_REGS16 equ ( $ - rgnam16 ) / 2
111
N_SEGREGS equ ( $ - segrgnam ) / 2
117
N_ALLREGS equ ( $ - rgnam816 ) / 2
119
;--- address of debuggee's segment registers
120
;--- used to display memory contents ( DIS_F_SHOW )
121
segrgaddr dw regs.rES,regs.rCS,regs.rSS,regs.rDS
122
if RING0 ; for DebugR, we also display FS/GS contents
123
dw regs.rFS, regs.rGS
126
;--- Tables for handling of named prefixes.
128
prefixlist db 26h,2eh,36h,3eh,64h,65h ;segment prefixes (in order)
129
db 9bh,0f0h,0f2h,0f3h ;WAIT,LOCK,REPNE,REPE
130
N_PREFIX equ $ - prefixlist
131
prefixmnem dw MN_WAIT,MN_LOCK,MN_REPNE,MN_REPE
135
disasm1: ;<--- standard entry
138
disasm proc ;<--- entry with AL=disflags ( DIS_F_REPT & DIS_F_SHOW )
142
CONST segment ; must be located inside disasm since local labels are used here
146
; Jump table for OP_IMM, OP_RM, OP_M, OP_R_MOD, OP_MOFFS, OP_R, OP_R_ADD,
148
; See orders of asm_jmp1 and bittab.
151
dw dop_imm, dop_rm, dop_m, dop_r_mod
152
dw dop_moffs, dop_r, dop_r_add, dop_ax
154
; jump table for displaying operands
155
; See orders of asm_jmp1 and bittab.
158
dw dop_m64, dop_mfloat, dop_mdouble, dop_m80, dop_mxx, dop_farmem ;00-05
159
dw dop_farimm, dop_rel8, dop_rel1632 ;06-08
160
dw dop_st1, dop_sti, dop_cr ;09-11
161
dw dop_dr, dop_tr, dop_segreg, dop_imms8 ;12-15
162
dw dop_imm8, dop_mmx, dop_shosiz ;16-18
163
;--- string items OP_1 .. OP_SS
169
db 'CS','DS','ES','FS','GS','SS' ;24-29
171
;--- Jump table for a certain place.
172
;--- the size of this table matches OPTYPES_BASE
175
dw disbad ;illegal instruction
176
dw da_twobyte ;two byte instruction (0F xx)
177
dw da_insgrp ;instruction group
178
dw da_fpuins ;coprocessor instruction
179
dw da_fpugrp ;coprocessor instruction group
180
dw da_insprf ;instruction prefix (including 66h/67h)
181
OPTYPES_BASE equ $ - dis_jmp2
195
mov word ptr [preflags],ax ;clear preflags and preused
201
mov [segmnt],3 ;initially use DS segment
202
mov [rmsize],80h ;signed byte (-128): don't display any memory
203
mov word ptr [ai.dismach],0;no special machine needed, so far
204
call disgetbyte ;get a byte of the instruction
205
cmp al,9bh ;wait instruction (must be the first prefix)
208
; The wait instruction is actually a separate instruction as far as
209
; the x86 is concerned, but we treat it as a prefix since there are
210
; some mnemonics that incorporate it. But it has to be treated specially
211
; since you can't do, e.g., seg cs wait ... but must do wait seg cs ...
212
; instead. We'll catch it later if the wait instruction is not going to
213
; be part of a shared mnemonic.
215
or [preflags],PREWAIT
217
; If we've found a prefix, we return here for the actual instruction
218
; (or another prefix).
223
mov [bInstr],al ;save away the instruction
226
;--- Now we have the sequence number of the instruction in AX. Look it up.
230
mov [idxins],ax ;save the compressed index
232
jb @F ;if it's not from the squeezed part of the table
233
mov bl,[sqztab+bx-SPARSE_BASE]
235
add bx,SPARSE_BASE ;bx = compressed index
237
mov cl,[optypes+bx] ;cx = opcode type
240
mov bx,[opinfo+bx] ;bx = other info (mnemonic if a true instruction)
246
jb @F ;if a higher machine is already required
247
mov [ai.dismach],al ;set machine type
249
and bh,0fh ;=and bx,0fffh - remove the machine field
251
jae da13 ;if this is an actual instruction
252
call [dis_jmp2+si] ;otherwise, do more specific processing
253
jmp da3 ;back for more
255
;--- dis_jmp2[1]: Two-byte instruction 0F xx: index 1E0-2DF.
264
;--- dis_jmp2[2]: Instruction group.
265
;--- BX contains "instruction base": 100h, 110h, ...
268
call getregmem_r ;get the middle 3 bits of the R/M byte
273
;--- dis_jmp2[3]: Coprocessor instruction.
274
;--- BX contains "instruction base": 148h, 158h, ...
277
or [disflags], DIS_I_SHOWSIZ
278
or [ai.dmflags], DM_COPR
281
jb da_insgrp ;range 00-bfh is same as an instruction group
283
shr al,cl ;C0-FF --> 18-1F
284
sub al,18h-8 ;18-1F --> 08-0F
289
;--- dis_jmp2[4]: Coprocessor instruction group.
290
;--- BX contains "instruction base": 1C8h, 1D0h, 1D8h
299
;--- dis_jmp2[5]: Instruction prefix. At this point, bl = prefix bits; bh = segment
302
if 0 ; v2.01: removed - opsize/adrsize prefixes "toggle" just once
304
and bl,not (PRE32D or PRE32A) ;these flags are XORed!
307
jnz disbad0 ;if there are duplicates
310
jz @F ;if not a segment
311
mov [segmnt],bh ;save the segment
313
pop ax ;discard return address
317
jmp disbad ;we don't allow duplicate prefixes
323
;--- here: si=index for opindex to scan oplists table
326
mov ax, word ptr [opindex][si]
327
mov [bEndOplItem], ah
331
if ?PM ; v2.01: update opsize/adrsize prefixes if D bit set AFTER prefixes have been read
334
xor [preflags], PRE32D or PRE32A
338
; OK. Here we go. This is an actual instruction.
339
; BX=offset of mnemonic in mnlist
340
; SI=offset of operand list in oplists
341
; First print the op mnemonic.
344
lea si,[mnlist+bx] ;offset of mnemonic
345
cmp si,offset mnlist+MN_BSWAP
348
jz disbad0 ;if no operand-size prefix
350
call showop ;print out the op code (at line_out+28)
351
mov [sizeloc],0 ;clear out this flag
352
pop si ;recover list of operands
353
add si,offset oplists
355
; Loop over operands. si -> operand type.
356
; Fortunately the operands appear in the instruction in the same
357
; order as they appear in the disassembly output.
361
sub ax, offset oplists
362
cmp al, [bEndOplItem]
363
jae da21 ;if we're done
364
mov [disflags2],0 ;clear out size-related flags
365
lodsb ;get the operand type
367
jb da18 ;if it's not size dependent
368
mov [disflags2],DIS_I_KNOWSIZ ;indicate variable size
370
jae da16 ;if the size is fixed (8,16,32,64)
372
jae da15 ;if word or dword
377
or [preused], PRE32D ;mark this flag as used
379
and ah, PRE32D ;this will be 10h for dword, 00h for word
383
mov ah,al ;OP_8, OP_16, OP_32 or OP_64 (we know which)
384
and ah,0f0h ;this converts ah to <0 for byte, =0 for word,
385
sub ah,OP_16 ;and >0 for dword (byte=F0,word=0,dword=10,qword=20)
387
;--- Now we know the size (in ah); branch off to do the operand itself.
391
and bx,0eh ;8 entries (IMM, RM, M, R_MOD, M_OFFS, R, R_ADD, AX)
392
call [dis_jmp1+bx] ;print out the operand
393
jmp da20 ;done with operand
395
;--- Sizeless operands.
400
xchg ax,bx ; mov bx, ax
401
mov ax,[dis_optab+bx-2]
402
jb @F ;if it's not a string
405
jnz da20 ;if it's two characters
407
jmp da20 ;done with operand
409
call ax ;otherwise, do something else
413
jmp da14 ;check for another operand
415
;--- all operands done.
417
;-------------------------------------------------------------------
418
;--- now check and loop for unused prefixes:
419
;--- OPSIZE (66h), ADDRSIZE (67h), WAIT, segment, REP[N][Z], LOCK
421
;--- v2.50: the string instructions may have both 66h & 67h prefixes.
422
;--- a 67h prefix will now be shown as a comment behind the opcode.
423
;--- this code has been reworked.
428
db PREWAIT ; a WAIT prefix hanging
429
db PRE32D ; opsize 66h
430
db PRE32A ; adrsize 67h
435
txsize label byte ; items in txtabs tables
447
dw offset prfxtab ; movsb/w, outsb/w, cmpsb/w, lodsb/w, xlat
460
db 6ch,6dh,6eh,6fh ; ins, outs
461
db 0A4h,0A5h,0A6h,0A7h ; movs, cmps, lods, scas, stos
462
db 0AAh,0ABh,0ACh,0ADh,0AEh,0AFh
470
;--- CS 16-bit: if PRE32x == 1, a prefix has been found.
471
;--- + PRE32D == 0: nothing done
472
;--- + PRE32D == 1: CS=32: scan opc table, fnd: switch opcode, notfnd:bad prefix
473
;--- + PRE32A == 0: nothing done
474
;--- + PRE32A == 1: CS=32, scan opc table, fnd: switch opcode, notfnd: check str instr
475
;--- CS 32-bit: if PRE32x == 1, no prefix has been found.
476
;--- + PRE32D == 0, CS=16: scan opc table, fnd: exit, notfnd: bad prefix
477
;--- + PRE32D == 1, CS=32: scan opc table, fnd: switch opcodes, notfnd: exit
478
;--- + PRE32A == 0, CS=16: scan opc table, fnd: exit, notfnd: check str instr
479
;--- + PRE32A == 1, CS=32: scan opc table, fnd: switch opcodes, notfnd: check str instr
481
;--- note: a prefix might be marked as "used" already. In this case it must be skipped!
483
;--- di=current output in line_out
484
;--- may be changed by the prefix loop if a prefix has to be inserted.
487
cmp byte ptr [di-1],',' ; skip the comma behind the last operand
491
; @dprintf "da21, di=%X", di
494
mov ax, word ptr [preflags] ; ah=preused
498
;--- if CS is 32bit, checks for A32 must be done in any case.
499
;--- to detect unused 66h prefixes, PRE32D is to be set as well.
500
or al, PRE32A or PRE32D
504
and al, ah ;skip flags that are set in preused
505
test al,[bx][txflags]
516
or [preused], al ;mark this prefix as used
521
; @dprintf "da21 done: preflags=%X", word ptr preflags
533
add di,cx ;position DI for opcode replacement
547
jmp hdl_showop ;copy op mnemonic, preserve di
551
test [bCSAttr], CS32 ; nothing special if CS is 16-bit
553
@dprintf "hdl_d32, scan opcode tab, preflags=%X", word ptr [preflags]
556
@dprintf "hdl_d32, CS=32: opcode found"
557
test [preflags], PRE32D ; 66h prefix in CS32 code?
558
jz hdl_d32_ex ; if yes: exit
559
jmp hdl_showop ; if no: switch opcode to 32-bit
561
@dprintf "hdl_d32, opcode not found"
562
test [preflags], PRE32D ; 66h prefix in CS32 code?
563
jz disbad2 ; if yes: bad 66h prefix
569
call hdl_scan_table ; check for the few opcodes that change with 67h prefix (LOOPx,JCXZ)
571
@dprintf "hdl_a32, opcode found"
573
test [preflags], PRE32A ; CS32?
574
jz hdl_a32_ex ; if no, do nothing
576
jmp hdl_showop ; switch opcode if found
578
@dprintf "hdl_a32, opcode not found"
582
test [preflags], PRE32A ; 32bit and a true 67h prefix in code stream?
583
jnz hdl_a32_ex ; if no, do nothing
586
@dprintf "hdl_a32, true 67h prefix, testing string instr"
588
mov di, offset strinstr
609
@dprintf "hdl_seg, ax=%X dx=%X, cx=%X", ax, dx, cx
611
jnz disbad2 ;if index > 256
616
jne disbad2 ;if it's not on the list
620
mov di,offset line_out+MNEMONOFS
621
call showseg ;show segment register
625
; or [preused],PRESEG ;mark it as used
628
;--- ax=instr, cx=items in table, dx=offset table
632
jnz disbad2 ;if not in the first 256 bytes
633
and al,not 1 ;clear bit0 (MOVSW -> MOVSB)
635
mov di,dx ;scan those for REP first
637
mov si,offset mnlist+MN_REP
638
je hdl_insprf ;if one of the REP instructions
639
mov cl,N_REPALL - N_REPNC
641
jne disbad2 ;if not one of the REPE/REPNE instructions
642
mov si,offset mnlist+MN_REPE
643
; test [preused],PREREPZ ; v2.50: isn't set yet with the new code,
644
test [preflags],PREREPZ ; but we may use [preflags].
645
jnz hdl_insprf ;if REPE
646
mov si,offset mnlist+MN_REPNE
647
jmp hdl_insprf ;it's REPNE
653
jne disbad2 ;if not in the approved list
654
test [preused],PRESEG
655
jz disbad2 ;if memory was not accessed
656
mov si,offset mnlist+MN_LOCK
657
; or [preused],PRELOCK
659
;--- Slip in another mnemonic: REP/REPE/REPNE/LOCK.
660
;--- SI = offset of mnemonic, what should be
661
;--- DI is on the stack.
675
;--- Done with instruction. Erase the size indicator, if appropriate.
680
jz da28b ;if there was no size given
682
test al,DIS_I_SHOWSIZ
683
jnz da28b ;if we need to show the size
684
test al,DIS_I_KNOWSIZ
685
jz da28b ;if the size is not known already
687
mov si,di ;save old di
690
scasb ;skip size name
691
jne @B ;if not done yet
692
;(The above is the same as repne scasb, but
693
;has no effect on cx.)
694
add di,4 ;skip 'PTR '
697
rep movsb ;move the line
699
;--- Now we're really done. Print out the bytes on the left.
702
push di ;print start of disassembly line
703
mov di,offset line_out
704
@dispsegm [u_addr+4];print segment part of address
707
sizeprfX ;mov eax,[u_addr+0]
714
mov si,offset line_out+MNEMONOFS - 1
718
jle da29 ;if it's a short instruction which fits in one line
727
mov di,offset line_out
734
mov al,' ' ;pad to op code
735
mov cx,offset line_out+MNEMONOFS
741
test [disflags], DIS_I_UNUSED
742
jz da32 ;if we don't print ' (unused)'
744
cmp byte ptr [di-1],' '
745
jne @F ;if there's already a space here
748
call copystring ;si->di
750
;--- Print info. on minimal processor needed.
754
mov di,offset obsinst
756
call showmach ;show the machine type, if needed
758
jcxz da32f ;if no message
760
;--- Print a message on the far right.
762
mov ax,offset line_out+79
765
call tab_to ;tab out to the location
767
rep movsb ;copy the string
770
;--- Dump referenced memory location.
771
;--- v2.50: skip this if instruction is LEA!
775
xor al,DIS_F_SHOW + DIS_I_SHOW
776
test al,DIS_F_SHOW + DIS_I_SHOW
777
jnz da32z ;if there is no memory location to show
779
cmp [bInstr], 8Dh ; v2.50: don't show mem contents for lea!
782
ife RING0 ; for DebugR, FS/GS memory contents aren't skipped
784
ja da32z ;if FS or GS
786
mov ax,offset line_out+79-8 ; room for ss:oooo=bb|wwww|dddddddd
791
add cx, 4 ; 4 more chars
793
add cx, 2 ; 2 more chars
798
call showseg ;show segment register
802
call hexword ;show offset
805
mov al,[segmnt] ;segment number
808
xchg ax,bx ;mov bx,ax
809
mov bx,[segrgaddr+bx] ;get address of value
811
;--- v2.0: we don't want that just msg "General Protection Fault"
812
;--- appears, without a hint what the underlying problem is.
813
;--- so display what's rendered so far...
815
or [disflags], DIS_I_MEMACC ; tell exc handler to print a crlf first
816
mov di, offset line_out
820
;--- v2.0: just read the bytes that the instruction would
829
call hexbyte ;display byte
834
and [disflags], not DIS_I_MEMACC
838
call trimputs ;print (rest of) disassembled line
841
jz da34 ;if we're not allowed to repeat ourselves
843
jnz @F ;if we printed ' (unused)'
846
je @F ;if it was 'pop ss'
848
je @F ;if it was 'mov ss,--'
850
jne da34 ;if it was not 'sti'
862
jmp dop_r1 ;if pure register reference
863
dop05: ;<--- used by OP_M, OP_M64, OP_M80
864
call showsize ;print out size in AH
865
dop06: ;<--- used by OP_MOFFS, OP_MXX, OP_MFLOAT, OP_MDOUBLE
866
or [preused],PRESEG ;needed even if there's no segment override
867
;because handling of LOCK prefix relies on it
868
test [preflags],PRESEG
869
jz @F ;if no segment override
870
call showseg ;print segment name
877
test [preflags], PRE32A
879
jmp dop18 ;if 32-bit addressing
881
or [disflags], DIS_I_SHOW ;we'd like to show this address
882
mov [addrr],0 ; zero out the address initially
884
xchg ax,bx ;mov bx,ax
896
test [preflags],PRESEG
897
jnz dop10 ;if segment override
898
dec [segmnt] ;default is now SS
905
mov [addrr],cx ;print it out, etc.
919
add [addrr],cx ; base+index ([BX+SI, .... )
922
test [ai.regmem], 0c0h
923
jz dop17 ;if no displacement
924
test [ai.regmem], 80h
925
jnz dop15 ;if word displacement
928
add [addrr],ax ; [base][+index]+byte
937
call hexbyte ;print the byte displacement
942
dop16: ;<--- pure 16bit offset
945
call hexword ;print word displacement
951
;--- 32-bit MOD REG R/M addressing.
955
jne @F ;if not just a disp32 address
956
;--- render "[xxxxxxxx]"
960
call disp32 ;get & display 32bit offset
961
jmp dop17 ;last the ']'
968
call disgetbyte ;get and save it
975
jz dop23 ;if no disp8
980
mov byte ptr [di],'-'
986
;--- for 32-bit, the disassembler displays offsets first;
987
;--- example: mov ax,00001000[ebx][edi]
990
;--- v2.50: put offset in square brackets: mov ax,[00001000][ebx][edi]
991
; call disp32 ;get and display 32bit offset
992
call dop18a ;get and display 32bit offset
998
jne showsqreg32 ;if no SIB
1000
if 1 ;bugfix: make 'u' correctly handle [ESP],[ESP+x]
1009
jne @F ;if not [EBP]
1010
test [ai.regmem], 0c0h
1012
call disp32 ;get and show 32-bit displacement instead of [EBP]
1016
call showsqreg32; render "[E®]"; al=reg
1024
je disbad1 ;if illegal
1026
call showsqreg32; render "[E®]; al=reg
1048
;--- Memory-only reference (OP_M)
1053
jae disbad1 ;if it's a register reference
1057
jmp disbad ;this is not supposed to happen
1059
;--- Register reference from MOD R/M part (OP_R_MOD)
1064
jb disbad1 ;if it's a memory reference
1067
;--- Memory offset reference (OP_MOFFS)
1070
call showsize ;print the size and save various things
1072
test [preflags], PRE32A
1073
jnz @F ;if 32-bit addressing
1077
jmp dop06 ;don't show size
1079
;--- Pure register reference (OP_R)
1083
dop_r1: ;<--- used by OP_RM, OP_R_MOD, OP_R_ADD, OP_AX
1084
and al,7 ;entry point for regs from MOD R/M, and others
1086
or [disflags],cl ;if it was variable size operand, the size
1087
;should now be marked as known.
1089
jl dop_reg ;if byte register
1090
jz dop_wordreg ;if word register
1091
cmp ah,20h ;qword register (mmx)?
1093
mov byte ptr [di],'E'
1096
add al,8 ; use the 16-bit names ( rgnam16 )
1100
xchg ax,bx ; mov bx,ax
1101
mov ax,[rgnam816+bx]; get the register name
1113
;--- Register number embedded in the instruction (OP_R_ADD)
1119
;--- AL or AX or EAX (OP_AX)
1125
;--- QWORD mem (OP_M64).
1126
;--- this operand type is used by:
1131
; mov ax,'Q' ;print 'Q' +'WORD'
1132
mov ah,20h ;size QWORD
1135
;--- FLOAT (=REAL4) mem (OP_MFLOAT).
1145
;--- DOUBLE (=REAL8) mem (OP_MDOUBLE).
1158
;--- TBYTE (=REAL10) mem (OP_M80).
1161
mov ax,0ff00h+'T' ;print 't' + 'byte'
1166
jae disbad5 ;if it's a register reference
1167
and [disflags],not DIS_F_SHOW ;don't show this
1170
;--- far memory (OP_FARMEM).
1171
;--- this is either a FAR16 (DWORD) or FAR32 (FWORD) pointer
1174
mov ax,'AF' ;store "FAR"
1191
and [disflags],not DIS_F_SHOW ;don't show this
1195
jae disbad5 ;if it's a register reference
1196
jmp dop06 ;don't show size
1201
;--- Check for ST(1) (OP_1CHK).
1204
pop ax ;discard return address
1208
je @F ;if it's ST(1)
1209
jmp da14 ;another operand (but no comma)
1211
jmp da21 ;end of list
1213
;--- store segment register name (OP_SEGREG).
1218
jae disbad ;if not a segment register
1221
and [disflags],not DIS_F_REPT ;clear flag: don't repeat
1224
jb @F ;if not FS or GS
1225
mov [ai.dismach],3 ;(no new 486-686 instructions involve seg regs)
1227
add al,8+8 ;segreg names are behind 8-bit/16-bit regnames
1228
jmp dop_reg ;go print it out
1230
;--- Sign-extended immediate byte (OP_IMMS8). "push xx"
1236
xchg ax,bx ;mov bl,al
1243
xchg ax,bx ;mov al,bl
1244
jmp dop59a ;call hexbyte and return
1246
;--- Immediate byte (OP_IMM8).
1251
jmp hexbyte ;call hexbyte and return
1253
;--- Set flag to always show size (OP_SHOSIZ).
1256
or [disflags],DIS_I_SHOWSIZ
1257
pop ax ;discard return address
1258
jmp da14 ;next operand
1262
;--- v2.50: return value in SI has changed
1263
;--- up to v2.50, si returned an offset for the oplists table ( + OPTYPES_BASE )
1264
;--- since v2.50, si returns just an index (for table opindex).
1269
mov esp,[run_sp] ;pop junk off stack
1271
mov sp,[run_sp] ;pop junk off stack
1273
mov ax,offset da13a ; the address where we "return" to
1276
mov word ptr [preflags],0 ;clear preflags and preused
1277
mov [rmsize],80h ;don't display any memory
1278
mov word ptr [ai.dismach],0 ;forget about the machine type
1279
and [disflags],not DIS_I_SHOW ;and flags
1281
mov di,offset prefixlist
1284
je @F ;if it's a named prefix
1285
dec [dis_n] ;reset cnt to 0 again
1286
mov bx,MN_DB ;offset of 'DB' mnemonic
1287
; mov si,OPLIST_26+OPTYPES_BASE;this says OP_IMM8
1288
mov si,26h ;v2.50: index 26h: this says OP_IMM8
1291
or [disflags],DIS_I_UNUSED ;print special flag
1294
cmp bx,6 ;the first 6 items are segment prefixes
1295
jb @F ;if SEG directive
1296
shl bx,1 ;prefix wait, lock, repe, repne
1297
mov bx,[prefixmnem+bx-6*2]
1298
; mov si,OPTYPES_BASE ;no operand
1299
xor si, si ;v2.50: index 0, first item, no operand
1302
;--- an unused segment prefix
1303
; lea si,[bx+OPLIST_40+OPTYPES_BASE] ;OPLIST_40 is OP_ES, size 2
1304
lea si,[bx+40h] ;v2.50: 40h is index for OP_ES
1313
;--- 8-bit relative jump (OP_REL8)
1314
;--- v2.50: correctly handle a 8-bit short jmp with a size prefix
1325
dop_rel16: ;16-bit distance ( also used for 8-bit short distances
1328
jmp hexword ;call hexword and return
1330
;--- 16/32-bit relative jump (OP_REL1632)
1331
;--- v2.50: a 16-bit relative call/jmp in 32-bit will clear hiword(eip)!
1332
;--- to make this evident, display a WORD only!
1337
jz dop_rel16 ;if not 32-bit distance
1340
dop_dispdwd: ; relative distance in ax:dx
1347
jmp hexword ;call hexword and return
1351
;--- Here are the routines for printing out the operands themselves.
1353
;--- CRx (OP_CR), DRx (OP_DR), TRx (OP_TR), MMx (OP_MMX)
1359
ja disbad4 ;if too large
1361
mov [ai.dismach],5 ;CR4 is new to the 586
1363
cmp [idxins],SPARSE_BASE+22h
1364
jne dop55 ;if not MOV CRx,xx
1366
jne dop55 ;if not CR1
1368
jmp disbad ;can't MOV CR1,xx
1375
mov cx,-1 ; no max or illegal value (remove?)
1390
jb disbad4 ;if too small
1393
mov [ai.dismach],4 ;TR3-5 are new to the 486
1410
xchg ax,bx ;mov bx,ax
1421
;--- far immediate (OP_FARIMM). Either FAR16 or FAR32
1428
jz @F ; if not 32-bit address
1432
call disgetword ; get segment part
1444
;--- Immediate data (OP_IMM)
1448
jl dop03 ;if just a byte
1450
test [disflags], DIS_I_SHOWSIZ
1451
jz @F ;if we don't need to show the size
1452
call showsize ;print size in AH
1453
sub di,4 ;erase "PTR "
1457
jz @F ;if just a word
1459
call disgetword ;print the high order word
1467
call disgetbyte ;print immediate byte
1472
;--- 32-bit addressing without SIB
1473
;--- store "[E®]" at DI
1481
mov ax, [rgnam16+bx]
1489
;--- for PUSH imm8 add D/W to opcode if size differs from default (WORD/DWORD)
1496
shr ah,2 ;40h -> 10h (=PRE32D)
1514
;--- DISCHK32D - Check for 32 bit operand size prefix (66h).
1517
or [preused], PRE32D
1518
test [preflags], PRE32D
1522
; GETREGMEM_R - Get the reg part of the reg/mem part of the instruction
1533
;--- GETREGMEM - Get the reg/mem part of the instruction
1536
test [preused],GOTREGM
1537
jnz @F ;if we have it already
1538
or [preused],GOTREGM
1539
call disgetbyte ;get the byte
1540
mov [ai.regmem],al ;save it away
1546
; DISP32 - Print 32-bit displacement for addressing modes.
1561
; SHOWSEG - Show the segment descriptor in SEGMNT
1562
; Entry DI Where to put it
1567
mov al,[segmnt] ;segment number
1570
xchg ax,bx ;mov bx,ax
1571
mov ax, [segrgnam+bx] ;get register name
1576
; SHOWOP Show the op code
1577
; Entry SI Null-terminated string containing the op mnemonic
1578
; Exit DI Address of next available byte in output line
1579
; (>= offset line_out + 32 due to padding)
1583
mov di,offset line_out+MNEMONOFS
1594
cmp di,offset line_out+MNEMONOFS+8
1599
; SHOWSIZE - Print a description of the size
1600
; Entry AH 10h=DWORD, 00h=WORD, F0h=BYTE, 20h=QWORD
1603
; SHOWPTR - Print " PTR"
1606
; SHOWDWD - Print "DWORD PTR"
1610
mov [rmsize],ah ;save r/m size
1611
mov [sizeloc],di;save where we're putting this
1616
jg showdwd ;if dword
1642
; DISGETBYTE - Get byte for disassembler.
1644
; Exit AL Next byte in instruction stream
1650
test [bCSAttr], CS32
1655
add si,[dis_n] ;index to the right byte
1660
inc [dis_n] ;indicate that we've gotten this byte
1666
lds esi,fword ptr [u_addr]
1667
add esi,dword ptr cs:[dis_n] ;index to the right byte
1677
; DISGETWORD - Get word for disassembler.
1685
test [bCSAttr], CS32
1690
add si,[dis_n] ;index to the right byte
1701
lds esi,fword ptr [u_addr]
1702
add esi,dword ptr cs:[dis_n] ;index to the right byte
1712
; DISSHOWBYTES - Show bytes for the disassembler.
1713
; Entry BX Number of bytes (must be > 0)
1714
; Exit u_addr updated
1719
test [bCSAttr], CS32
1735
lds esi,fword ptr [u_addr]
1742
mov dword ptr [u_addr],esi
1748
; MOVEOVER - Move the line to the right - disassembler subfunction.
1749
; used to insert prefixes - called by code in the "prefix loop" only.
1750
; Entry DI Last address + 1 of line so far
1751
; Exit CX Number of bytes to move
1757
je @F ;if sizeloc not saved
1763
sub cx,offset line_out+MNEMONOFS
1774
; TAB_TO - Space fill until reaching the column indicated by AX.
1775
; (Print a new line if necessary.)
1780
ja @F ;if there's room on this line
1782
mov di,offset line_out
1787
rep stosb ;space fill to the right end