2
;--- A command - tiny assembler.
5
;--- 1. fix regression since v1.09: cmp [x], yy assumes word operand if no size given
6
;--- 2. MS debug accepts call near/far [x], Debug rejects near [x], accepts far [x]
7
;--- 3. MS debug accepts call near/far x (adding current cs as seg if far), Debug rejects both
9
;--- macros for asmtbl.inc
11
;--- mne macro, used for the assembler mnemonics table
13
mne macro val2:REQ, dbytes:VARARG
21
MN_&val2 equ $ - mnlist
22
tmpstr catstr <!">,@SubStr(val2,1,@SizeStr(val2)-1),<!",!'>,@SubStr(val2,@SizeStr(val2)),<!'>,<+80h>
26
;--- AGRP: num is the index into agroups, that finally defines the opcode (1 or 2 byte).
27
;--- rfld, bits 0-2 of the final value, define bits 3-5 in ai.regmem.
30
exitm <240h + num*8 + rfld>
33
variant macro opcode:req, key:req, lockb, machine
41
ainfo = (opcode) * ASMMOD + key
42
db HIGH ainfo, LOW ainfo
46
fpvariant macro opcode, key, addb, lockb, machine
47
variant opcode, key, lockb, machine
59
;--- opl macro, used to define operand list types
60
;--- the macro defines an EQUate, OPLIST_XX, which
61
;--- is refered to by array opindex.
62
;--- v2.50: "terminating" 0 no longer required.
64
opl macro index, value:VARARG
65
OPLIST_&index equ $ - oplists
71
;--- flags for instruction operands.
74
OP_ALL equ 40h ;byte/word/dword operand (could be 30h but ...)
75
OP_1632 equ 50h ;word or dword operand
76
OP_8 equ 60h ;byte operand
77
OP_16 equ 70h ;word operand
78
OP_32 equ 80h ;dword operand
79
OP_64 equ 90h ;qword operand
81
OP_SIZE equ OP_ALL ;the lowest of these
83
;--- These operand types need to be combined with a size flag..
84
;--- order must match items in asm_jmp1, bittab and dis_jmp1
86
OP_IMM equ 0 ;immediate
88
OP_M equ 4 ;mem (but not reg)
89
OP_R_MOD equ 6 ;register, determined from MOD R/M part
90
OP_MOFFS equ 8 ;memory offset; e.g., [1234]
91
OP_R equ 10 ;reg part of reg/mem byte
92
OP_R_ADD equ 12 ;register, determined from instruction byte
93
OP_AX equ 14 ;al or ax or eax
95
;--- These don't need a size.
96
;--- order must match items in asm_jmp1, bittab and dis_optab.
97
;--- additionally, order of OP_M64 - OP_FARMEM is used
98
;--- in table asm_siznum
99
;--- v2.50: value 0 was used to terminate an operand list ( macro opl )
102
OP_M64 equ 2 ; 0 qword memory (obsolete?)
103
OP_MFLOAT equ 4 ; 1 float memory
104
OP_MDOUBLE equ 6 ; 2 double-precision floating memory
105
OP_M80 equ 8 ; 3 tbyte memory
106
OP_MXX equ 10 ; 4 memory (size unknown)
107
OP_FARMEM equ 12 ; 5 memory far16/far32 pointer
108
OP_FARIMM equ 14 ; 6 far16/far32 immediate
109
OP_REL8 equ 16 ; 7 byte address relative to IP
110
OP_REL1632 equ 18 ; 8 word or dword address relative to IP
111
OP_1CHK equ 20 ; 9 check for ST(1)
112
OP_STI equ 22 ;10 ST(I)
116
OP_SEGREG equ 30 ;14 segment register
117
OP_IMMS8 equ 32 ;15 sign extended immediate byte
118
OP_IMM8 equ 34 ;16 immediate byte (other args may be (d)word)
120
OP_SHOSIZ equ 38 ;18 set flag to always show the size
122
OP_1 equ 40 ;19 1 (simple "string" ops from here on)
126
OP_ST equ 48 ;23 ST (top of coprocessor stack)
134
OP_STR equ OP_1 ;first "string" op
138
;--- Instructions that have an implicit operand subject to a segment override
139
;--- (outsb/w, movsb/w, cmpsb/w, lodsb/w, xlat).
140
;--- also used by disassembler
142
prfxtab db 06eh,06fh, 0a4h,0a5h, 0a6h,0a7h, 0ach,0adh, 0d7h
143
N_PRFXTAB equ $ - prfxtab
145
;--- Instructions that can be used with REP/REPE/REPNE.
146
;--- also used by disassembler
148
replist db 06ch,06eh,0a4h,0aah,0ach ;REP (INSB, OUTSB, MOVSB, STOSB, LODSB)
149
N_REPNC equ $ - replist
150
db 0a6h,0aeh ;REPE/REPNE (CMPSB, SCASB)
151
N_REPALL equ $ - replist
155
;--- opindex array - help array to access operand list items (oplists);
156
;--- needed because the operand list items differ in size.
163
% db OPLIST_0&@CatStr(%opidx)
165
% db OPLIST_&@CatStr(%opidx)
170
db offset agroups - offset oplists ; size of oplists table, required to find end of last operand list
176
asm_mn_flags db 0 ;flags for the mnemonic
178
AMF_D32 equ 1 ;32bit opcode/data operand
180
AMF_A32 equ 4 ;address operand is 32bit
181
AMF_SIB equ 8 ;there's a SIB in the arguments
182
AMF_MSEG equ 10h ;if a seg prefix was given b4 mnemonic
183
AMF_FSGS equ 20h ;if FS or GS was encountered
185
AMF_D16 equ 40h ;16bit opcode/data operand
186
AMF_ADDR equ 80h ;address operand is given
188
bEndOplItem db 0 ;v2.50
190
;--- aa_saved_prefix and aa_seg_pre must be consecutive.
191
aa_saved_prefix db 0 ;WAIT or REP... prefix
192
aa_seg_pre db 0 ;segment prefix
194
mneminfo dw 0 ;address associated with the mnemonic
195
a_opcode dw 0 ;op code info for this variant
196
a_opcode2 dw 0 ;copy of a_opcode for obs-instruction
199
DM_COPR equ 1 ;math coprocessor
200
DM_MMX equ 2 ;MMX extensions
203
VAR_LOCKABLE equ 1 ;variant is lockable
204
VAR_MODRM equ 2 ;if there's a MOD R/M here
205
VAR_SIZ_GIVN equ 4 ;if a size was given
206
VAR_SIZ_FORCD equ 8 ;if only one size is permitted
207
VAR_SIZ_NEED equ 10h ;if we need the size
208
VAR_D16 equ 20h ;if operand size is WORD
209
VAR_D32 equ 40h ;if operand size is DWORD
212
rmaddr dw ? ;address of operand giving the R/M byte (asm only)
213
;--- regmem and sibbyte must be consecutive
214
regmem db ? ;mod reg r/m part of instruction
215
sibbyte db ? ;SIB byte
216
immaddr dw ? ;address of operand giving the immed stf (asm only)
217
xxaddr dw ? ;address of additional stuff (asm only)
218
;--- dismach and dmflags must be consecutive
219
dismach db ? ;type of processor needed
220
dmflags db ? ;flags for extra processor features
221
opcode_or db ? ;extra bits in the op code (asm only)
222
opsize db ? ;size of this operation (2 or 4) (asm only)
223
varflags db ? ;flags for this variant (asm only)
224
reqsize db ? ;size that this arg should be (asm only)
227
ai AINSTR <?> ; used by assembler and disassembler
233
;--- search for "obsolete" instructions
237
;--- 124: MOV TRx, reg
238
;--- 126: MOV reg, TRx
240
a_obstab dw 0dbe0h,0dbe1h,0dbe4h,124h,126h ;obs. instruction codes
241
obsmach db 1,1,2,4,4 ;max permissible machine for the above
243
modrmtab db 11,0,13,0,15,0,14,0 ;[bx], [bp], [di], [si]
244
db 15,13,14,13,15,11,14,11 ;[bp+di],[bp+si],[bx+di],[bx+si]
248
;--- Equates for parsed arguments, stored in OPRND.flags
250
ARG_DEREF equ 1 ;non-immediate memory reference
251
ARG_MODRM equ 2 ;if we've computed the MOD R/M byte
252
ARG_JUSTREG equ 4 ;a solo register
253
ARG_WEIRDREG equ 8 ;if it's a segment register or CR, etc.
254
ARG_IMMED equ 10h ;if it's just a number
255
ARG_FARADDR equ 20h ;if it's of the form xxxx:yyyyyyyy
257
;--- For each operand type in the following table, the first byte is
258
;--- the bits, at least one of which must be present; the second is the
259
;--- bits all of which must be absent.
260
;--- the items in bittab must be ordered similiar to asm_jmp1 and dis_jmp1.
263
db ARG_IMMED ;+0 OP_IMM
264
db ARG_DEREF+ARG_JUSTREG;+1 OP_RM
265
db ARG_DEREF ;+2 OP_M
266
db ARG_JUSTREG ;+3 OP_R_MOD
267
db ARG_DEREF ;+4 OP_MOFFS
268
db ARG_JUSTREG ;+5 OP_R
269
db ARG_JUSTREG ;+6 OP_R_ADD
270
db ARG_JUSTREG ;+7 OP_AX
272
db ARG_DEREF ; 0 OP_M64
273
db ARG_DEREF ; 1 OP_MFLOAT
274
db ARG_DEREF ; 2 OP_MDOUBLE
275
db ARG_DEREF ; 3 OP_M80
276
db ARG_DEREF ; 4 OP_MXX
277
db ARG_DEREF ; 5 OP_FARMEM
278
db ARG_FARADDR ; 6 OP_FARIMM
279
db ARG_IMMED ; 7 OP_REL8
280
db ARG_IMMED ; 8 OP_REL1632
281
db ARG_WEIRDREG ; 9 OP_1CHK
282
db ARG_WEIRDREG ;10 OP_STI
283
db ARG_WEIRDREG ;11 OP_CR
284
db ARG_WEIRDREG ;12 OP_DR
285
db ARG_WEIRDREG ;13 OP_TR
286
db ARG_WEIRDREG ;14 OP_SEGREG
287
db ARG_IMMED ;15 OP_IMMS8
288
db ARG_IMMED ;16 OP_IMM8
289
db ARG_WEIRDREG ;17 OP_MMX
290
db 0ffh ;18 OP_SHOSIZ
294
db ARG_JUSTREG ;OP_DX
295
db ARG_JUSTREG ;OP_CL
296
db ARG_WEIRDREG ;OP_ST
297
db ARG_WEIRDREG ;OP_CS
298
db ARG_WEIRDREG ;OP_DS
299
db ARG_WEIRDREG ;OP_ES
300
db ARG_WEIRDREG ;OP_FS
301
db ARG_WEIRDREG ;OP_GS
302
db ARG_WEIRDREG ;OP_SS
304
;--- special ops DX, CL, ST, CS, DS, ES, FS, GS, SS
305
;--- entry required if ao48 is set
306
;--- order of entries matches the last 9 ones in dis_optab
309
db REG_DX, REG_CL, REG_ST, REG_CS, REG_DS, REG_ES, REG_FS, REG_GS, REG_SS
317
;--- 6 FL=FLOAT ptr (REAL4)
318
;--- 7 DO=DOUBLE ptr (REAL8)
319
;--- 8 TB=TBYTE ptr (REAL10)
338
sizetcnam db 'BY','WO','WO','DW','QW','FL','DO','TB','SH','LO','NE','FA'
340
;--- sizes for OP_M64, OP_MFLOAT, OP_MDOUBLE, OP_M80, OP_MXX, OP_FARMEM
342
asm_siznum db SIZ_QWORD, SIZ_FLOAT, SIZ_DOUBLE, SIZ_TBYTE
343
db -1, SIZ_FAR ;-1 = none
347
;--- write byte in AL to BX/[E]DX, then increment [E]DX
356
;--- write CX bytes from DS:SI to BX:[E]DX
369
mov [errret],offset aa01
371
je aa01x ;if end of line
372
@movs bx,[regs.rCS] ;default segment to use
374
call getaddr ;get address into bx:(e)dx
375
call chkeol ;expect end of line here
376
sizeprfX ;mov [a_addr+0],edx
377
mov [a_addr+0],dx ;save the address
385
;--- v2.0: def seg for a is no longer automatically converted
386
;--- when pm is entered.
388
test [bFlagsPM], 1 ; default for a-cmd already set?
390
@movs ax, [regs.rCS]; use current CS:IP as default
392
sizeprfX ; mov eax, [regs.IP]
394
sizeprfX ; mov [a_addr+0], eax
400
;--- Begin loop over input lines.
406
@dprintf "aa01: a_addr=%X:%lX", word ptr [a_addr+4], dword ptr [a_addr+0]
409
mov esp,[top_sp] ;restore the stack (this implies no "ret")
411
mov sp,[top_sp] ;restore the stack (this implies no "ret")
413
mov di,offset line_out
423
sizeprfX ;mov eax,[a_addr+0]
433
mov word ptr [aa_saved_prefix],0 ;clear aa_saved_prefix and aa_seg_pre
435
;--- Get mnemonic and look it up.
438
mov di,offset line_out ;return here after LOCK/REP/SEG prefix
439
push si ;save position of mnemonic
442
jb @F ;if not lower case letter
445
and al,TOUPPER ;convert to upper case
450
je @F ;if end of mnemonic
460
or byte ptr [di-1],80h ;set highest bit of last char of mnemonic
461
call skipwh0 ;skip to next field
463
push si ;save position in input line
467
;--- now search mnemonic in list
470
aa06: ;<--- next mnemonic
472
add si,2 ;skip the 'asmtab' offset
475
lodsb ;skip to end of string
477
jns @B ;if not end of string
480
sub cx,si ;size of opcode in mnlist
481
mov di,offset line_out
485
cmp si,offset end_mnlist
486
jc aa06 ;next mnemonic
487
pop si ;skip position in input line
489
pop si ;skip position of mnemonic
491
jmp cmd_error ;complain
493
jmp cmdloop ;done with this command
495
;--- We found the mnemonic.
498
mov si,[bx] ;get the offset into asmtab
501
; Now si points to the spot in asmtab corresponding to this mnemonic.
502
; The format of the assembler table is as follows.
503
; First, there is optionally one of the following bytes:
507
; ASM_WAIT the mnemonic should start with a wait
509
; ASM_D32 This is a 32 bit instruction variant.
510
; ASM_D16 This is a 16 bit instruction variant.
511
; ASM_AAX Special for AAM and AAD instructions:
512
; put 0ah in for a default operand.
513
; ASM_SEG This is a segment prefix.
514
; ASM_LOCKREP This is a LOCK or REP... prefix.
516
; Then, in most cases, this is followed by one or more of the following
517
; sequences, indicating an instruction variant.
518
; ASM_LOCKABLE (optional) indicates that this instruction can
519
; follow a LOCK prefix.
520
; ASM_MACHx (optional) indicates the first machine on which this
521
; instruction appeared.
522
; [word] This is a 16-bit integer, most significant byte
523
; first, giving ASMMOD * a + b, where b is an
524
; index into the array opindex (indicating the
525
; key, or type of operand list), and a is as
527
; 0-255 The (one-byte) instruction.
528
; 256-511 The lower 8 bits give the second byte of
529
; a two-byte instruction beginning with 0fh.
530
; 512-575 Bits 2-0 say which floating point instruction
531
; this is (0d8h-0dfh), and 5-3 give the /r
533
; 576-... (a-576)/8 is the index in the array agroups
534
; (which gives the real value of a), and the
535
; low-order 3 bits gives the /r field.
537
; [byte] This gives the second byte of a floating
538
; instruction if 0d8h <= a <= 0dfh.
540
; Following these is an ASM_END byte.
543
; ASM_SEG and ASM_LOCKREP are followed by just one byte, the
545
; ASM_DB, ASM_DW, and ASM_DD don't need to be followed by
568
cmp byte ptr [si],ASM_LOCKREP ;check for mnemonic flag byte
570
lodsb ;get the prefix
571
sub al,ASM_LOCKREP ;convert to 0-9
572
je aa18 ;if LOCK or REP...
575
jz aa17 ;if segment prefix (ASM_SEG)
577
jz aa16 ;if aad or aam (ASM_AAX)
579
jz aa15_1 ;if ASM_D16
581
jae aa20 ;if ASM_ORG or ASM_DD or ASM_DW or ASM_DB
582
or [asm_mn_flags],al ;save AMF_D32 or AMF_WAIT (1 or 2)
584
jmp ab01 ;now process the arguments
586
or [asm_mn_flags],AMF_D16
587
inc si ;skip the ASM_D32 byte
588
jmp ab01 ;now process the arguments
596
lodsb ;get prefix value
599
or [asm_mn_flags],AMF_MSEG
600
pop si ;get position in input line
611
mov di,offset line_out
614
jmp aa27 ;back for more
616
;--- LOCK or REP prefix
619
lodsb ;get prefix value
620
xchg al,[aa_saved_prefix]
622
jnz aa13a ;if there already was a saved prefix
627
je @F ;if end of line
629
je @F ;if end of line (comment)
630
jmp aa02 ;back for more
632
mov al,[aa_saved_prefix] ;just a prefix, nothing else
633
mov di,offset line_out
637
;--- Pseudo ops (org or db/dw/dd).
640
cmp word ptr [aa_saved_prefix],0
641
jnz aa13a ;if there was a prefix or a segment: error
642
pop si ;get position in input line
643
sub al,3 ;AX=0 if org, 1 if dd, 2 if dw, 3 if db.
644
jnz aa20m ;if not ORG
646
;--- Process ORG pseudo op.
651
mov bx,[a_addr+4] ;default segment
654
jmp aa01 ;get next line
656
;--- Data instructions (DB/DW/DD).
659
mov di,offset line_out ;put the bytes here when we get them
660
xchg ax,bx ;mov bx,ax
662
mov bp,[bx+aadbsto-2] ;get address of storage routine
665
je aa27 ;if end of line
672
call aageti ;get a numerical value into dx:bx, size into cl
673
cmp cl,cs:[bp-1] ;compare with size
676
call bp ;store value in AL/AX/DX:AX
677
cmp di,offset real_end
678
ja aa24 ;if output line overflow
680
jmp aa26 ;done with this one
687
je aa24 ;if end of line
689
je aa25 ;if end of string
691
cmp di,offset real_end
692
jbe aa23 ;if output line not overflowing
700
jne aa21 ;if not end of line
702
;--- End of line. Copy it to debuggee's memory
705
mov si,offset line_out
707
sizeprfX ;mov edx, [a_addr+0]
712
sizeprfX ;mov [a_addr+0],edx
717
;--- table for routine to store a number ( index dd=1,dw=2,db=3 )
718
aadbsto dw sto_dd,sto_dw,sto_db
721
;--- Routines to store a byte/word/dword.
725
stosw ;store a dword value
732
stosw ;store a word value
736
stosb ;store a byte value
739
; Here we process the AAD and AAM instructions. They are special
740
; in that they may take a one-byte argument, or none (in which case
741
; the argument defaults to 0ah = ten).
744
mov [mneminfo],si ;save this address
748
je ab00a ;if end of line
750
jne ab01b ;if not end of line
752
mov si,offset aam_args ;fake a 0ah argument
755
;--- Process normal instructions.
757
; First we parse each argument into a 12-byte data block (OPRND), stored
758
; consecutively at line_out, line_out+12, etc.
759
; This is stored in an OPRND struct:
761
; [di+2]: Size argument, if any (1=byte, 2=word, 3=(unused), 4=dword,
762
; 5=qword, 6=float, 7=double, 8=tbyte, 9=short, 10=long, 11=near,
763
; 12=far), see SIZ_xxx and sizetcnam
764
; [di+3] Size of MOD R/M displacement
765
; [di+4] First register, or MOD R/M byte, or num of additional bytes
766
; [di+5] Second register or index register or SIB byte
768
; [di+7] Sizes of numbers are or-ed here
769
; [di+8] (dword) number
771
; For arguments of the form xxxx:yyyyyyyy, xxxx is stored in <num2>,
772
; and yyyyyyyy in <num>. The number of bytes in yyyyyyyy is stored in
773
; opaddr, 2 is stored in <numadd>, and di is stored in xxaddr.
776
flags db ? ;+0 ARG_xxx Flags (ARG_DEREF, etc.)
779
sizedis db ? ;+3 Size of MOD R/M displacement
781
reg1 db ? ;+4 First register, or MOD R/M byte
782
numadd db ? ;+4 (additional bytes, stored at num2 (up to 4)
786
reg2 db ? ;+5 Second register or index register or SIB byte
787
index db ? ;+6 Index factor
796
mov [mneminfo],si ;save this address
797
pop si ;get position in line
801
mov di,offset line_out
803
;--- Begin loop over operands.
805
ab02: ;<--- next operand
807
je ab03 ;if end of line
809
jne ab04 ;if not end of line
811
jmp ab99 ;to next phase
814
push di ;clear out the current OPRND storage area
815
mov cx,sizeof OPRND / 2
820
;--- Small loop over "BYTE PTR" and segment prefixes.
826
cmp [di].OPRND.sizearg,SIZ_NONE
827
jne ab07 ;if already have a size qualifier ("BYTE PTR",...)
829
mov di,offset sizetcnam
830
mov cx,sizeof sizetcnam / 2
833
jne ab07 ;if not found
839
jne ab09 ;if not 'FAR' (could be hexadecimal)
841
sub cl,sizeof sizetcnam / 2
842
neg cl ;convert to 1, ..., 12
843
mov [di].OPRND.sizearg,cl
844
call skipalpha ;go to next token
848
jne ab05 ;if not 'PTR'
849
call skipalpha ;go to next token
854
jne ab09 ;if we already have a segment prefix
856
mov di,offset segrgnam
860
jne ab09 ;if not found
861
push si ;save si in case there's no colon
865
jne ab08 ;if not followed by ':'
866
pop ax ;discard saved si
867
call skipwhite ;skip it
868
mov bx,offset prefixlist + 5
870
mov al,[bx] ;look up the prefix byte
871
mov [aa_seg_pre],al ;save it away
876
;--- Begin parsing main part of argument.
878
;--- first check registers
881
push di ;check for solo registers
882
mov di,offset rgnam816
883
mov cx,N_ALLREGS;8+16bit regs, segment regs, special regs
886
jc ab14 ;if not a register
887
or [di].OPRND.flags, ARG_JUSTREG
888
mov [di].OPRND.reg1,bl ;save register number
889
cmp bl,24 ;0-23 = AL-DH, AX-DI, EAX-EDI (REG_NO_GPR)
890
jae @F ;if it's not a normal register
891
xchg ax,bx ;mov al,bl
893
shr al,cl ;al = size: 0 -> byte, 1 -> word, 2 -> dword
895
adc al,3 ;convert to 1, 2, 4 (respectively)
898
xor [di].OPRND.flags, ARG_JUSTREG + ARG_WEIRDREG
899
mov al,SIZ_WORD ;register size
901
ja ab11 ;if it's MM, CR, DR or TR
903
cmp bl,28 ;24-27 are ES,CS,SS,DS (segrgnam)
904
jb ab13 ;if it's a normal segment register
905
or [asm_mn_flags],AMF_FSGS ;flag it
908
cmp byte ptr [si],'('
909
jne ab12 ;if just plain ST
915
mov [di].OPRND.reg2,al ;save the number
918
je ab12 ;if not error
922
;--- other registers 31-34 (MM, CR, DR, TR)
929
mov [di].OPRND.reg2,al ;save the number
930
mov al,SIZ_DWORD;register size
932
jne ab13 ;if not MM register
933
or [di].OPRND.flags, ARG_JUSTREG
937
mov al,0 ;size for ST regs
939
cmp al,[di].OPRND.sizearg ;compare with stated size
941
xchg al,[di].OPRND.sizearg
943
jne ab10 ;if wrong size given - error
945
jmp ab44 ;done with this operand
947
;--- It's not a register reference. Try for a number.
952
jc ab17 ;it's not a number
953
call aageti ;get the number
954
mov [di].OPRND.orednum,cl
955
mov word ptr [di].OPRND.num+0,bx
956
mov word ptr [di].OPRND.num+2,dx
959
jg ab17 ;if we can't have a colon here
961
jne ab17 ;if not xxxx:yyyy
962
if 1 ;v2.50: size for ssss:oooo must be none or far
963
cmp [di].OPRND.sizearg, SIZ_NONE
965
cmp [di].OPRND.sizearg, SIZ_FAR
971
mov cx,word ptr [di].OPRND.num+0
972
mov [di].OPRND.num2,cx
973
mov word ptr [di].OPRND.num+0,bx
974
mov word ptr [di].OPRND.num+2,dx
975
or [di].OPRND.flags, ARG_FARADDR
976
jmp ab43 ;done with this operand
981
jmp ab30 ;do post-processing
986
cmp al,'[' ;begin loop over sets of []
988
or [di].OPRND.flags, ARG_DEREF ;set the flag
992
cmp al,']' ;begin loop within []
995
;--- Check for a register (within []).
999
mov di,offset rgnam16
1003
jc ab25 ;if not a register
1005
jae @F ;if 32-bit register
1006
add bl,8 ;adjust 0..7 to 8..15
1009
cmp [di].OPRND.reg2, 0
1010
jnz ab21 ;if we already have an index
1014
jne ab21 ;if not followed by '*'
1016
mov [di].OPRND.reg2,bl ;save index register
1020
jmp ab28 ;ready for next part
1023
cmp [di].OPRND.reg1,0
1024
jne @F ;if there's already a register
1025
mov [di].OPRND.reg1,bl
1028
cmp [di].OPRND.reg2, 0
1029
jne ab24 ;if too many registers
1030
mov [di].OPRND.reg2,bl
1033
jmp ab28 ;ready for next part
1037
;--- Try for a number (within []).
1042
call aageti ;get a number (or flag an error)
1045
je ab27 ;if it's an index factor
1046
or [di].OPRND.orednum,cl
1047
add word ptr [di].OPRND.num+0,bx
1048
adc word ptr [di].OPRND.num+2,dx
1049
jmp ab28 ;next part ...
1056
mov di,offset rgnam16
1061
cmp [di].OPRND.reg2, 0
1062
jne ab24 ;if there is already a register
1063
mov [di].OPRND.reg2, bl
1066
;--- Ready for the next term within [].
1070
je ab26 ;if a (negative) number is next
1072
jne @F ;if no next term (presumably)
1075
jmp ab19 ;back for more
1077
;--- Post-processing for complicated arguments.
1080
cmp word ptr [di].OPRND.reg1,0 ;check both reg1+reg2
1081
jnz ab32 ;if registers were given ( ==> create MOD R/M)
1082
cmp [di].OPRND.orednum,0
1083
jz ab31 ;if nothing was given ( ==> error)
1084
cmp [di].OPRND.flags,0
1085
jnz ab30b ;if it was not immediate
1086
or [di].OPRND.flags,ARG_IMMED
1088
jmp ab43 ;done with this argument
1090
or [asm_mn_flags],AMF_ADDR
1091
mov al,2 ;size of the displacement
1092
test [di].OPRND.orednum,4
1093
jz @F ;if not 32-bit displacement
1096
or [asm_mn_flags],AMF_A32 ;32-bit addressing
1098
mov [di].OPRND.sizedis,al ;save displacement size
1099
jmp ab30a ;done with this argument
1101
jmp aa13b ;flag an error
1103
; Create the MOD R/M byte.
1104
; (For disp-only or register, this will be done later as needed.)
1107
or [di].OPRND.flags, ARG_MODRM
1108
mov al,[di].OPRND.reg1
1109
or al,[di].OPRND.reg2
1111
jnz ab34 ;if 32-bit addressing
1112
test [di].OPRND.orednum,4
1113
jnz ab34 ;if 32-bit addressing
1114
; or [asm_mn_flags], AMF_ADDR | AMF_A32
1115
or [asm_mn_flags], AMF_ADDR
1116
mov ax,word ptr [di].OPRND.reg1 ;get reg1+reg2
1118
ja @F ;make sure al >= ah
1122
mov di,offset modrmtab
1126
jne ab31 ;if not among the possibilities
1127
mov bx,206h ;max disp = 2 bytes; 6 ==> (non-existent) [bp]
1128
jmp ab39 ;done (just about)
1130
;--- 32-bit addressing
1133
or [asm_mn_flags],AMF_A32 + AMF_ADDR
1134
mov al,[di].OPRND.reg1
1135
or al,[di].OPRND.index
1136
jnz @F ;if we can't optimize [EXX*1] to [EXX]
1137
mov ax,word ptr [di].OPRND.reg1 ;get reg1+reg2
1139
mov word ptr [di].OPRND.reg1,ax
1141
mov bx,405h ;max disp = 4 bytes; 5 ==> (non-existent) [bp]
1142
cmp [di].OPRND.reg2,0
1143
jne @F ;if there's a SIB
1144
mov cl,[di].OPRND.reg1
1146
jl ab31 ;if wrong register type
1148
cmp cl,4 ;check for ESP
1149
jne ab39 ;if not, then we're done (otherwise do SIB)
1151
or [asm_mn_flags],AMF_SIB ;form SIB
1152
mov ch,[di].OPRND.index ;get SS bits
1154
shl ch,cl ;shift them halfway into place
1155
mov al,[di].OPRND.reg2 ;index register
1157
je ab31 ;if ESP ( ==> error)
1160
mov al,20 ;set it for index byte 4
1163
jl ab31 ;if wrong register type
1165
or ch,al ;put it into the SIB
1166
shl ch,cl ;shift it into place
1167
inc cx ;R/M for SIB = 4
1168
mov al,[di].OPRND.reg1 ;now get the low 3 bits
1170
jne @F ;if there was a first register
1172
jmp ab42 ;MOD = 0, disp is 4 bytes
1175
jl ab45 ;if wrong register type
1176
and al,7 ;first register
1177
or ch,al ;put it into the SIB
1179
je ab40 ;if it's EBP, then we don't recognize disp=0
1180
;otherwise bl will be set to 0
1182
;--- Find the size of the displacement.
1186
je ab40 ;if it's [(E)BP], then disp=0 is still 1 byte
1187
mov bl,0 ;allow 0-byte disp
1191
mov al,byte ptr [di].OPRND.num+0
1195
mov ah,byte ptr [di].OPRND.num+1
1197
jne @F ;if it's bigger than 1 byte
1198
cmp ax,word ptr [di].OPRND.num+2
1200
mov bh,0 ;no displacement
1201
or bl,byte ptr [di].OPRND.num+0
1202
jz ab42 ;if disp = 0 and it's not (E)BP
1203
inc bh ;disp = 1 byte
1204
or cl,40h ;set MOD = 1
1207
or cl,80h ;set MOD = 2
1209
mov [di].OPRND.sizedis,bh ;store displacement size
1210
mov word ptr [di].OPRND.reg1, cx ;store MOD R/M and maybe SIB
1212
;--- Finish up with the operand.
1220
je ab99 ;if end of line
1222
je ab99 ;if comment (ditto)
1224
jne ab45 ;if not comma ( ==> error)
1225
cmp di,offset line_out+ 3 * sizeof OPRND
1226
jae ab45 ;if too many operands
1231
jmp aa13b ;error jump
1234
mov [di].OPRND.flags,-1;end of parsing phase
1235
push si ;save the location of the end of the string
1237
; For the next phase, we match the parsed arguments with the set of
1238
; permissible argument lists for the opcode. The first match wins.
1239
; Therefore the argument lists should be ordered such that the
1240
; cheaper ones come first.
1242
; There is a tricky issue regarding sizes of memory references.
1243
; Here are the rules:
1244
; 1. If a memory reference is given with a size, then it's OK.
1245
; 2. If a memory reference is given without a size, but some
1246
; other argument is a register (which implies a size),
1247
; then the memory reference inherits that size.
1248
; Exceptions: OP_CL does not imply a size
1250
; 3. If 1 and 2 do not apply, but this is the last possible argument
1251
; list, and if the argument list requires a particular size, then
1253
; 4. In all other cases, flag an error.
1255
ac01: ;<--- next possible argument list
1260
mov si,[mneminfo] ;address of the argument variant
1262
;--- Sort out initial bytes. At this point:
1263
;--- si = address of argument variant
1265
ac02: ;<--- next byte of argument variant
1268
jb ac05 ;if no more special bytes
1269
cmp al,ASM_LOCKABLE - ASM_MACH0
1270
je @F ;if ASM_LOCKABLE
1271
ja ac04 ;if ASM_END ( ==> error)
1272
mov [ai.dismach],al;save machine type
1273
jmp ac02 ;back for next byte
1275
or [ai.varflags],VAR_LOCKABLE
1276
jmp ac02 ;back for next byte
1281
;--- Get and unpack the word.
1286
xchg al,ah ;put into little-endian order
1289
div bx ;ax = a_opcode; dx = index into opindex
1290
mov [a_opcode],ax ;save ax
1291
mov [a_opcode2],ax ;save the second copy
1293
ja @F ;if not coprocessor instruction
1296
or [ai.dmflags],DM_COPR;flag it as an x87 instruction
1297
mov ah,al ;ah = low order byte of opcode
1298
lodsb ;get extra byte
1299
mov [ai.regmem],al ;save it in regmem
1300
mov [a_opcode2],ax ;save this for obsolete-instruction detection
1301
or [ai.varflags],VAR_MODRM ;flag its presence
1303
mov [mneminfo],si ;save si back again
1305
@dprintf "ac05: opindex=%X", si
1306
mov ax,word ptr [opindex+si]
1308
mov [bEndOplItem], ah ; end of oplist item
1310
lea si,[oplists+bx] ;si = the address of our operand list
1311
mov di,offset line_out ;di = array of OPRNDs
1313
;--- Begin loop over operands.
1315
ac06: ;<--- next operand
1317
sub ax, offset oplists
1318
cmp al, [bEndOplItem]
1320
lodsb ;get next operand byte
1322
; je ac10 ;if end of list
1323
cmp [di].OPRND.flags,-1
1324
je ac01 ;if too few operands were given
1326
jb @F ;if no size needed
1329
; shl ax,cl ;move bits 4-7 (size) to ah (OP_1632=5,OP_8=6,OP_16=7,...)
1330
; shr al,cl ;move bits 0-3 back
1331
db 0d4h,10h ;=aam 10h (AX=00XY -> AX=0X0Y)
1332
mov [ai.reqsize],ah ;save size away
1333
@dprintf "ac08: di=%X size requested, AH in AX=%X", di, ax
1335
@@: ;AL = OP_M64 - ...
1336
add al,ASM_OPOFF - OP_M64 ;adjust for the start entries im asm_jmp1
1339
xchg ax,bx ;now bx contains the offset
1340
mov cx,[asm_jmp1+bx] ;subroutine address
1343
@dprintf "ac08: di=%X si=%X, offset=%X, func=%X, al=%X", di, si, bx, cx, ax
1344
test al,[di].OPRND.flags
1345
jz ac09 ;if no required bits are present
1346
call cx ;call its specific routine
1347
cmp word ptr [si-1], (OP_1632 + OP_R) * 256 + (OP_1632 + OP_R_MOD)
1348
je ac06 ;(hack) for IMUL instruction
1349
add di,sizeof OPRND ;next operand
1350
jmp ac06 ;back for more
1353
jmp ac01 ;back to next possibility
1355
;--- End of operand list.
1358
cmp [di].OPRND.flags,-1
1359
jne ac09 ;if too many operands were given
1361
;--- Final check on sizes
1363
mov al,[ai.varflags]
1364
test al,VAR_SIZ_NEED
1365
jz ac12 ;if no size needed
1366
test al,VAR_SIZ_GIVN
1367
jnz ac12 ;if a size was given
1368
test al,VAR_SIZ_FORCD
1369
jz ac09 ;if the size was not forced ( ==> reject)
1371
cmp byte ptr [si],ASM_END
1372
je ac12 ;if this is the last one
1374
jmp aa13a ;it was not ==> error (not a retry)
1376
;--- Check other prefixes.
1379
mov al,[aa_saved_prefix]
1381
jz ac14 ;if no saved prefixes to check
1383
jne @F ;if it's a rep prefix
1384
test [ai.varflags],VAR_LOCKABLE
1385
jz ac11 ;if this variant is not lockable - error
1388
mov ax,[a_opcode] ;check if opcode is OK for rep{,z,nz}
1389
and al,not 1 ;clear low order bit (MOVSW -> MOVSB)
1391
ja ac11 ;if it's not a 1 byte instruction - error
1392
mov di,offset replist ;list of instructions that go with rep
1393
mov cx,N_REPALL ;scan all (REP + REPxx)
1395
jnz ac11 ;if it's not among them - error
1398
test [asm_mn_flags],AMF_MSEG
1399
jz @F ;if no segment prefix before mnemonic
1400
mov ax,[a_opcode] ;check if opcode allows this
1402
ja ac11 ;if it's not a 1 byte instruction - error
1403
mov di,offset prfxtab
1406
jnz ac11 ;if it's not in the list - error
1410
jz ac16 ;if no immediate data
1415
jnz ac11 ;if the immediate data was too big - error
1417
; Put the instruction together
1418
; (maybe is this why they call it an assembler)
1420
; First, the prefixes (including preceding WAIT instruction)
1423
sizeprfX ;mov edx,[a_addr]
1426
test [asm_mn_flags],AMF_WAIT
1427
jz @F ;if no wait instruction beforehand
1431
mov al,[aa_saved_prefix]
1433
jz @F ;if no LOCK or REP prefix
1437
;--- a 67h address size prefix is needed
1438
;--- 1. for CS32: if AMF_ADDR=1 and AMF_A32=1
1439
;--- 2. for CS16: if AMF_ADDR=1 and AMF_A32=0
1441
mov al,[asm_mn_flags]
1450
and al,AMF_A32 + 40h
1452
cmp al,AMF_A32 + 40h
1454
@dprintf "ac20: 67h prefix"
1459
;--- a 66h data size prefix is needed
1460
;--- for CS16: if VAR_D32 == 1 or AMF_D32 == 1
1461
;--- for CS32: if VAR_D16 == 1 or AMF_D16 == 1
1463
mov ah,[asm_mn_flags]
1464
mov al,[ai.varflags]
1480
@dprintf "ac20: 66h prefix"
1482
call writeasm ;store operand-size prefix
1486
jz @F ;if no segment prefix
1489
jb @F ;if not 64 or 65 (FS or GS)
1490
or [asm_mn_flags],AMF_FSGS ;flag it
1493
;--- Now emit the instruction itself.
1500
jb ac24 ;if regular instruction
1501
or [ai.dmflags],DM_COPR ;flag it as an x87 instruction
1502
and al,038h ;get register part
1503
@dprintf "ac21: fpu instr (>200h), update ai.regmem with AL=%X", ax
1505
xchg ax,di ;mov ax,di (the low bits of di are good)
1508
jmp ac25 ;on to decoding the instruction
1510
mov cl,3 ;one instruction of a group
1514
@dprintf "ac21: grp-instr (%X), update ai.regmem with AL=%X", a_opcode, ax
1517
mov ax,[agroups+di] ;get actual opcode
1521
jz ac25 ;if no 0fh first
1522
push ax ;store a 0fh
1523
@dprintf "ac24: 0F prefix"
1529
@dprintf "ac25: instruction byte: %X", ax
1530
or al,[ai.opcode_or] ;put additional bits into the op code
1531
call writeasm ;store the op code itself
1533
;--- Now store the extra stuff that comes with the instruction.
1535
mov ax,word ptr [ai.regmem]
1536
test [ai.varflags],VAR_MODRM
1537
jz @F ;if no mod reg/mem
1538
@dprintf "ac25: modrm %X (ai.regmem)", ax
1542
test [asm_mn_flags],AMF_SIB
1545
@dprintf "ac25: sib in AL %X", ax
1546
call writeasm ;store the MOD R/M and SIB, too
1551
jz @F ;if no offset associated with the R/M
1552
mov cl,[di].OPRND.sizedis
1554
lea si,[di].OPRND.num ;store the R/M offset (or memory offset)
1555
@dprintf "ac25: mem offs, size=%X ofs=%X", cx, word ptr [di].OPRND.num
1559
;--- Now store immediate data
1563
jz @F ;if no immediate data
1566
xchg ax,cx ;mov cx,ax
1567
@dprintf "ac25: imm data, size=%X data=%X", cx, word ptr [di].OPRND.num
1568
lea si,[di].OPRND.num
1572
;--- Now store additional bytes (needed for, e.g., enter instruction)
1573
;--- also for FAR memory address
1577
jz @F ;if no additional data
1578
lea si,[di].OPRND.numadd ;number of bytes (2 for FAR, size of segment)
1581
xchg ax,cx ;mov cx,ax
1582
@dprintf "ac25: additional data=%X", cx
1586
;--- Done emitting. Update asm address offset.
1588
sizeprfX ;mov [a_addr],edx
1591
;--- Compute machine type.
1594
jae ac31 ;if we already know a 386 is needed
1595
test [asm_mn_flags], AMF_D32 or AMF_A32 or AMF_FSGS
1597
test [ai.varflags],VAR_D32
1602
mov di,offset a_obstab ;obsolete instruction table
1604
call showmach ;get machine message into si, length into cx
1605
jcxz ac33 ;if no message
1608
mov di,offset line_out
1609
rep movsb ;copy the line to line_out
1613
jmp aa01 ;back for the next input line
1616
;--- This is debugging code. It assumes that the original value
1617
;--- of a_addr is on the top of the stack.
1619
pop si ;get orig. a_addr
1625
mov di,offset line_out
1632
call hexbyte ;display the bytes generated
1638
call disasm1 ;disassemble the new instruction
1639
jmp aa01 ;back to next input line
1646
;--- Jump table for operand types.
1647
;--- order of entries in asm_jmp1 must match
1648
;--- the one in dis_jmp1 / dis_optab.
1651
dw aop_imm, aop_rm, aop_m, aop_r_mod ;OP_IMM, OP_RM, OP_M, OP_R_MOD
1652
dw aop_moffs, aop_r, aop_r_add, aop_ax ;OP_MOFFS, OP_R, OP_R_ADD, OP_AX
1653
ASM_OPOFF equ $ - asm_jmp1
1655
;--- order must match the one in dis_optab
1656
dw ao17, ao17, ao17 ;OP_M64, OP_MFLOAT, OP_MDOUBLE
1657
dw ao17, ao17, ao17 ;OP_M80, OP_MXX, OP_FARMEM
1658
dw aop_farimm, aop_rel8, aop_rel1632;OP_FARIMM, OP_REL8, OP_REL1632
1659
dw ao29, aop_sti, aop_cr ;OP_1CHK, OP_STI, OP_CR
1660
dw ao34, ao35, ao39 ;OP_DR, OP_TR, OP_SEGREG
1661
dw ao41, ao42, aop_mmx ;OP_IMMS8, OP_IMM8, OP_MMX
1662
dw ao44, ao46, ao47 ;OP_SHOSIZ, OP_1, OP_3
1663
dw ao48, ao48, ao48 ;OP_DX, OP_CL, OP_ST
1664
dw ao48, ao48, ao48 ;OP_CS, OP_DS, OP_ES
1665
dw ao48, ao48, ao48 ;OP_FS, OP_GS, OP_SS
1669
; Routines to check for specific operand types.
1670
; Upon success, the routine returns.
1671
; Upon failure, it pops the return address and jumps to ac01.
1672
; The routines must preserve si and di.
1674
;--- OP_RM, OP_M, OP_R_MOD: form MOD R/M byte.
1679
call ao90 ;form reg/mem byte
1680
jmp ao07 ;go to the size check
1685
mov al,[di].OPRND.reg1 ;register number
1688
shl al,cl ;shift it into place
1689
or [ai.regmem],al ;put it into the reg/mem byte
1690
jmp ao07 ;go to the size check
1692
;--- OP_R_ADD: register, added to the instruction.
1695
mov al,[di].OPRND.reg1
1697
mov [ai.opcode_or],al ;put it there
1698
jmp ao07 ;go to the size check
1700
;--- OP_IMM: immediate data.
1703
mov [ai.immaddr],di ;save the location of this
1704
jmp ao07 ;go to the size check
1706
;--- OP_MOFFS: just the memory offset
1709
test [di].OPRND.flags,ARG_MODRM
1710
jnz ao11 ;if MOD R/M byte ( ==> reject)
1711
mov [ai.rmaddr],di ;save the operand pointer
1712
jmp ao07 ;go to the size check
1714
;--- OP_AX: check for AL/AX/EAX
1717
test [di].OPRND.reg1,7
1718
jnz ao11 ;if wrong register
1719
;jmp ao07 ;go to the size check
1723
ao07: ;<--- entry for OP_RM, OP_M, OP_R_MOD, OP_R, OP_R_ADD...
1724
or [ai.varflags],VAR_SIZ_NEED
1725
@dprintf "ao07: size check, reqsizeB=%X, sizeargB=%X", word ptr ai.reqsize, word ptr [di].OPRND.sizearg
1726
mov al,[ai.reqsize] ;4 OP_ALL, 5 OP_1632, 6 OP_8, 7 OP_16, 8 OP_32, 9 OP_64
1730
;--- OP_8=1, OP_16=2, OP_32=3, OP_64=4
1732
adc al,3 ;convert 3 --> 4 and 4 --> 5
1734
ao08: ;<--- entry for OP_M64 ... OP_FARMEM
1735
or [ai.varflags],VAR_SIZ_FORCD + VAR_SIZ_NEED
1737
mov bl,[di].OPRND.sizearg
1738
@dprintf "ao08_1: BL=%X AL=%X ai.opsize=%X", bx, ax, word ptr ai.opsize
1740
jz @F ;if no size given
1741
or [ai.varflags],VAR_SIZ_GIVN
1743
jne ao11 ;if sizes conflict
1746
je @F ;if sizes agree
1749
jnz ao11 ;if sizes disagree
1750
;--- v2.50: the next line caused - as a side effect - a regression for "call [xxxx]"
1751
;--- which has been fixed at ao13.
1752
or [ai.varflags],VAR_SIZ_GIVN ;v1.18 added!!!
1759
;--- OP_ALL - Allow all sizes.
1762
mov al,[di].OPRND.sizearg
1766
or [ai.opcode_or],1;set bit in instruction
1767
jmp ao14 ;if size is 16 or 32
1769
ao13: ;<--- OP_1632 - word or dword.
1770
mov al,[di].OPRND.sizearg
1771
@dprintf "ao13: OP_1632, AL=sizearg=%X, dx=%X", ax, dx
1772
if 1 ;v2.50: set default size for call/jmp/push [mem] (hackish fix)
1775
cmp dx, 40 ;just opindex 40 ( call/jmp/push [memref] )
1787
je ao16 ;if still unknown
1790
or [ai.varflags],VAR_D16
1794
jne ao11 ;if not dword
1795
or [ai.varflags],VAR_D32
1798
or [ai.varflags],VAR_SIZ_GIVN
1802
; OP_M64 - 64-bit memory reference.
1803
; OP_MFLOAT - single-precision floating point memory reference.
1804
; OP_MDOUBLE - double-precision floating point memory reference.
1805
; OP_M80 - 80-bit memory reference.
1806
; OP_MXX - memory reference, size unknown.
1807
; OP_FARMEM - far memory pointer
1809
;--- bx contains byte index for bittab
1811
call ao90 ;form reg/mem byte
1812
mov al,[asm_siznum + bx - ASM_OPOFF/2]
1813
@dprintf "ao17: bx=%X al=%X ai.opsiz=%X [di].sizearg=%X", bx, ax, word ptr ai.opsize, word ptr [di].OPRND.sizearg
1814
jmp ao08 ;check size
1816
;--- OP_FARIMM - far address contained in instruction
1824
cmp word ptr [di].OPRND.num+2,0
1825
jz ao22 ;if 16 bit address
1827
or [ai.varflags],VAR_D32
1830
mov [di].OPRND.numadd,2 ;2 additional bytes (segment part)
1832
mov [ai.opsize],al ;2/4, size of offset
1837
;--- OP_REL8 - relative address
1838
;--- Jcc, LOOPx, JxCXZ
1842
call aasizchk ;check the size
1843
mov cx,2 ;size of instruction
1844
mov al,[asm_mn_flags]
1846
test al,AMF_D32 or AMF_D16
1847
jz ao23_1 ;if not JxCXZ, LOOPx
1850
or al,AMF_A32 ; JxCXZ and LOOPx need a 67h, not a 66h prefix
1852
and al,not (AMF_D32 or AMF_D16)
1854
mov [asm_mn_flags],al
1866
inc cx ;instruction size = 3
1870
mov cx,[a_addr+2];v1.22: handle HiWord(EIP) properly
1872
mov ax,word ptr [di].OPRND.num+0
1873
mov dx,word ptr [di].OPRND.num+2
1874
;--- CX:BX holds E/IP (=src), DX:AX holds dst
1877
mov byte ptr [di].OPRND.num2,al
1878
mov cl,7 ;range must be ffffff80 <= x <= 0000007f
1879
sar al,cl ;1xxxxxxxb -> FF, 0xxxxxxxb -> 00
1881
jne ao_err1 ;if too big
1883
jne ao_err1 ;if too big
1884
mov [di].OPRND.numadd,1 ;save the length
1885
jmp ao22_1 ;save it away
1887
;--- OP_REL1632: relative jump/call to a longer address.
1888
;--- size of instruction is
1890
;--- 3 (xx xxxx, jmp/call) or
1892
;--- 6 (66 xx xxxxxxxx)
1893
;--- 7 (66 0F xx xxxxxxxx)
1896
;--- 5 (xx xxxxxxxx, jmp/call) or
1897
;--- 6 (0F xx xxxxxxxx)
1902
mov dx,word ptr [di].OPRND.num+2
1903
mov al,[di].OPRND.sizearg
1904
cmp [a_opcode],100h ;is a 0F xx opcode?
1909
je @F ;if no size given
1911
je ao27 ;if size "dword"
1913
jne ao_err1 ;if not size "long"
1920
jnz ao_err1 ;if operand is too big
1921
mov al,2 ;displacement size 2
1924
mov al,4 ;displacement size 4
1925
or [ai.varflags],VAR_D32
1926
add cx,3 ;add 3 to instr size (+2 for displ, +1 for 66h)
1930
dec cx ;no 66h prefix byte in 32-bit code
1937
mov [di].OPRND.numadd,al ;store size of displacement (2 or 4)
1938
mov ax,word ptr [di].OPRND.num+0
1939
sub ax,bx ;compute DX:AX - CX:BX
1941
mov [di].OPRND.num2,ax
1942
mov [di].OPRND.num2+2,dx
1948
;--- OP_1CHK - The assembler can ignore this one.
1951
pop ax ;discard return address
1952
jmp ac06 ;next operand
1957
mov al,REG_ST ;code for ST
1958
mov bl,[di].OPRND.reg2
1959
jmp ao38 ;to common code
1961
;--- OP_MMX [previously was OP_ECX (used for LOOPx)]
1965
jmp ao37 ;to common code
1970
mov al,[di].OPRND.reg2 ;get the index
1972
ja ao_err1 ;if too big
1974
mov [ai.dismach],5 ;CR4 is new to the 586
1978
cmp [di+sizeof OPRND].OPRND.flags,-1
1979
jne ao_err1 ;if another arg (can't mov CR1,xx)
1981
mov al,REG_CR ;code for CR
1982
jmp ao37 ;to common code
1987
mov al,REG_DR ;code for DR
1988
jmp ao37 ;to common code
1993
mov al,[di].OPRND.reg2 ;get the index
1995
jb ao_err1 ;if too small
1998
mov [ai.dismach],4 ;TR3-5 are new to the 486
2000
mov al,REG_TR ;code for TR
2002
;--- Common code for these weird registers.
2005
mov bl,[di].OPRND.reg2
2010
or [ai.varflags],VAR_MODRM
2011
cmp al,[di].OPRND.reg1 ;check for the right numbered register
2012
je ao40 ;if yes, then return
2019
mov al,[di].OPRND.reg1
2022
jae ao38a ;if not a segment register
2026
;--- v1.26: don't force size for MOV sreg,mxx / MOV mxx, sreg
2027
or [ai.varflags], VAR_SIZ_GIVN
2031
;--- OP_IMMS8 - Sign-extended immediate byte (PUSH xx)
2034
and [ai.varflags],not VAR_SIZ_NEED ;added for v1.09. Ok?
2035
mov ax,word ptr [di].OPRND.num+0
2038
jmp ao43 ;common code
2040
;--- OP_IMM8 - Immediate byte
2043
mov ax,word ptr [di].OPRND.num+0
2047
jne ao50 ;if too big
2048
cmp ax,word ptr [di].OPRND.num+2
2049
jne ao50 ;if too big
2051
call aasizchk ;check that size == 0 or 1
2052
mov ah,byte ptr [di].OPRND.num+0
2053
mov word ptr [di].OPRND.numadd,ax ;store length (0/1) + the byte
2058
;--- OP_SHOSIZ - force the user to declare the size of the next operand
2061
test [ai.varflags],VAR_SIZ_NEED
2062
jz ao45 ;if no testing needs to be done
2063
test [ai.varflags],VAR_SIZ_GIVN
2064
jz ao50 ;if size was given ( ==> reject)
2066
and [ai.varflags],not VAR_SIZ_GIVN ;clear the flag
2067
cmp byte ptr [si],OP_IMM8
2068
je ao45a ;if OP_IMM8 is next, then don't set VAR_SIZ_NEED
2069
or [ai.varflags],VAR_SIZ_NEED
2071
mov byte ptr [ai.opsize],0
2072
pop ax ;discard return address
2073
jmp ac06 ;next operand
2078
cmp word ptr [di+7],101h ;check both size and value
2079
jmp ao49 ;test it later
2084
cmp word ptr [di+7],301h ;check both size and value
2085
jmp ao49 ;test it later
2087
;--- OP_DX, OP_CL, OP_ST, OP_CS/DS/ES/FS/GS/SS
2088
;--- bx contains index for bittab
2091
mov al,[asm_regnum+bx-(ASM_OPOFF + OP_DX - OP_M64)/2]
2093
cmp ax,word ptr [di].OPRND.reg1
2098
;--- Reject this operand list.
2101
pop ax ;discard return address
2102
jmp ac01 ;go back to try the next alternative
2107
;--- AASIZCHK - Check that the size given is 0 or AL.
2110
cmp [di].OPRND.sizearg,SIZ_NONE
2112
cmp [di].OPRND.sizearg,al
2114
pop ax ;discard return address
2119
;--- Do reg/mem processing.
2124
@dprintf "ao90: reg/mem processing [di].flags=%X", word ptr [di].OPRND.flags
2125
test [di].OPRND.flags, ARG_JUSTREG
2126
jnz ao92 ;if just register
2127
test [di].OPRND.flags, ARG_MODRM
2128
jz @F ;if no precomputed MOD R/M byte
2129
mov ax,word ptr [di].OPRND.reg1 ;get the precomputed bytes
2132
mov al,6 ;convert plain displacement to MOD R/M
2133
test [asm_mn_flags],AMF_A32
2134
jz ao93 ;if 16 bit addressing
2139
mov al,[di].OPRND.reg1 ;convert register to MOD R/M
2143
mov al,[di].OPRND.reg2
2146
and al,7 ;get low 3 bits
2150
@dprintf "ao90: modrm, ai.regmem=%X, ax=%X", word ptr ai.regmem, ax
2151
or word ptr [ai.regmem],ax ;store the MOD R/M and SIB
2152
or [ai.varflags],VAR_MODRM ;flag its presence
2153
mov [ai.rmaddr],di ;save a pointer
2157
; AAIFNUM - Determine if there's a number next.
2158
; Entry AL First character of number
2159
; SI Address of next character of number
2160
; Exit CY Clear if there's a number, set otherwise.
2165
je aai2 ;if minus sign (carry is clear)
2177
cmc ;carry clear <==> it's a number
2182
; AAGETI - Get a number from the input line.
2183
; Entry AL First character of number
2184
; SI Address of next character of number
2185
; Exit DX:BX Resulting number
2186
; CL 1 if it's a byte ptr, 2 if a word, 4 if a dword
2187
; AL Next character not in number
2188
; SI Address of next character after that
2193
je aag1 ;if negative
2194
call aag4 ;get the bare number
2204
call aag4 ;get the bare number
2209
not dx ;negate the answer
2227
inc cx ;return: it's a dword
2230
inc cx ;return: it's a word
2234
xor bx,bx ;get the basic integer
2237
jc aag7 ;if not a hex digit
2239
or bl,al ;add it to the number
2244
jnz aag7 ;if overflow
2247
shl bx,1 ;shift it by 4
2253
jmp cmd_error ;error
2257
; AACONVINDEX - Convert results from AAGETI and store index value
2258
; Entry DX:BX,CL As in exit from AAGETI
2259
; DI Points to information record for this arg
2260
; Exit SS bits stored in [di].OPRND.index
2265
jne aacv1 ;if the number is too large
2278
jmp cmd_error ;error
2281
mov [di].OPRND.index,dl ;save the value
2285
; AAGETREG - Get register for the assembler.
2286
; Entry DI Start of register table
2287
; CX Length of register table ( or 0 )
2288
; SI Address of first character in register name
2289
; Exit NC if a register was found
2290
; SI Updated if a register was found
2291
; BX Register number, defined as in the table below.
2295
; DI = rgnam816, CX = 27 DI = rgnam16, CX = 8
2296
; ---------------------- --------------------
2297
; 0 .. 7: AL .. BH 0 .. 7: AX .. DI
2298
; 8 .. 15: AX .. DI 16 .. 23: EAX..EDI
2305
and ax,TOUPPER_W ;convert to upper case
2306
cmp al,'E' ;check for EAX, etc.
2313
mov di,offset rgnam16
2321
jne aagr1 ;if no match
2324
add bl,8+16 ;adjust BX
2325
jmp aagr2 ;finish up
2328
mov bx,cx ;(if cx = 0, this is always reached with
2329
repne scasw ; ZF clear)
2330
jne aagr3 ;if no match
2334
jb aagr2 ;if AL .. BH or AX .. DI
2337
inc si ;skip the register name