📄 doexec.asm
字号:
page ,132
title doexec -- (xenix) exec a child process
;***
;doexec.asm - execute a child process
;
; Copyright (c) 1985-1988, Microsoft Corporation. All rights reserved.
;
;Purpose:
; defines _doexec() - execute a child process (overlay existing process)
; This is complicated and involves some knowledge of DOS
; arena headers.
;
;*******************************************************************************
?DF = 1 ; tell cmacros.inc we want to define our own segments
.xlist
include version.inc
include cmacros.inc
include msdos.inc
.list
assumesdata macro seg ;;[1] Newer versions of CMACROS reject
assumes seg,DGROUP ;;[1]
endm ;;[1]
createSeg _TEXT, code, word, public, CODE, <>
createSeg _DATA, data, word, public, DATA, DGROUP
createSeg EXEC, eseg, word, common, DATA, DGROUP
defGrp DGROUP ; define DGROUP
codeOFFSET equ offset _TEXT:
dataOFFSET equ offset DGROUP:
l macro nam ;;[1] Conditionally make label public
nam: ;;[1]
endm ;;[1]
arena struc ; first 5 bytes of the arena header
sig db 0 ; 'M' or 'Z' for last block
own dw 0 ; PSP value of owner process or 0 if free
asiz dw 0 ; size of block (not including header)
arena ends
extrn b$EX_MSG_BEG:FAR ;[1]
extrn b$EX_MSG_END:FAR ;[1]
sBegin data
assumesdata ds ;[1]
externW _psp ; psp segment
externB _osmajor ; dos major version number
externW _sigintseg ; SIGINT default signal handler (segment)
externW _sigintoff ; SIGINT default signal handler (offset)
globalW _p_overlay,2 ; OLD_P_OVERLAY value
staticW freepsp,0 ; arena of last free segment contiguous with PSP
staticW emsg,<2+ OFFSET b$EX_MSG_BEG> ;[1] +2 to skip first msg number
staticW emsgseg,<SEG b$EX_MSG_BEG> ;[1]
staticW emsgln,<OFFSET b$EX_MSG_END>;[1] must subtract emsg from it
staticD target,0 ; for long jump to 'exec code'
sEnd
FCB1 = 5ch ; offset in psp
FCB2 = 6ch
DOS2CMD= 280h ; size of DOS 2.0 non-resident COMMAND.COM
externP execve
sBegin eseg
dd execve ; force in execve() if called from spawnve
sEnd
sBegin code
assumes cs,code
assumesdata ds ;[1]
page
;***
;_doexec - execute a child process (overlay existing)
;
;Purpose:
;
;Entry:
;
;Exit:
;
;Uses:
;
;Exceptions:
;
;*******************************************************************************
cProc _doexec,<PUBLIC>,<si,di>
parmw flag
parmdp nam
parmw nlength
parmdp command
parmdp envblock
parmw elength
parmw siz
parmw initss
parmw initsp
parmw initcs
parmw initip
parmw fsiz
cBegin
; exec overlays the current process using its PSP and all memory
; above it.
push ds ; save DGROUP
; check for trashed arena before we go on - will assume OK from here on
; DGROUP is on the top of the stack
assumes ds,nothing
l checkmem
pop ds ; restore DGROUP
assumesdata ds ;[1]
mov bx,-1 ; request max memory
callos allocmem ; will always fail
cmp al,E_arena
je ov0 ; arena is trashed
; find out how much contiguous memory there is that is either free
; or belongs to the current process
mov bx,[_psp]
mov dx,bx ; dx = current owner
dec bx ; bx = current arena header
xor cx,cx ; last free block in contiguous area
push ds ; save DGROUP
l maxloop
assumes ds,nothing
mov ds,bx ; ds = current arena
mov ax,ds:[own]
cmp ax,dx ; do we own it?
je maxadd ; yes - count it
or ax,ax ; is it free?
jne maxend ; no - end of contiguous memory
mov cx,bx ; last free block of memory
l maxadd
inc bx
add bx,ds:[asiz]
jc checkmem ; carry - assuming arena is trashed
mov al,ds:[sig] ; get arena signature
cmp al,'M' ; are we at end of memory?
je maxloop ; no - have good next block
cmp al,'Z' ;
jne checkmem ; unknown sig byte - assuming arena is trashed
; bx = top of contiguous area for current process
; cx = last free segment contiguous with PSP
l maxend
sub bx,dx ; bx = size
pop ds ; restore DS
assumesdata ds ;[1]
mov [freepsp],cx ; save last free segment contiguous with PSP
cmp [_osmajor],2 ; see if 2.x or above
ja nohole ; 3.x or above, don't need hole for loader
sub bx,DOS2CMD+1 ; leave 280h paras (10K) for the system's loader
jnc nohole ; enough space
;----- memory overflow or error before user memory is released
l ov
mov ax,E_nomem ; not enough memory
l ov0
mov AH,4CH ;[1]get code to terminate
INT 21H ;[1]immediate termination
;-----
l nohole
; see how big the exec code will be. it must sit in hi mem. it consists of
; code between a: and z: below (or b: and y: for .coms), the filename, (in the
; case of .exe files) a para of data (initial register values), and some room
; (160 bytes) for a local stack
STKSIZ= 160
exesz= z-a
exeln= exesz + STKSIZ ; .exe loader size + stack
comsz = y-b
comln= comsz + STKSIZ ; .com loader size + stack
push bx ; save max length possible
sub [emsgln],offset b$EX_MSG_BEG ;[1] compute message length
mov ax,[emsgln] ;[1] need emsgln in calculations
add ax,BYTE PTR exeln ;[2] assume .exe
cmp flag,0
je join0 ; was .exe
___tmp= comln-exeln
add ax,BYTE PTR ___tmp ;[2] was .com
l join0
mov cl,4
add ax,nlength ; plus filename
add ax,0fh ; exec code rounded up to next para
shr ax,cl ; (ax) = paras for exec code
mov dx,elength ; new env length (in bytes)
add dx,0fh ; env rounded up to next para
shr dx,cl ; (dx) = paras for new env
pop bx ; restore the maximum length to bx
; ax = exec code + data size
; dx = environment size
; bx = PSP contiguous size
sub bx,dx ; reduce PSP by environment segment
jbe ov
sub bx,2 ; reduce by 2 (arena header + DOS 4.0 slop)
jc ov
; bx = PSP contiguous size
mov cx,siz ; cx = assumed .exe size
cmp flag,0 ; .exe or .com?
je join1 ; was .exe
mov cx,fsiz ; size of .com child in paras
inc cx ; plus para for stack
jz ov
l join1
add cx,10h ; child must have a PSP
jc ov
; ax = exec code + data size
; cx = minimum size of child
; bx = PSP contiguous size
cmp bx,cx ; enough for child?
jb ov ; no
push ax ; save exec code size
push dx ; save env size
; allocate and link all free memory in the system
; assume the arena is good here and all errors are not enough memory
xor cx,cx ; cx = free link
l allocloop
mov bx,1 ; allocate 1 paragraph block
callos allocmem
jc allocall ; all linked up
mov es,ax ; es = segment to allocate
mov bx,-1 ; bx = maximum request
l allocretry
callos setmem ; grow segment
jc allocretry ; force it to be allocated
mov es:[0],cx ; save last free block
mov cx,es ; cx = current free link
mov dx,bx ; dx = size of last block
jmp allocloop ; keep allocating
l allocall
mov bx,dx
; es = cx = free segment linked list
; bx = size of last free block
cmp [_osmajor],2 ; check for DOS 2.0
jne allocenv ; no - just try allocing environment
sub bx,DOS2CMD+1 ; size to cut back
jnc shrinkdos2
;----- release all "free" blocks because of error
l freefree ; free all linked up "free" memory
jcxz allfree
mov es,cx
mov cx,es:[0] ; next free block
callos freemem
jnc freefree ; keep freeing linked blocks
l allfree ; if freemem error, just give up
jmp ov ; fail with no memory error
;-----
l shrinkdos2
callos setmem
jc freefree ; any error at this point is no memory
; es = cx = free segment linked list
; bx = size of last free block
l allocenv
pop dx ; dx = environment size
push dx
inc dx
inc dx ; dx = envsize + 2 (for arena header + DOS 4.0)
sub bx,dx
jnc haveenv ; have space in this block for environment
; no space for environment in this block - try end of PSP contiguous area
mov ax,[freepsp] ; ax = last free segment in PSP-contiguous area
or ax,ax
jz tryotherfree ; none here - try other free blocks
inc ax ; convert arena address to segment address
mov es,ax
mov bx,-1
callos setmem ; find size of segment
cmp al,E_nomem
jne freefree ; must be something like arena trashed
sub bx,dx ; enough room?
jnc haveenv ; yes - do actual environment allocation
; else go try somewhere else
; try other free blocks if above attempts fail
l tryotherfree
jcxz allfree
mov ax,cx
;
; dx = environment size in paragraphs + 2 (for arena hdr + DOS 4.0 slop)
; cx = pointer to beginning of "free" list (segment address)
; ax = pointer into "free" list (segment address)
;
l tryotherloop
dec ax ;[1] AX = header address (temporarily)
mov es,ax ; header of current free block
mov bx,es:[asiz] ; size of current free block (in header)
inc ax ;[1] convert header addr back into seg addr
mov es,ax ;[1] AX = ES = segment address
sub bx,dx ; will environment fit?
jnc haveenv ; yes - do actual environment allocation
mov ax,es:[0] ; else go on to next free block
or ax,ax ; end of list?
jz freefree ; yes - not enough memory; clean up and fail
jmp short tryotherloop ; keep trying
; es = segment to shrink for environment
; bx = size to which to shrink chosen "free" segment
l haveenv
callos setmem
jc freefree ; any error at this point is no memory
pop bx
callos allocmem ; allocate environment segment
jc freefree ; any error at this point is no memory
; ax = environment segment
mov es,[_psp]
mov bx,es
mov es:[DOS_envp],ax ; new env segment
mov es,ax
xor di,di ; es:di points to new env
if sizeD
push ds ; save DGROUP
lds si,envblock
else
mov si,envblock
endif
mov cx,elength
rep movsb ; move env to new segment
if sizeD
pop ds ; restore DGROUP
endif
mov dx,es ; dx = environment segment
; bx = PSP
; dx = environment segment
push dx ; save needed registers
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -