⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 asm.asm

📁 比dos下的debug更好的debug程序源码
💻 ASM
📖 第 1 页 / 共 3 页
字号:
;
; GRDB
;
; Copyright(c) LADsoft
;
; David Lindauer, camille@bluegrass.net
;
;
; ASM.ASM
;
; Function: Assembler parser
;
; not very efficient, but, fast enough!
;
	;MASM MODE
	.MODEL SMALL
	.386

include iasm.inc
include iopcodes.inc
include eaoperan.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
include ehistory.inc

	PUBLIC	asm
	PUBLIC	arg1
	PUBLIC	arg2
	PUBLIC	arg3
	PUBLIC	RepPfxBitmap
	PUBLIC	lastofs
	PUBLIC	lastbyte
	PUBLIC	PrefixBitmapWord

	.data
mtoofew		db	"Not enough operands",0
lastbyte	db	0		;last char of valid mnemonic
lastofs		dw	0		;current disassembly offset
lastseg		dw	0		;and current segment
say_repne	db	"repne",0	;prefix strings to look for
say_repe	db	"repe",0
say_rep		db	"rep",0
say_lock	db	"lock",0
say_word	db	"word",0	;opcode size overrides
say_byte	db	"byte",0
say_ptr		db	"ptr"
arg1		asmop	<>		;three args
arg2		asmop	<>
arg3		asmop	<>
arg4		asmop	<>		;temp for base-mode register gathering
AsmbldInstrsBuf	db	16 DUP (?)	;temporary to hold assembled instructions
OpSizeTable	db	16 DUP (?)	;sizes returned by AOP routines
OpSizeTblIndex	dw	0		;pointer into OpSizeTable
RepPfxBitmap	db	?		;bitmap of which rep prefix found
EnteredMnemonic	db	16 DUP (?)	;bucket to hold mnemonic as typed

;DefaultSeg appears to hold an index into SegmentPfxBytes.

DefaultSeg	db	0		;current default seg (DS or SS)
SegmentPfxBytes	db	26h,2eh,36h,3eh,64h,65h	;table of seg prefixes
	SEGPFXLISTSIZE	equ	$-SegmentPfxBytes
OverridePfxList	db	"asosgsfsdssscses"	;list of prefixes with colon
PrefixBitmapWord	dw	?	;bitmap of which prefix found
	.CODE
;
; interpreter stub to get params
; INPUT: DS:SI points at the user input line, just past the command char.
; I am assuming that someone issued the A command.  This can be by itself, 
; or it can be followed by some addresses
; The syntax is A [[segment:]offset]
;	where 
;	[segment:] can be any segment register, or it can be any hex
;		number of up to 4 digits.
;	[offset] can be any hex number of up to 8 digits
; OUTPUT: lastseg and lastofs set up to assemble at if user provided a legal 
;	address. Segment is also in FS
;	CY if invalid address
;	code address saved in case an unqualified 'A' command later
;
;
asm	PROC
	call	WadeSpace		; see if address given
	jnz	readaddr		; yep, get it (not CR past spaces)
	mov	ax,lastseg		; else see if any last addr
	or	ax,lastofs
	jz	usehere			;if not, go from where we are
	mov	dx,lastseg		;else, get prior assemble address
	movzx	ebx,lastofs
	jmp	gotaddr			;no need to set up our own
usehere:
	mov	ebx,RegdumpEIP		;else load our CS:IP
	mov	dx,RegdumpCS
	jmp	gotaddr			;and use that

readaddr:
	call	ReadAddress		; read address from input line
	jc	aserrm			; out on err
	call	WadeSpace		; make sure nothing else
	jnz	aserrm			; NZ means we didn't hit a CR
	call	defCS			; default CS
gotaddr:
	mov	esi,ebx			; load address
	mov	fs,dx			;setup segreg 
	and	esi,0ffffh		;force to 16-bit offset
	mov	lastseg,fs		;save current segment/selector
	mov	lastofs,si		;and current 16-bit offset
	call	histoff
	call	doasm			; do assembly
	call	histon
	clc				; exit
	ret
aserrm:
	stc				; exit with err
	ret
asm	ENDP
;
; prompt for a line, parse and assemble
;
; main assembler
;
; OK, the user pressed A <CR>. Here we solicit each entry, one line
; at a time, and convert the valid ones to opcodes. Invalid entries are
; complained about, and we return to the top of this routine to get
; another attempt.
; INPUT: address to assemble at is in FS (and lastseg): lastofs
; OUTPUT: Assembled code placed at target memory location and code ptr
;	  incremented
; PROCESSING: 
;	1) Display the segment:offset for the next line 
;	2) Get an instruction from the user
;		If CR only, we are done
;	3) If error, report and goto step 1, else assemble the instruction
;		into a temporary assembly buffer
;	4) Add any prefixes or overrides to the buffer as required
;	5) Copy the buffer to the target memory location
;	6) Return to step 1 until done.
; NOTES:
;	1) GetInputLine places the user input into InputBuffer, an 80-char
;		buffer. It handles backspacing. It returns with SI pointing
;		to the beginning of the edited input, which may not make
;		sense
;	2) getCode points DI at a 16-char bucket I call EnteredMnemonic,
;		and returns the first delineated string
;
doasm	PROC
	call	crlf			;move to new line
	mov	ax,fs			;get segment address
	call	printword		;paint that
	mov	dl,':'			;and a colon
	call	putchar
	mov	ax,lastofs		;get last offset
	call	printword		;print it
	call	printspace		;and a couple of spaces
	call	printspace
	call	GetInputLine           	; get input line
	call	WadeSpace		; if nothing there we are done
	jz	doasx			;since we hit the CR
	sub	al,al			;clear out AL
	call	setsize			;put 0 into these 3 fields
	mov	PrefixBitmapWord,0	;say no prefix found
	mov	DefaultSeg,3
	call	getcode			; get the opcode
	jc	badop
	mov	di,offset arg1		; get first arg
	call	parsearg
	jc	badarg
	mov	di,offset arg2		; get second arg
	call	parsearg
	jc	badarg
	mov	di,offset arg3		; get third arg
	call	parsearg
	jc	badarg
	jz	assemble		;if no more, to assemble it
manyerr:
	Call	printAlignedErrorMsg	;else bitch about too many operands
	db	"Too many operands",0
	jmp	doasm
badarg:
	call	printAlignedErrorMsg	;complain about invalid operand
	db	"Unknown operand",0
	jmp	doasm
badop:		
	call	printAlignedErrorMsg	;complain about invalid opcode
	db	"Unknown opcode",0
	jmp	doasm
assemble:
	call	validops		;size check and set
	jc	doasm			;size mismatch, ignore
	mov	si,offset mnemonicMatchAddrTable	;find table we built
	mov     cx,[mnemonicMatchCount]	;number of valid table entries
	mov	OpSizeTblIndex,0	;init index to top of table

;mnemonicMatchAddrTable contains a list of up to 10h addresses. Each address
;points to a structure. Each structure contains (among other things) a
;pointer to a string for this mnemonic, the base opcode for the
;mnemonic, and an index to the routine used to assemble the code
;  This loop is examining every valid element of the table we build to
;isolate those instances of this mnemonic that are valid in this case (that
;is, valid for size, addressing mode, etc).

assl:
	push	cx			;save count
	push	si			;save table address
	mov	si,[si]			;find structure address
	mov	di,offset AsmbldInstrsBuf	;where to put binary 
	call	oneasm			;dispatch for this operand
					; copies opcode for this instruction
					; into the assembled code buffer
	mov	cl,0			;assume we didn't do anything
	jc	assx2			;and if true, cl is right
	mov	cx,di			;else get offset we ended up at
	sub	cx,offset AsmbldInstrsBuf	;minus starting offset
assx2:		   	
	mov	bx,OpSizeTblIndex	;pointer into opsize table
	mov	[bx+OpSizeTable],cl	;save how many we did
	inc	OpSizeTblIndex		;bump to next location
	pop	si			;restore mnemonic ptr table address
	pop	cx			;and how many to examine
	add	si,2			;point to next possibility
	loop	assl			;do them all
	movzx	ecx,byte ptr OpSizeTblIndex	;see if we did anything
	jcxz	nomatch			;nope, not found in table
	sub	bx,bx			;else init for next loop


;at this point we have at least one match between the disassembly
;strucutre and the mneominc/addressmode / size data we accrued earlier.
;We are going to search the matched entries for the one with the
;smallest possible byte sequence

szllp:
	or	bh,bh			;if bh is zero
	jz	szlg			;skip this stuff
	cmp	bh,[ecx+OpSizeTable-1]	;see if high byte of table value
					;is greater than bh
	jb	sslc			;go here if it is
	test	byte ptr [ecx+OpSizeTable-1],0FFh	;see if table value is 0
	jz	sslc			;and if it is, same place

;OK, BH is keeping track of the length of the sequence, and BL is keeping
;track of the table offset to that sequence.  We get here in case a) this
;is the only valid sequence we found, or b) this sequence is shorter than
;the prior shortest sequence we found.

szlg:
	mov	bh,[ecx+OpSizeTable-1]	;get high byte of tbl element->bh
	mov	bl,cl			;track the index to the shortest
sslc:
	loop	szllp			;do for as many valid match instances
					;as we found
ssgot:
	or	bh,bh			;did we find anything?
	jz	nomatch			;no, we did not
	sub	bh,bh			;convert BL into a word index
	shl	bx,1			;into the match table
	mov	si,[bx+mnemonicMatchAddrTable-2]	;get an address
	mov	di,offset AsmbldInstrsBuf	;point to buffer
	call	oneasm				;build our favorite sequence
	mov	cx,di				;DI is new buffer offset
	mov	si,offset AsmbldInstrsBuf	;switch top to SI
	sub	cx,si			;get buffer bytecount
	mov	di,lastofs		;point to last assemble offset
	push	es			;save ES
	push	fs			;mov FS to ES
	pop	es
	push	cx			;save count

;Now DI points to the actual location in memory where we want to put our
;assembled buffer.  Since prefixes are not in the assembly buffer, we first
;stick in as many prefixes as we found, then paste the remainder of the
;buffer beyond them.

	call	InsertPrefixes
	pop	cx			;restore count
	jc	pfxerr			;if carry, too many prefixes
	rep	movsb			;copy to memory location for asm
	mov	lastofs,di		;update assemble in mem location
doasmn:
	pop	es			;restore old ES
	jmp	doasm			;and get next instruction
pfxerr:
	pop	es			;rectify stack
	call	printAlignedErrorMsg
	db	"Too many prefixes",0
	jmp	doasm

nomatch:
	call	printAlignedErrorMsg
	db	"Invalid opcode/operand combo",0
	jmp	doasm
doasx:
	ret
doasm	ENDP

;
;this routine is the shell which assembles an instruction based
;on the opcode/operand/size data
;
;INPUT: SI points to the opcode structure
;       DI points to a temp buffer into which we do the assembly
;OUTPUT: BUFFER FILLED.  This routine does the 0F prefix but none of the
;        other prefixes

oneasm	PROC
	test	[si+OPCODE.FLAGS],prefix0F	;0F prefix on this guy?
	jz	no386p				;nope
	mov	al,0fh				;else stash the 0F
	stosb					;into the buffer
no386p:

;The syntax here works, but it can be clarified a little. opcode.operands
;was never explicitly written to.  Instead, we build a table of pointers
;into a table of opcode structures. SI contains one of the pointers out
;of that table. Maybe it's just because I'm more used to it, but I prefer
;the MASM syntax to indicate this:
;	mov	al,(opcode ptr [si]).operands

	mov	al,[si+opcode.operands]		;get addressing mode
	push	0				;TableDispatch calls this subkey
	call	TableDispatch			;and dispatch it
	dw	58				;length of table

	dw	AOP0,  AOP1,  AOP2,  AOP3,  AOP4,  AOP5,  AOP6,  AOP7
	dw	AOP8,  AOP9,  AOP10, AOP11, AOP12, AOP13, AOP14, AOP15
	dw	AOP16, AOP17, AOP18, AOP19, AOP20, AOP21, AOP22, AOP23
	dw	AOP24, AOP25, AOP26, AOP27, AOP28, AOP29, AOP30, AOP31
	dw	AOP32, AOP33, AOP34, AOP35, AOP36, AOP37, AOP38, AOP39
	dw	AOP40, AOP41, AOP42, AOP43, AOP44, AOP45, AOP46, AOP47
	dw	AOP48, aop49, aop50, AOP51, AOP52, AOP53, AOP54, AOP55
	dw	AOP56, AOP57, AOP58
	ret
oneasm	ENDP

;
; inserts prefixes into buffer
;
;INPUT: ES:DI points to buffer
;OUTPUT: all prefixes inserted and DI updated
;
;
; first comes th 386 prefixes

InsertPrefixes	PROC
	sub	dx,dx
	test	[PrefixBitmapWord],AS_OPSIZE	;see if 66 override
	jz	nopsiz
	mov	al,66h
	stosb
nopsiz:
	test	[PrefixBitmapWord],AS_ADDRSIZE	;see if 67 override
	jz	naddrsiz
	mov	al,67h
	stosb

naddrsiz:
;
; now we do segment overrid prefixes by scanning the prefix bitmap
; word
	sub	dx,dx			;start with no override byte count
	mov	dh,byte ptr [PrefixBitmapWord]	;get prefix bitmap lo byte
	mov	bx,offset SegmentPfxBytes	;list of prefix bytes
	mov	cx,SEGPFXLISTSIZE		;there are 6 of these

sl2:
	shr	dh,1			;see if this one required
	jnc	nsl2			; no, skip
	mov	al,[bx]			; else load the prefix from the table
	stosb				; save it
	inc	dx			; increment prefix count
nsl2:
	inc	bx			; point to next prefix
	loop	sl2			; next prefix
	
	cmp	dl,2			;count of segment prefixes added
	jb	lpnerr			;can't exceed 1
	stc
	ret
lpnerr:
;
; now we do the remainder of the 8086 repeate and lock prefixes
;
	test	RepPfxBitmap,AF_LOCK	;see if lock set
	jz	nlock			;nope, no lock
	mov	al,0f0h			;else stash lock prefix
	stosb
nlock:
	test	RepPfxBitmap,AF_REPNE OR AF_REP	;see if REPNE set
	jz	nrepne			; nope, no REPNE
	mov	al,0f2h			;stick in repne prefix
	stosb
nrepne:
	test	RepPfxBitmap,AF_REPE	; See if REPE
	jz	nrepe			; noe, no repe
	mov	al,0f3h			;stick in repe prefix
	stosb
nrepe:
	clc
	ret
InsertPrefixes	ENDP
;
; routine displays error if operands are mismatched
;
; INPUT: none
; OUTPUT: message displayed
operr	PROC
	call	printAlignedErrorMsg
	db	"Unusable operand combination",0
	stc
	ret
operr	ENDP
;
; check for size mismatches and get a size.
; INPUT: SI points to user's input buffer/
; OK, a little bit of clarification has happened on this one, thankfully.
;  Turns out that opcodes fall into several categories with respect to this
; routine. In general, for any opcode with more than one operand, all
; subsequent operands must match one another in size except for the
; exceptions. The exceptions to be permitted are:
;	1) movzx and movsx, which by definition have mismatched operands
;	2) In and Out instructions, where DX holds the port, and we can
;	   read or write any size operand through that port
;	3) SHR,SAR,SHL,SAL,RCR,RCL CL, since any size operand can be shifted 
;	   by CL bits
;	4) Immediate operands, which can be smaller but not larger than
;	   their targets
;	5) Memory, if sizes to any memory mode are given they must match
;	   the rest of the arguments.
;

validops	PROC
	cmp	lastbyte,"x" 		;if movzx or movsx
	je	vox			;then this is OK


;OK, the logic here is really hosed. What it is supposed to say is this:
;IF any operand is provided
;	IF more than one operand
;		IF all operands are not equal in size
;			IF not an allowed exception
;				THEN error
;			ELSE OK
;		ELSE OK
;	ELSE OK
;ELSE OK

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -