📄 doexec.asm
字号:
push bx
cmp _sigintseg,0 ; has ^C been hooked ?
je letsgo ; no, do the exec
push ds
mov dx,_sigintoff ; load system default address
mov ds,_sigintseg ; load system default segment
mov ax,DOS_setvector shl 8 + 23H ; reset ^C vector (INT 23H)
callos
pop ds ; restore registers
l letsgo
;
; IMPORTANT NOTE:
;
; DOS 3.30 and later allow the user to increase the size of the
; file handle table. If the file handle count > 20, then a far
; segment is allocated to store the table. This segment must be
; freed up before the child program is exec-ed. This code relies
; on the fact that DOS will free up that far segment if the handle
; count is set back to 20. If DOS ever changes, this code will fail.
;
mov ax,word ptr [_osmajor]
xchg ah,al ; AH = _osmajor, AL = _osminor
cmp ax,(3 shl 8) + 30
jb pre_DOS330 ; _osmajor:_osminor < 3:30?
mov bx,20 ; IF >= DOS 3.30 THEN
mov ah,67h ; Set Handle Count on principle
callos ; set number of handles to default value
pre_DOS330:
pop bx
pop dx
; WARNING - any errors past this point - must go to execpanic
; now free all blocks of memory belonging to this process
; except the PSP and new environment block
; bx = PSP
; dx = environment segment
l freemore
push bx ; save PSP
mov ah,52h ; magic DOS call
int 21h
mov ax,es:[bx-2] ; ax = first arena segment!!!
pop bx ; restore PSP
; ax = current segment to check
l findused
mov es,ax
inc ax
cmp ax,bx ; is it PSP?
je atend ; yes - skip
cmp ax,dx ; is it environment?
je atend ; yes - skip
cmp es:[own],bx ; do we own it?
jne atend ; no -skip
mov es,ax ; es = must be one past arena header
callos freemem ; free up the segment
jmp freemore ; and start over - even if error
l atend
add ax,es:[asiz] ; add in segment size
jc freemore ; error - changed arena - retry
cmp es:[sig],'Z' ; last segment?
jne findused ; no - check next segment
; increase size of PSP to maximum amount available
;
; bx = PSP
mov es,bx ; es= PSP
mov bx,-1
callos setmem
callos setmem ; allocates on second try
jnc bigPSP
l execpanic ; error in exec after memory freed
mov dx,word ptr [emsg] ;[1] DS:DX = "Not enough memory"
mov ax,word ptr [emsgseg] ;[1]
mov ds,ax ;[1]
callos message
mov ax,DOS_terminate shl 8 + 255
callos ; error code = 255
l bigPSP
mov ax,es
add ax,bx ; bx = size of PSP block
mov es:[DOS_maxpara],ax ; set new memory limit in PSP
; ax = top of PSP segment
; ((sp)) = (exec code size)
pop cx ; cx = exec code size
sub bx,cx ; reduce PSP size
jc execpanic
sub ax,cx
mov word ptr [target+2],ax ; set up final jump address
; move the exec code and its data up to hi mem
;
; ax = exec code segment
mov es,ax ; es = exec code segment
push es ; save exec code segment
push ds ; save DGROUP
push cs
pop ds ; ds points into code segment
xor di,di
mov cx,BYTE PTR exesz ;[1] assume exe file
mov si,codeOFFSET a
cmp flag,0 ; .exe or .com?
je exe4 ; .exe
mov cx,BYTE PTR comsz ;[1]
mov si,codeOFFSET b
l exe4
rep movsb ; move code to exec code segment
pop ds ; restore DGROUP
push ds ;[1] save DGROUP
mov cx,[emsgln] ;[1] count of bytes to move
mov si,word ptr [emsg] ;[1] DS:SI = start of 3 error messages
mov ax,word ptr [emsgseg] ;[1]
mov ds,ax ;[1]
rep movsb ;[1] move 3 error messages
pop ds ;[1] restore DGROUP
mov bx,di ; (bx) = offset of data/name (save)
cmp flag,0 ; .exe or .com?
jne com5 ; .com
; for .exe save initial register values
mov ax,initss
stosw
mov ax,initsp
stosw
mov ax,initcs
stosw
mov ax,initip
stosw
l com5
if sizeD
push ds ; save DGROUP
lds si,nam
else
mov si,nam
endif
mov cx,nlength
rep movsb ; move name
if sizeD
pop ds ; restore DGROUP
endif
; exec code and its data are in hi mem. set the dma and fix the psp (the
; command line at offset 80h, and the fcbs)
mov es,[_psp] ; psp seg
; set the dma to psp:80h
push ds ; save DGROUP
push es
pop ds ; psp segment
mov dx,80h ; default dma=psp:80h
callos setdma
pop ds ; restore DGROUP
; set up the command line
mov di,DOS_cmdline
if sizeD
push ds ; save DGROUP
lds si,command
else
mov si,command
endif
mov cl,[si] ; length of command
inc cx ; (ch) = 0 from last rep movsb (name)
inc cx ; count byte & terminating <cr>
rep movsb ; move the command line into psp:80h
; set up the fcbs
mov dx,bx ; (dx) = data/name offset
mov di,FCB1 ; fcb at offset 5ch
xchg ax,cx ; null byte to store
; (cx) = 0 from last rep movsb (command line)
mov cx,20h ; length of 2 fcbs
rep stosb ; zero the fcbs
mov di,FCB1 ; fcb at offset 5ch
if sizeD
lds si,command
else
mov si,command
endif
inc si ; si points to arg1 (or space before it)
mov ax,DOS_fcbparse shl 8 + 1
callos ; parse filename
cmp al,0ffh ; see if invalid drive letter
je bad1
xor al,al
l bad1
mov bl,al ; first drive letter
mov di,FCB2 ; second fcb in psp
mov ax,DOS_fcbparse shl 8 + 1
callos ; parse filename
cmp al,0ffh ; see if invalid drive letter
je bad2
xor al,al
l bad2
mov bh,al ; bx = drive letter flags
if sizeD
pop ds ; restore DGROUP
endif
; setup stack in exec code segment
pop cx ; exec code segment
mov si,dx ; data/name offset in exec code
add si,STKSIZ ; push it up to produce a stack
cmp flag,0 ; .exe or .com? (last frame reference)
mov bp,bx ; initial ax
cli ; disable interrupts until stack set up
mov ss,cx
mov sp,si
sti ; temporary stack set up
jne join6 ; was .com
push dx ; save data offset to init. register values
add dx,8 ; name offset in hi mem
l join6
mov ax,es ; (ax) = paras from 0:0 to psp:0
add ax,10h ; (ax) = paras from 0:0 to parameter block
mov bx,100h ; psp:100h is parameter block for load/exec
mov es:[bx],ax ; word segment address to load at
mov es:[bx+2],ax ; word relocation factor to be applied
push ax ; save relocation factor
mov ax,DOS_exec shl 8 + 3
; (ax) = dos code for load/exec (4b03h)
; (dx) = name offset in exec segment
; (es:bx) = psp:100 (parameter block)
; (ds) = DGROUP seg
; (bp) = initial ax
;
; di and si are free
jmp dword ptr [target] ; and away we go!
;-----------------------------------------------------------------------------
NOMEM equ 5
BADFORM equ 6
BADENV equ 7
execom macro lab,fil
l lab
push cs
pop ds ; DS = exec code segment
callos ; overlay parent with child
jnc allok&lab
mov bx,BADFORM - NOMEM
cmp al,E_ifunc ; invalid format
je die&lab
mov bl,BADENV - NOMEM
cmp al,E_badenv ; bad environment
je die&lab
mov bl,BADFORM - NOMEM
cmp al,E_badfmt ; bad format
je die&lab
xor bx,bx ; NOMEM - NOMEM
l die&lab
push cs
pop es ; es = exec code segment
xor ax,ax
mov cx,-1
mov di,BYTE PTR fil&sz ;[2]
or bx,bx
jz outmsg&lab
jmp short nmsg&lab
; Warning if you change this section above you must
; leave the following bytes for DOS 2.0 to walk all
; over without walking on data DOS walks on DS:2E to
; DS:31 extra slop just incase!
org lab + 32h
l nmsg&lab
repne scasb
inc di ; skip past message number
inc di
dec bx
jnz nmsg&lab
l outmsg&lab
mov dx,di
callos message
mov ax,DOS_terminate shl 8 + 255
callos ; terminate (255)
l allok&lab
endm
;-----------------------------------------------------------------------------
;
; .exe exec code
execom a,exe ; expand for .exe file
pop di ; relocation factor
pop si ; data offset of initial register values
lodsw ; initss
add ax,di ; relocation factor (paras) from 0:0
xchg dx,ax
lodsw ; initsp
cli
mov ss,dx ; reloc'd ss
mov sp,ax
sti
lodsw ; initcs
add di,ax
lodsw
push di ; save INIT CS
push ax ; save INIT IP
push es
pop ds ; es = ds = PSP
mov ax,bp ; ax = valid drive letter flags
xglobal proc far
ret ; force far return to dos int 21h handler
xglobal endp
z:
;-----------------------------------------------------------------------------
;
; .com exec code
execom b,com ; expand for .com file
pop di ; burn relocation factor (not used)
mov bx,cs ; get exec code segment
mov ax,es ; get PSP segment
sub bx,ax ; bx = size of program area (in paragraphs)
mov cl,4
test bx,0f000h ; will we lost precision when we shift?
jz doit
mov bx,1000h ; yes, set ss:sp = psp:0000
doit:
shl bx,cl ; make byte offset from psp:0
dec bx
dec bx
cli ; disable interrupts until stack's ok
mov ss,ax
mov sp,bx ; reserved para offset (stack grows down)
sti ; enable interrupts; stack's ok now
mov word ptr ss:[bx],0 ; put 0000 on top of stack for return
push es
mov ax,100h
push ax ; INIT CS:IP = PSP:100h
push es
pop ds ; DS = ES = CS = PSP
mov ax,bp ; ax = valid drive letter flags
cglobal proc far
ret ; force far return
cglobal endp
y:
cEnd nogen
sEnd
end
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -