|
|
title asmhelp - assembler helpers page ,132
;-------------------------------------------------------------------- ; ; asmhelp fast assembly language helpers for masm ; ; (C)Copyright 1985 Microsoft Corp. ; ; Revision history ; ; 04/02/85 Greg Whitten ; initial version ; scanatom speedups ; ;--------------------------------------------------------------------
ifndef MSDOS ifndef CPDOS .286 endif endif .model medium,c
if1
alignCode macro align 4 endm
.xlist include mixed.inc .list .lall
endif
cLang = 1 CASEL = 1 SYMMAX = 31 TSYMSIZE = 451 ; from asmsym.c
LEGAL1ST = 08h ; legal 1st token character mask TOKLEGAL = 10h ; legal token character mask
.code A_TEXT
extrn Pascal ERRORC:near extrn Pascal CREFNEW:far extrn Pascal CREFOUT:far extrn Pascal OFFSETASCII:far extrn Pascal listline:far extrn Pascal crefline:far extrn Pascal tryOneFile:far
extrn _ffree:far
ifndef MSDOS extrn read:proc extrn write:proc extrn lseek:proc extrn free:proc endif
ifdef CPDOS extrn Pascal DosRead:far extrn Pascal DosChgFilePtr:far extrn Pascal DosWrite:far endif .data
extrn _asmctype_:byte extrn _asmcupper_:byte extrn _asmTokenMap_:byte extrn caseflag:byte extrn fCrefline:byte extrn fNeedList:byte extrn objing:byte extrn srceof:byte extrn crefing:byte extrn emitrecordtype:byte
extrn linebp:word extrn linelength:byte extrn linebuffer:byte extrn linessrc:word extrn listconsole:byte extrn begatom:word extrn endatom:word extrn errorlineno:word extrn errorcode:word extrn oOMFCur:dword extrn handler:byte extrn lbufp:word extrn pass2:byte extrn save:byte extrn svname:word extrn obj:word extrn pFCBCur:word extrn naim:word extrn objerr:word extrn objectascii:word extrn iProcCur:word
extrn symptr:dword extrn lsting:byte extrn lbuf:byte
ifdef BCBOPT extrn hash:word extrn lcname:word extrn svhash:word extrn svlcname:word extrn fNoCompact:byte endif
@CurSeg ends
assume ds:nothing extrn tsym:dword assume ds:@data
.data?
mapstr db 10 dup(?) ; use this if /Ml
ifdef M8086OPT qlcname db SYMMAX+1 dup(?)
dw 1 dup(?) ;hash for name db 1 dup(?) ;cb for name qname db SYMMAX+1 dup(?)
qsvlcname db SYMMAX+1 dup(?)
dw 1 dup(?) ;hash for name db 1 dup(?) ;cb for name qsvname db SYMMAX+1 dup(?)
endif
ifdef M8086OPT public qlcname, qname, qsvlcname, qsvname endif
.data fEatBlanks db 1 ; flag for common getatom & getatomend cbLeft dw 0 ; count of bytes left in lbuf rarea dw 0 ; area for DosRead/Write to tell how much it read
.code A_TEXT
ifdef M8086OPT
;*** getatom () ( hash = scanatom() )
nulToken: mov lbufp,si ; update buffer pointer mov [di+SYMMAX+4],bh pop di pop si retn
getatomComm:
hProc <getatom near>, <uses si di>
mov ax,ds mov es,ax mov di,lbufp mov ax,0920H ; load tab|space into AX or cx,0FFFFH ; large count to CX alignCode skipbeg: repe scasb ; look for space xchg al,ah dec di repe scasb ; then tab dec di cmp byte ptr [di],ah je skipbeg ; repeat if still space
xor ax,ax xor bx,bx mov si,di mov di,lcname
mov bl,[si] test byte ptr _asmctype_[bx],LEGAL1ST jz nulToken
xor dx,dx ; initial hash value mov cx,SYMMAX mov begatom,si ; start of atom
cmp bl,'.' ;special case for token starting jne notDot ;with . inc si dec cx mov al,bl mov dx,ax stosb mov [di+SYMMAX+3],al notDot: mov bx,offset _asmTokenMap_ ; character translation table
cmp caseflag,CASEL je short tokloop ; Mu or Mx - use MAP version
alignCode Mtokloop: rept 3 lodsb ; al = get next character stosb ; *lcname++ = cc xlat
mov [di+SYMMAX+3],al ; *naim++ = cc add dx,ax ; swapped hash += MAP(cc)
dec cx or al,al jz short tokdone jcxz skiptok endm
lodsb stosb xlat
mov [di+SYMMAX+3],al add dx,ax
or al,al loopnz Mtokloop
jz tokdone jmp skiptok
tokloop: rept 3 lodsb ; al = get next character stosb ; *lcname++ = cc
mov [di+SYMMAX+3],al ; *naim++ = cc xlat add dx,ax ; swapped hash += MAP(cc)
dec cx or al,al jz short tokdone0 jcxz skiptok endm
lodsb stosb
mov [di+SYMMAX+3],al xlat add dx,ax
or al,al loopnz tokloop
jz tokdone0 jmp short skiptok
tokdone0: mov [di+SYMMAX+3],al ; terminate tokdone: mov [di-1],al dec si mov endatom,si jmp short skipend
skiptok: dec cx
skipnext: lodsb ; eat extra characters in token xlat or al,al jnz skipnext ; skip token
mov endatom,si
mov [di],al inc di mov [di+SYMMAX+3],al ; terminate dec si
skipend: ; skip for getatom only mov bx,cx mov di,si cmp fEatBlanks,0 jz noEatSemie
mov ax,0920H ; load tab|space into AX or cx,0FFFFH ; large count to CX alignCode skipend1: repe scasb ; look for space xchg al,ah dec di repe scasb ; then tab dec di cmp byte ptr [di],ah je skipend1 ; repeat if still space
skipend2: ; skip trailing white space mov lbufp,di ; update buffer pointer
xor ax,ax mov al,SYMMAX-1 ; compute token length sub al,bl
mov bx,naim mov byte ptr [bx-1],al ; save prefixed cb mov word ptr [bx-3],dx ; save prefixed hash
hRet
noEatSemie: mov fEatBlanks,1 jmp skipend2
hEndp
;*** getatomend () ; get an token without skiping trailing spaces
hProc <getatomend near>
mov fEatBlanks,0 jmp getatomComm
hEndp
endif ;M8086OPT
ifdef M8086OPT ;*** inset (value, setptr)
hProc <inset near>, <uses si di>, value:byte, setptr:word
mov ax,ds mov es,ax cld mov al,value mov di,setptr mov cl,[di] inc di xor ch,ch ; cx = set length repne scasb ; scan for al in es:di je insetT ; yes - return TRUE xor ax,ax ; return FALSE insetexit: hRet
insetT: mov ax,1 ; return TRUE jmp short insetexit
hEndp
endif ;M8086OPT
;*** strffcmp (far1, far2)
hProc <strffcmp far>, <uses si di>, far1:dword, far2:dword
cld les di,far2 lds si,far1 mov bx,di ; save start of string cmpsb ; fast 1st char check jnz ffne dec si xor ax,ax ; search for 0 terminator mov cx,-1 repne scasb neg cx ; cx = byte count for compare mov di,bx repz cmpsb ffne: mov al,[si-1] sub al,es:[di-1] ; ax = 0 if equal cbw
push ss pop ds hRet
hEndp
;*** strnfcmp (near1, far2)
hProc <strnfcmp near>, <uses di si>, near1:word, far2:dword
cld mov si,near1 les di,far2 mov bx,di ; save start of string cmpsb ; fast check on 1st character jnz nfne dec si xor ax,ax ; search for 0 terminator mov cx,-1 repne scasb neg cx ; cx = byte count for compare mov di,bx repz cmpsb nfne: mov al,[si-1] sub al,es:[di-1] ; ax = 0 if equal
hRet
hEndp
ifdef M8086OPT
;*** switchname ()
hProc <switchname near> alignCode
mov ax,naim ;; (naim) <--> (svname) xchg ax,svname mov naim,ax mov ax,lcname ;; (lcname) <--> (svlcname) xchg ax,svlcname mov lcname,ax hRet
hEndP
endif ;M8086OPT
ifdef M8086OPT
;*** I/O routines: readmore, getline, ebuffer, etc.
objfile struc ofh dw ? ifdef MSDOS pos dd ? buf dd ? else pos dw ? buf dw ? endif ;MSDOS cnt dw ? siz dw ? oname dw ? objfile ends
endif ;M8086OPT
ifdef M8086OPT
;*** ebuffer - write out object buffer ; ; ebuffer (rectype, bufpos, buffer)
ebyte macro dec [bx].cnt jge short $+5 call edump ; dump buffer stosb add ah,al endm
hProc <ebuffer near>, <uses si di>, rectype:byte, bufpos:word, buffer:word
mov si,buffer mov cx,bufpos sub cx,si ; cx = buffer count jz ebufdone cmp objing,0 je ebufdone ; return if no object file
mov ax,cx add ax,4 add word ptr oOMFCur,ax ; oOMFCur += cbBuffer + 3 adc word ptr oOMFCur.2,0 ifndef MSDOS mov ax,ds mov es,ax endif cld xor ax,ax ; ah = 0 (initial checksum) mov al,rectype mov bx,OFFSET obj ; bx = obj file data structure pointer ifdef MSDOS les di,[bx].pos ; es:di = output buffer position else mov di,[bx].pos ; di = output buffer position endif ebyte ; output record type inc cx ; + 1 for record length mov al,cl ebyte mov al,ch ebyte ; output record length dec cx ; - 1 for buffer loop alignCode ebufloop: ; output buffer lodsb ebyte loop ebufloop mov al,ah ; output checksum neg al ebyte ifdef MSDOS mov word ptr [bx].pos,di ; reset buffer position else mov [bx].pos,di ; reset buffer position endif
ebufdone: mov emitrecordtype,0 hRet
hEndp
; edump ; ; Save: ; bx = obj file descriptor pointer ; ax = (checksum,outputbyte) ; cx = possible count ; si = emit buffer position
edump: push ax push cx push bx ; save src file descriptor pointer ifdef MSDOS push ds mov cx,[bx].siz mov ax,[bx].ofh lds dx,[bx].buf mov bh,40h xchg ax,bx ifdef CPDOS push bx ; file handle push ds ; buffer (selector) push dx ; buffer (offset) push cx ; # bytes to read mov ax,@data push ax ; reply area (selector) mov ax,offset rarea push ax ; reply area (offset) call DosWrite else int 21h endif pop ds
ifdef CPDOS or ax,ax mov ax,rarea jnz writerr else jc writerr endif pop bx push bx cmp ax,[bx].siz je writeok writerr: mov objerr,-1 writeok: else push [bx].siz push [bx].buf push [bx].ofh call write ; write (ofh,buf,siz) add sp,6 pop bx ; need to get bx back. push bx ; write trashes it. -Hans cmp ax,[bx].siz je writeok mov objerr,-1 writeok: mov ax,ds mov es,ax cld ; in case endif pop bx mov ax,[bx].siz dec ax mov [bx].cnt,ax ; reset buffer position ifdef MSDOS mov di,word ptr [bx].buf ; di = start of buffer else mov di,[bx].buf ; di = start of buffer endif pop cx pop ax ret
endif ;M8086OPT
hProc <fMemcpy near>, <uses si di>, pDest:dword, pSource:dword, cb:word
mov cx,cb jcxz fM1
mov dx,ds lds si,pSource les di,pDest shr cx,1 rep movsw jnc fM01 movsb fM01: mov ds,Dx fM1: hRet hEndp
ifdef M8086OPT ; Native code version of symsrch as in asmsym.c
hProc <symsrch near>, <uses si di>
mov si,naim xor Dx,Dx cmp byte ptr[si-1],dl jne sy001 jmp sy99 sy001: mov Ax,word ptr[si-3] mov Cx,TSYMSIZE div Cx
mov Bx,Dx ;index into hash table shl Bx,1 shl Bx,1 mov Ax,SEG tsym mov Es,Ax les di,dword ptr es:[Bx].tsym mov Ax,es or Ax,Ax ;if segment 0 jne sy002 jmp sy991 sy002: mov Ax,word ptr[si-3] mov Dx,si xor Cx,Cx jmp short syLook
alignCode syNext: les di,es:[di] ; next symbol mov Bx,es or Bx,Bx ; continue if segment not 0 jnz sylook jmp sy99 syLook: mov bx,es:[di].12 ; pointer to name cmp Ax,es:[Bx] ; check hash values jne syNext
xchg Bx,di mov cl,[si-1] ; lenght to cl inc Cx inc di inc di ; skip hash repz cmpsb ; check actual strings mov di,Bx ; restore pointers mov si,Dx jnz syNext
syFound: cmp byte ptr es:[bx].1bH,12 ; if (p->symkind == CLABEL) jne @F
@@: mov cx,iProcCur jcxz noNest
push ax cmp byte ptr es:[bx].1bH,2 ; if (p->symkind == CLABEL) jne sy1 mov Ax,word ptr es:[bx].22h ; if (p->iProc) sy01: or ax,ax jz noNest0 cmp cx,Ax ; if (p->iProc != iProcCur) je noNest0 pop ax xor cx,cx jmp syNext sy1: cmp byte ptr es:[bx].1bH,6 ; if (p->symkind == EQU) jne noNest0 mov Ax,word ptr es:[bx].1eh ; AX = p->csassume jmp sy01
noNest0: pop ax
noNest: mov word ptr symptr,Bx mov word ptr symptr+2,es mov Ax,1 cmp crefing,al je syCref hRet ;Return true syCref: push Ax ;call crefing routines call crefnew call crefout mov al,1 jmp short sy991 sy99: xor Ax,Ax sy991: hRet
hEndp
endif ;M8086OPT
ifdef M8086OPT
;int PASCAL iskey (table)
hProc <iskey near>, <uses si di>, table:dword hLocal l1:word, l2:word
cld mov si,naim cmp caseflag,1 ;if (caseflag == CASEL) { jne noComputeHash
xor Dx,Dx ;nhash = 0;
;|*** for (uc = mapstr, lc = str; *lc; )
push ds pop es mov di,OFFSET mapstr xor bh,bh mov ah,bh alignCode $F791: lodsb or al,al jz $L2001 mov bl,al mov al,BYTE PTR _asmcupper_[bx] stosb add Dx,Ax jmp short $F791 $L2001:
;|*** *uc = 0;
stosb ;0 terminate string
;|*** uc = mapstr;
mov si,OFFSET mapstr mov Cx,di sub Cx,si ;cb of string into Cx mov Ax,Dx ;hash to Ax jmp SHORT storeNhash ;Ax has computed hash
noComputeHash:
xor cx,cx mov cl,[si-1] inc Cx ;include NULL mov ax,[si-3]
storeNhash: mov l1,ax ;nhash mov l2,Cx ;cb
;|*** for (p = table->kttable[nhash % table->ktsize]; p; p = p->knext)
les bx,table mov di,es:[bx] ;es now contains symbol table segment cwd idiv WORD PTR es:[bx+2] shl dx,1 add di,dx mov Bx,si ;save uc name
alignCode isLook: cmp word ptr es:[di],0 je isNotFound mov di,es:[di]
;|*** if ((nhash == p->khash) && (!strcmp (p->kname,uc)))
mov Ax,l1 ;nhash cmp es:[di+4],Ax jne isLook
; do an inline string compare
mov Dx,di ; save p
mov Cx,l2 ;cB mov di,WORD PTR es:[di+2] ;Es:di = p->kname
repe cmpsb ; compare while equal
jcxz isFound
mov di,Dx ;restore registers mov si,Bx
jmp isLook
;|*** return (p->ktoken);
isFound: mov di,Dx mov Ax,es:[di+6] jmp SHORT isReturn
isNotFound: alignCode mov ax,-1 isReturn: hRet hEndp
endif ;M8086OPT
ifdef M8086OPT hProc <skipblanks near>
mov bx,lbufp dec bx alignCode ik1: ; skip leading white space inc bx mov al,[Bx] cmp al,' ' je ik1 cmp al,9 je ik1
mov lbufp,bx
hRet
hEndp endif
MC struc ;structure for macro call, see asm86.h for full comments
pTSHead dd ? pTSCur dd ?
flags db ? iLocal db ? cbParms dw ? locBase dw ? countMC dw ?
pParmNames dw ? pParmAct dw ?
svcondlevel db ? svlastcond db ? svelseflag db ? db ? rgPV dw ? MC ends
ifdef M8086OPT
leOverflow2: pop ax
leOverflow: push ss pop ds xor Ax,Ax stosb ; terminate line
mov ax, 100 ; E_LTL push AX ; print error message call ERRORC jmp leFin2
; fast version to expand macro bodies / coded in C in asmirp.c
hProc <lineExpand near>, <uses si di>, pMC:word, pMacroLine:dword assume es:@data
ifdef BCBOPT mov fNoCompact, 0 endif mov cbLeft, 511 ; LBUFMAX (asm86.h) - 4 les si,pMacroLine ; get pointer to macro prototype mov bx,pMC
mov dl,[bx].iLocal ; dl: local base index mov dh,080H ; dh: local base with high bit set add dh,dl
lea bp,[bx].rgPV ; bp: pointer to actual arg array mov di,offset lbuf ; si: pointer to new line
push ds mov Ax,Es mov ds,Ax ; set seg regs for ds:si & es:di pop es xor ah,ah xor ch,ch ; set loop invariate le1: lodsb ; fetch next prefix test al,080H ; check for parm jnz leParmFound
mov cl,al jcxz leFinished sub es:[cbLeft],ax jc leOverflow
repz movsb ; move non parameter entry jmp le1
leParmFound: ; argment found mov bl,al ; compute index shl bx,1 shl bx,1 and bx,01FFH ; remove shifted high bit add Bx,Bp
push ds push es pop ds ; save current ds and set to near
cmp al,dh ; determine parm type jae leLocalFound
mov Bx,word ptr[Bx] ; fetch pointer to actual xchg Bx,si ; save pMacroLine
lodsb mov cl,al jcxz leNullArg sub cbLeft,ax jnc le2 jmp leOverflow2
le2: repz movsb ; move parameter entry leNullArg: mov si,Bx ; restore saved pMacroLine pop ds xor ah, ah jmp le1
leLocalFound: cmp word ptr[Bx],0 ; check to see if the local jz leBuildLocal ; is defined
leLocalMove: xchg Bx,si ; save pMacroLine sub cbLeft,6 jnc le3 jmp leOverflow2
le3: mov Ax,'??' ; store leading ?? stosw movsw ; and then remaining xxxx movsw jmp leNullArg leBuildLocal: push Dx ; call runtime helper to generate name push Bx push Es xor ah,ah sub al,dh
mov Bx,Sp ; fetch pMC mov Bx,[Bx+8+4+4] add Ax,[Bx].locBase xor Bx,BX
push Bx ; offsetAscii((long) .. ) push Ax call offsetAscii
pop Es pop Bx pop Dx
mov Ax,objectascii ; copy 4 byte local name to cach mov [Bx],AX mov Ax,objectascii+2 mov [Bx].2,AX jmp leLocalMove
leFinished: mov ax,es ; restore ds mov ds,ax leFin2: mov linebp,di ; set linebp mov si,offset lbuf mov lbufp,si ; lbufp= lbuf sub di,si mov cx, di mov linelength, al ; linelength = linbp - lbuf
cmp fNeedList,0 ;for listing copy to list buffer je @F mov di,offset linebuffer shr cx,1 rep movsw rcl cx,1 rep movsb @@: .8086 hRet
ifndef MSDOS .286 endif hEndp
endif ;M8086OPT
ifdef M8086OPT
;*** expandTM - expand text macro in naim in lbuf/lbufp ;* ;* expandTM (equtext); ;* ;* Entry equtext = replacement string ;* naim = text macro ;* begatom = first character in lbuf to replace ;* endatom = first character in lbuf after string to replace ;* Exit lbuf = new line to be parsed ;* Returns ;* Calls ;* Note Shifts characters from lbufp to make substitution of TM. ;* Inserts replacement string at begatom ;*/
hProc <expandTM near>, <uses si di>, equtext:word hLocal cbEndatom:word, cbNaim:word, cbText:word, fShifted:byte
cld ; String instructions go forward
mov ax, ds ; Set es to @data mov es, ax ;
xor ax, ax ; Will stop scanning when [di] == [al] == 0 mov fshifted, 0 ; Haven't shifted line yet
mov cx, linebp ; Calculate cbEndatom == strlen(endatom) sub cx, endatom ; but use (linebp - endatom + 1) as method inc cx ; mov cbEndatom, cx ; Store result in cbEndatom
mov cx, endatom ; Calculate cbNaim == strlen(naim) sub cx, begatom ; but use (endatom - begatom) as method mov cbNaim, cx ; Store result in cbNaim
mov di, equtext ; Calculate cbText == strlen(equtext) mov cx, -1 ; repne scasb ; not cx ; [cx] == length of equtext dec cx ; don't count NULL mov cbText, cx ; Store result in cbText
cmp cbNaim, cx ; Q: Is replacement longer than name? jl shiftline ; Y: Must shift endatom string to the right
copytext: mov di, begatom ; Copy replacement text into lbuf mov si, equtext ; mov cx, cbText ; Number of bytes to copy shr cx, 1 ; rep movsw ; jnc etm2 ; movsb ; etm2: cmp fShifted, 0 ; Q: Have already shifted line right? jne etmEnd ; Y: Done
mov si, endatom ; Q: Is cbNaim == cbText? cmp di, si ; je etmEnd ; Y: Done
mov cx, cbEndatom ; N: Must shift endatom string left shr cx, 1 ; rep movsw ; jnc etm3 ; movsb ; etm3: mov linebp, di ; jmp etmEnd ; Done
shiftline: ; Shift string at endatom to right
mov cx, cbEndatom ; Number of bytes to move mov si, linebp ; [si] = end of string in lbuf mov di, si ; add di, cbText ; sub di, cbNaim ; di == si + amount to shift string right mov linebp, di ;
mov dx, di ; check if line too long sub dx, OFFSET lbuf ; cmp dx, 512 ; LBUFMAX (asm86.h) jge eltl ; line too long
std ; String instructions go backwards rep movsb ; Shift line inc fShifted ; cld ; String instructions go forward again jmp copytext ;
eltl: mov ax,100 ; Error E_LTL Line too long push ax ; call ERRORC ; mov di, begatom mov byte ptr [di], 0 ; Truncate line
etmEnd: mov ax, begatom ; Reset lbufp to point to start of next mov lbufp, ax ; token
hRet hEndp
endif ;M8086OPT
ifdef MSDOS ifdef M8086OPT
;*** farwrite - write with far buffer ; farwrite(ofh,buf,count);
hProc <farwrite far>, handle:word, buffer:dword, count:word
mov ax,handle mov cx,count push ds lds dx,buffer mov bh,40h ; write xchg ax,bx ifdef CPDOS push bx ; file handle push ds ; buffer (selector) push dx ; buffer (offset) push cx ; # bytes to read mov ax,@data push ax ; reply area (selector) mov ax,offset rarea push ax ; reply area (offset) call DosWrite else int 21h endif pop ds ifdef CPDOS or ax,ax mov ax, word ptr rarea jnz fwriterr else jc fwriterr endif cmp ax,count je fwriteok fwriterr: mov objerr,-1 fwriteok: hRet
hEndp endif ;M8086OPT endif
;*** farAvail ()
ifdef MSDOS ifndef CPDOS
hProc <farAvail far>
or Bx,0FFFFH ;request max memory from dos mov ah,48H ;paragraphs left in Bx int 21H
mov ah,48H ;then allocate it int 21H jnc noMem xor Bx,Bx noMem: mov Ax,16 cwd mul Bx ;return paragraphs * 16 hRet
hEndp
endif endif
end
|