📄 asmops.asm
字号:
;
; GRDB
;
; Copyright(c) LADsoft
;
; David Lindauer, camille@bluegrass.net
;
;
; ASMOPS.ASM
;
; Function: Assembler operand parsers
;
;MASM MODE
.MODEL SMALL
.386
include iasm.inc
include easm.inc
include iopcodes.inc
include eopcodes.inc
include eopcom.inc
include eprints.inc
include einput.inc
include emtrap.inc
include edispatc.inc
include eoperand.inc
include eoptions.inc
PUBLIC AOP0, AOP1, AOP2, AOP3, AOP4, AOP5, AOP6, AOP7
PUBLIC AOP8, AOP9, AOP10, AOP11, AOP12, AOP13, AOP14, AOP15
PUBLIC AOP16, AOP17, AOP18, AOP19, AOP20, AOP21, AOP22, AOP23
PUBLIC AOP24, AOP25, AOP26, AOP27, AOP28, AOP29, AOP30, AOP31
PUBLIC AOP32, AOP33, AOP34, AOP35, AOP36, AOP37, AOP38, AOP39
PUBLIC AOP40, AOP41, AOP42, AOP43, AOP44, AOP45, AOP46, AOP47
PUBLIC AOP48, AOP49, AOP50, AOP51, aop52, AOP53, AOP54, AOP55
PUBLIC AOP56, AOP57, AOP58
.data
base16c dw 0ff03h,0ff05h,0ff07h,0ff06h,0705h,0605h, 0703h,0603h
dw 0ffffh,0ffffh,0ffffh,0ffffh,0507h,0506h, 0307h,0306h
.code
;Check if arg1.asize is 4 or less. If greater, return error to caller's
;caller by mucking with the stack.
intsize PROC
cmp [arg1.asize],DWORDSIZE ;maybe this means the first argument
ja rtnDirectlyToDispatcherWithCY ;can't exceed dword size
ret
intsize ENDP
;See if the mode field for this structure references a memory operand
;and return error to caller's caller if not
chkmem PROC
cmp [bx+asmop.mode],AM_MEM ;this is 3
jne rtnDirectlyToDispatcherWithCY ;bomb if not memory operand
ret
chkmem ENDP
;See if the mode field for this structure references an immediate operand
;and return error to caller's caller if not
chkimm PROC
cmp [bx+asmop.mode],AM_IMM ;check if immediate
jne rtnDirectlyToDispatcherWithCY ;if not, bomb
ret
chkimm ENDP
;See if the mode field for this structure references a segment
;and return error to caller's caller if not
chkseg PROC
cmp [bx+asmop.mode],AM_SEG
jne rtnDirectlyToDispatcherWithCY
ret
chkseg ENDP
;This is a little more complicated. Let's hypothesize that chkregw is
;shorthand for checking a 16-bit register type opcode. In this case,maybe the
;opcode must contain more than a single byte. So before we check if it
;is a register-type opcode, we must make sure it has extra byte(s). So
;we stop here first, and if the length makes us happy, then we check mode
; Next guess - if this is a byte argument, we bomb since a word register
;requires a word operand.
chkregw PROC
cmp [bx+asmop.asize],BYTESIZE ;is this a byte opcode
je rtnDirectlyToDispatcherWithCY ;if so, bomb
jmp chkreg ;else check mode for register type
chkregw ENDP
;Possibly this is used for in and out, where DX is the only register
;allowed?
chkdx PROC
cmp [bx+asmop.asize],WORDSIZE ;if not a word register
jne rtnDirectlyToDispatcherWithCY ;then bomb
cmp [bx+asmop.areg1],isEDX ;else see if DX register
jne rtnDirectlyToDispatcherWithCY ;if not, bomb
jmp chkreg
chkdx ENDP
;Not sure about the AX part of this, since all that is being checked is
;a size of byte
chkaxw PROC
cmp [bx+asmop.asize],BYTESIZE ;if a byte register
je rtnDirectlyToDispatcherWithCY ;then bomb
chkaxw ENDP
;This IS a check for AX (actually, 0 is EAX)
chkax PROC
cmp [bx+asmop.areg1],0 ;if not EAX (maybe AX or AL)
jne rtnDirectlyToDispatcherWithCY ;then bomb
chkax ENDP
;Check for a register? As opposed to ??
chkreg PROC
cmp [bx+asmop.mode],AM_REG ;is this flag set?
jne rtnDirectlyToDispatcherWithCY ;if not, bomb
ret
chkreg ENDP
;We bomb if arg3.mode isn't none, and if it is, we still bomb if arg2.mode
;is none. So arg3 is required to have a 'mode', whatever that is, I guess
noarg3 PROC
cmp [arg3.mode],AM_NONE
jne rtnDirectlyToDispatcherWithCY
cmp [arg2.mode],AM_NONE
je rtnDirectlyToDispatcherWithCY
ret
noarg3 ENDP
;Same as above, except it applies to arg2
noarg2 PROC
cmp [arg2.mode],AM_NONE
jne rtnDirectlyToDispatcherWithCY
cmp [arg1.mode],AM_NONE
je rtnDirectlyToDispatcherWithCY
ret
noarg2 ENDP
;Whoa, lets see here. If arg1.mode, whatever that is, is NOT 0, we jnz to
;rtnDirectlyToDispatcherWithCY. Since this routine was called, the return
;address is on the stack. Which means rtnDirectlyToDispatcherWithCY strips
;off the return address, and returns to the caller's caller.
noarg1 PROC
cmp [arg1.mode],AM_NONE
jne rtnDirectlyToDispatcherWithCY
ret
noarg1 ENDP
;
; pops the ret address from the AOP caller
; and goes directly back to the parser with a mismatch error
;
rtnDirectlyToDispatcherWithCY PROC
pop ax
stc
ret
rtnDirectlyToDispatcherWithCY ENDP
;see if size of this opcode is 1. If not, we are returning NZ and AL=1. I
;assume that 1 is important, since without the OR line, we would also be
;returning NZ if the size was not 1. In fact, several callers immediately
;do a stosb, so at the very least we are ensuring an odd number???
; Next guess: AL will eventually be used as part of the stored, assembled
;byte. So apparently the purpose of this routine is to set bit 0 of the
;untimate assembled value if this is NOT a byte operand.
sizeb0 PROC
cmp [bx+asmop.asize],BYTESIZE
je szb0x
or al,1
szb0x:
ret
sizeb0 ENDP
;In which case, the purpose of this routine is to set bit 3 of AL if the
;operand is NOT a byte operand.
sizeb3 PROC
cmp [bx+asmop.asize],BYTESIZE
je szb3x
or al,8
szb3x:
ret
sizeb3 ENDP
;
; main RM handler
;
; within this routine, CX = pointer to mod/RM byte and DX = flag for
; <e>bp based indexing
;
; all MOD/RM fields are set up assuming no offset and updated
; later...
;
asmfrm PROC
cmp [bx+asmop.mode],AM_FPREG ; check for register direct mode
jne asmrm2
or al,0c0h ; modrm = 0c0+al+regval
or al,[bx+asmop.areg1]
stosb
ret
asmfrm ENDP
asmrm PROC
shl al,3 ; shift reg val into place
asmrm ENDP
asmrm2 PROC
;
; registers are the same in both 16 & 32-bit
;
cmp [bx+asmop.mode],AM_REG ; 1check for register direct mode
jne rmnreg
or al,0c0h ; modrm = 0c0+al+regval
or al,[bx+asmop.areg1]
stosb
ret
rmnreg:
cmp [bx+asmop.msize],DWORDMODE ; see which style of addressing
je asmrm32
;
; 16-bit MEM handler
;
cmp [bx+asmop.mode],AM_MEM ; 16 bit, check for mem
jne rm16nmem
or al,6 ; MODRM = 6+al
stosb
jmp rmwoffs
rm16nmem:
cmp [bx+asmop.mode],AM_BASED ; check for 16 bit based
jne rtnDirectlyToDispatcherWithCY
;
; 16-bit base handler, restricted combos and no scaling
;
push ax ; yes, get the reg vals
sub ax,ax
mov al,[bx+asmop.areg1]
mov ah,[bx+asmop.areg2]
mov dx,ax
push di ; scan for a match and to get index
mov di,offset base16c
mov cx,16
repne scasw
pop di
pop ax
jnz rtnDirectlyToDispatcherWithCY ; scan failed, exit
bt cx,3
jc rm16nswap
xchg dl,dh
rm16nswap:
and cl,7
or al,cl
mov cx,di ; cx points at modrm byte
stosb
jmp rmanyoffs ; check for offs
;
; 32-bit modes start here
;
asmrm32:
cmp [bx+asmop.mode],AM_MEM ; 32 bit, check for mem
jne rm32nmem
;
; generic mem handler
;
or al,5 ; MODRM = 5+al
stosb
jmp rmwoffs
rm32nmem:
cmp [bx+asmop.mode],AM_BASED ; check for based
jne rtnDirectlyToDispatcherWithCY ; not legal if not
cmp [bx+asmop.areg2],0FFh ; else see if second reg defined
je rm32bbonly
cmp [bx+asmop.areg1],0FFh ; else see if first reg defined
je rm32bionly
;
; both a base AND an index
;
; the parser should have checked that ESP is not the scond arg
; and that we don't have two EBP args
;
cmp [bx+asmop.areg1],isEBP ; check for BP based
je rm32bbsebp
or al,4 ; flag MOD for SIB
mov cx,di
stosb
bsf ax,[bx+asmop.ascale] ; calculate SIB byte
shl ax,3
or al,[bx +asmop.areg2]
shl ax,3
or al,[bx+asmop.areg1]
stosb
sub dx,dx
jmp rmanyoffs
;
; base and index, base is ebp
rm32bbsebp:
or al,4
mov cx,di
stosb
bsf ax,[bx+asmop.ascale] ; calculate SIB byte
shl ax,3
or al,[bx+asmop.areg2]
shl ax,3
or al,5 ; bp based
stosb
mov dx,0ff05h
jmp rmanyoffs
;
; index only
rm32bionly:
or al,4 ; select SIB byte
stosb
bsf ax,word ptr [bx+asmop.ascale] ; calculate scale factor
shl ax,3 ; shift over
or ax,word ptr [bx+asmop.areg2] ; add in index
shl ax,3 ; shift over
or ax,5 ; base = 5, that is none since mod = 0
stosb
mov eax,[bx+asmop.addrx] ; always 32-bit ofs in this mode
stosd
ret
;
; only a base reg
;
rm32bbonly:
; shouldn't get here if no regs
cmp [ebx+asmop.areg1],isESP ; only one reg, check for ESP
je rm32besp
cmp [ebx+asmop.areg1],isEBP ; only one reg, check for EBP
je rm32bebp
or al,[ebx+asmop.areg1] ; no, normal MODRM byte with no SIB
mov cx,di
stosb
mov dh,0FFh ; pretend 16 bit
mov dl,al
and dl,7
jmp rmanyoffs
;
; based ESP, no index
;
rm32besp:
or al,4 ; select SIB byte (sib needed
mov cx,di ; for indexing off ESP)
stosb
mov al,24h ; sib byte for [esp] mode
stosb
sub dx,dx
jmp rmanyoffs
;
; based ebp, no index
;
rm32bebp:
or al,5
mov cx,di ; so we can adjust mod later
stosb
mov dx,0ff05h ; MUST have offset, this is BP base reg
jmp rmanyoffs
;
; now the auto offset routine.
; if (E)BP, we ALWAYS have an offset
; otherwise we see if the offset is zero before encoding anything
asmrm2 ENDP
rmanyoffs PROC
mov eax,[bx+asmop.addrx] ; get offs
cmp dx,0ff05h ; BP reg ALWAYS has offs
je rmaomho
or eax,eax ; else no offs if offs = 0
jz rmaook
;
; if we get here we have an offset, fix the RM field and embed the
; offset
;
rmaomho:
xchg cx,bx
add byte ptr [bx],40h ; else set MOD field = 1
xchg cx,bx
and eax,NOT 7FH ; else see if fits in a byte
jz rmboffs
cmp eax,NOT 7fh
je rmboffs ; yep, go do it
xchg cx,bx
add byte ptr [bx],40h ; else MOD field = 2
xchg cx,bx
jmp rmwoffs ; and go do it
rmboffs:
mov eax,[bx+asmop.addrx] ; get offs
stosb ; store a byte offs
rmaook:
clc
ret
rmanyoffs ENDP
rmszoffs PROC
mov eax,[bx+asmop.addrx]
cmp [bx+asmop.msize],WORDMODE
jae rmwoffs
stosb
clc
ret
rmszoffs ENDP
rmwoffs PROC
mov eax,[bx+asmop.addrx] ; check size
cmp [bx+asmop.msize],WORDMODE
ja rmdwoffs
stosw ; word offs
clc
ret
rmdwoffs:
test [Disassemble32Bit],1
jz rtnDirectlyToDispatcherWithCY
stosd ; dword offs
clc
ret
rmwoffs ENDP
rmszimm PROC
mov eax,[bx+asmop.addrx] ; check size
cmp [bx+asmop.asize],WORDSIZE
jae rmszimmw
stosb
clc
ret
rmszimmw:
jne rmszimmd
stosw
ret
rmszimmd:
cmp [bx+asmop.asize],DWORDSIZE
jne rtnDirectlyToDispatcherWithCY
test [Disassemble32Bit],1
jz rtnDirectlyToDispatcherWithCY
stosd
ret
rmszimm ENDP
;
; no operands. In this case, the opcode length is 1, so we go through this
; weird locution to rep mov a single byte out of the structure and
; into [di], wherever that points. Apparently it points into an opcode
; buffer somewhere. If the opcode length is greater than one, what
; happens?
;
AOP0 PROC
call noarg1 ;see if arg1.mode=0, whatever that means
push si ;only return here if it IS 0
movzx cx,[si+opcode.oclength] ;so get the length of the opcode
lea si,[si+opcode.compare] ;find the opcode in the structure
rep movsb ;copy from structure to buffer
pop si ;restore pointer to structure
clc ;say no problem
ret
AOP0 ENDP
;
; word reg, bits 0-2 of opcode = reg num
;
AOP1 PROC
call noarg2
call intsize
mov bx,offset arg1
call chkregw
mov al,byte ptr [si+OPCODE.COMPARE]
or al,[arg1.areg1]
stosb
clc
ret
AOP1 ENDP
;
; word acc,reg... reg = bits 0-2 of opcode
;
AOP2 PROC
call noarg3
call intsize
mov bx,offset arg1
call chkaxw
mov bx,offset arg2
call chkregw
mov al,byte ptr [si+opcode.compare]
or al,[arg2.areg1]
stosb
ret
AOP2 ENDP
;
; one arg, seg goes in b3-4 of opcode
;
AOP3 PROC
call noarg2
call intsize
mov bx,offset arg1
call chkseg
mov ah,byte ptr [si+OPCODE.COMPARE]
mov al,[arg1.areg1]
cmp ah,8
jae aop3ext
cmp al,4
jae aop3errx
aop3c:
shl al,3
or al,ah
stosb
ret
aop3ext:
sub al,4
jnc aop3c
aop3errx:
stc
ret
AOP3 ENDP
;
; either combo of a reg & rm... bit 1 of opcode set if reg is dest
; bit 0 set if size = word
;
AOP4 PROC
call noarg3
call intsize
sub al,al
mov bx,offset arg1
call sizeb0
cmp [arg1.mode],AM_REG
jne aop4rs
or al,2
mov bx,offset arg2
mov ah,[arg1.areg1]
jmp aop4j
aop4rs:
cmp [arg2.mode],AM_REG
jne aop4err
mov bx,offset arg1
mov ah,[arg2.areg1]
aop4j:
or al,byte ptr [si+OPCODE.COMPARE]
stosb
mov al,ah
call asmrm
ret
aop4err:
stc
ret
AOP4 ENDP
;
; use only rm, bit 0 = size (exception : jmp/call)
;
AOP5 PROC
call noarg2
call intsize
mov bx,offset arg1
mov ax,[si+OPCODE.COMPARE]
test al,1
jz aop5cansize
cmp [arg1.asize],DWORDSIZE ; special sizing for jump
jne aop5jn4
and [PrefixBitmapWord],NOT AS_OPSIZE
or ah,8
aop5jn4:
cmp [bx+asmop.asize],WORDSIZE
je aop5unsized
cmp [bx+asmop.asize],NOSIZE
je aop5unsized
stc
ret
aop5cansize:
call sizeb0
aop5unsized:
stosb
xchg al,ah
and al,38h
mov bx,offset arg1
call asmrm2
ret
AOP5 ENDP
;
; rm,count or rm,cl (shifts) bit 0 = size
; bit 1 set if size = 1, bit 4 set if size = cl, otherwise follow rm with
; a count byte
;
AOP6 PROC
call noarg3
call intsize
mov bx,offset arg1
mov ax,[si+opcode.compare]
call sizeb0
cmp [arg2.mode],AM_REG
je aop6cl
cmp [arg2.mode],AM_IMM
je aop6imm
aop6b:
stc
ret
aop6cl:
cmp [arg2.asize],BYTESIZE
jne aop6b
cmp [arg2.areg1],isECX
jne aop6b
or al,12h
stosb
jmp aop6rm
aop6imm:
cmp [arg2.addrx],1
je aop6shift1
stosb
xchg al,ah
call asmrm2
mov al,byte ptr [arg2.addrx]
stosb
ret
aop6shift1:
or al,10h
stosb
aop6rm:
xchg al,ah
call asmrm2
ret
AOP6 ENDP
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -