windows-nt/Source/XPSP1/NT/base/mvdm/wow16/kernel31/ldutil.asm
2020-09-26 16:20:57 +08:00

1323 lines
24 KiB
NASM

TITLE LDUTIL - Loader support procedures
.xlist
include kernel.inc
include newexe.inc
include tdb.inc
include protect.inc
.list
;externFP GetCurrentPDB
if ROM and PMODE32
externFP HocusROMBase
endif
DataBegin
;externB Kernel_Flags
;externW AltfEEMS
externW headTDB
externW hExeHead
;externW pGlobalHeap
;externW MyCSDS
externW topPDB
externW cur_dos_pdb
externW Win_PDB
externW curTDB
;externW segSwapArea
DataEnd
externFP CallWEP
sBegin CODE
assumes CS,CODE
assumes DS,NOTHING
assumes ES,NOTHING
externNP MyUpper
externNP MyLock
externNP LoadNRTable
externNP LoadSegment
externNP GetOwner
externNP GetCachedFileHandle
if SDEBUG
externNP DebugFreeSegment
endif
externFP IGlobalAlloc
externFP IGlobalFree
;externFP IGlobalLock
externFP IGlobalUnfix
externFP IGlobalHandle
externFP GlobalFlags
externFP FreeNRTable
externFP Int21Handler
ifdef FE_SB ;declare it.
externNP MyIsDBCSLeadByte ;Use near one as we are in the same seg
endif
if ROM
externFP FreeSelector
externNP alloc_data_sel16
endif
cProc SafeCall,<PUBLIC,FAR>
parmD Addr
cBegin
call Addr
cEnd
;-----------------------------------------------------------------------;
; GetExePtr ;
; ;
; Returns the exe header pointer for the passed handle. ;
; ;
; Arguments: ;
; parmW hinstance ;
; ;
; Returns: ;
; ;
; Error Returns: ;
; AX = 0 ;
; ;
; Registers Preserved: ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; ;
; History: ;
; ;
; Mon Aug 03, 1987 04:40:45p -by- David N. Weise [davidw] ;
; Rewrote it to work with expanded memory. Note that if the handle ;
; passed is truly bogus we could still catch a page fault under ;
; Win386. ;
;-----------------------------------------------------------------------;
assumes ds, nothing
assumes es, nothing
cProc GetExePtr,<PUBLIC,FAR>
parmW hinstance
cBegin
mov ax,hinstance
test ax,GA_FIXED ; Passed a segment address?
jz not_module
mov es,ax
cmp es:[ne_magic],NEMAGIC ; Yes, does it point to a Module?
jz gxdone
not_module:
SetKernelDS es
mov cx,headTDB
assumes es, nothing
find_TDB:
jcxz last_chance
mov es,cx
cmp ax,es:[TDB_module]
jz found_it
mov cx,es:[TDB_next]
jmp find_TDB
found_it:
mov ax,es:[TDB_pModule]
jmps gxdone
last_chance: ; The problem here is that USER
cCall MyLock,<ax> ; KNOWS that hinstance is but
or ax,ax ; the handle to his data segment.
jz gxdone
mov es,ax
cmp es:[ne_magic],NEMAGIC
je gxdone
cCall GetOwner,<ax>
or ax,ax
jz gxfail
mov es,ax
cmp es:[ne_magic],NEMAGIC
je gxdone
; The owner,ax, is now a PDB. We gotta find the TDB
SetKernelDS es
mov cx,headTDB
assumes es, nothing
find_PDB:
jcxz gxfail
mov es,cx
cmp ax,es:[TDB_PDB]
jz found_PDB
mov cx,es:[TDB_next]
jmp find_PDB
found_PDB:
mov ax,es:[TDB_pModule]
jmps gxdone
gxfail:
if KDEBUG
xor cx,cx
kerror ERR_LDMODULE,<Invalid module handle>,cx,hinstance
endif
xor ax,ax
gxdone: mov cx,ax
cEnd
;-----------------------------------------------------------------------;
; ;
; GetExpWinVer - return the expected Windows version for a given ;
; module handle ;
; ;
; Arguments: ;
; parmW hinstance ;
; ;
; Returns: ;
; AX = expected windows version ;
; DX = BOOL proportional font flag ;
; ;
; Error Returns: ;
; AX = 0 ;
; ;
; Registers Preserved: ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; ;
; History: ;
; ;
; Fri 06 Jan 1989 -- Written by Sankar. ;
; ;
;-----------------------------------------------------------------------;
assumes ds, nothing
assumes es, nothing
cProc GetExpWinVer,<PUBLIC,FAR>, <si,di>
parmW hInstance
cBegin
cCall GetExePtr,<hInstance>
or ax,ax
jz err_GetExpWinVer
mov es,ax
mov ax,es:[ne_expver]
mov dx,es:[ne_flags]
and dx,NEWINPROT
; error if offsets don't match our defines - In which case find the right
; offsets and changes the defines in mvdm\inc\tdb16.h
.erre (NE_LOWINVER_OFFSET EQ ne_expver)
.erre (NE_HIWINVER_OFFSET EQ ne_flags)
err_GetExpWinVer:
cEnd
;-----------------------------------------------------------------------;
; MyAlloc ;
; ;
; Private interface to memory manager ;
; ;
; Arguments: ;
; parmW aflags ;
; parmW nsize ;
; parmW nelem ;
; ;
; Returns: ;
; ;
; Error Returns: ;
; AX = Handle ;
; DX = Seg Address ;
; ;
; Registers Preserved: ;
; DI,SI,DS ;
; ;
; Registers Destroyed: ;
; BX,CX,ES ;
; ;
; Calls: ;
; GlobalAlloc ;
; MyLock ;
; ;
; History: ;
; ;
; Wed Apr 08, 1987 06:22:57a -by- David N. Weise [davidw] ;
; Wrote it. ;
;-----------------------------------------------------------------------;
assumes ds, nothing
assumes es, nothing
cProc MyAllocLinear,<PUBLIC,NEAR>
; Same as MyAlloc, except for size parameter
parmW aflags
parmD dwBytes
cBegin
jmps MyAllocNBD
cEnd
assumes ds, nothing
assumes es, nothing
cProc MyAlloc,<PUBLIC,NEAR>
parmW aflags
parmD dwBytes
; parmW nsize
; parmW nelem
cBegin
xor dx,dx
mov ax,seg_dwBytes ;nsize
mov cx,off_dwBytes ;nelem
jcxz ma3
ma2:
shl ax,1
rcl dx,1
loop ma2
ma3:
mov seg_dwBytes, dx
mov off_dwBytes, ax
MyAllocNBD:
SetKernelDS es
mov cx,aflags
mov al,NSTYPE
and al,cl ; al has SEGTYPE
mov bx,NSDISCARD
and bx,cx
jz @F
shr bx,1
shr bx,1
shr bx,1
shr bx,1 ; BX has GA_DISCARDABLE
cmp al,NSCODE
jne @F
or bl,GA_DISCCODE ; Allocating discardable code
@@:
cmp al,NSDATA
jne @F
and cx,NOT NSWINCODE ; undo Excel bogusness
or bl,GA_DGROUP ; Allocating automatic data segment
@@:
test cl,NSMOVE
jz @F
or bl,GA_MOVEABLE
@@:
cmp al,NSTYPE
jz @F
or bh,GA_CODE_DATA
@@:
cCall IGlobalAlloc,<bx,dwBytes> ;dxax>
assumes es, nothing
push ax
test al,GA_FIXED
jnz @F
cCall MyLock,<ax>
@@:
pop dx
cEnd
;
; MyLock( hseg ) - Procedure to return the physical segment address of
; the passed handle.
;
;;;cProc MyLock,<PUBLIC,NEAR>
;;; parmW hseg
;;;cBegin
;;; cCall IGlobalHandle,<hseg>
;;; xchg dx,ax
;;;cEnd
;-----------------------------------------------------------------------;
; MyFree ;
; ;
; Frees a segment allocated by MyAlloc. ;
; ;
; Arguments: ;
; ;
; Returns: ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; ;
; History: ;
; ;
; Tue Dec 09, 1986 12:48:43p -by- David N. Weise [davidw] ;
; Added this nifty comment block. ;
;-----------------------------------------------------------------------;
assumes ds, nothing
assumes es, nothing
cProc MyFree,<PUBLIC,NEAR>
parmW hseg
localW pseg
cBegin
mov bx,hseg
or bx,bx
jz mf3
mov ax,bx
xor cx,cx
test bl,GA_FIXED
jnz mf0a
push bx
cCall GlobalFlags,<bx>
mov cx, ax
xor ax, ax
pop bx
xchg ch, cl
test cl, HE_DISCARDED
jnz mf0a
mov ax, bx
HtoS ax
mf0a:
if KDEBUG
push cx
endif
mov pseg,ax
or ax,ax
jz mf1
mf0:
if SDEBUG
cCall DebugFreeSegment,<pseg,0>
endif
mf1:
if KDEBUG
pop cx
or ch,ch
jz mf2
mf1a:
push cx
cCall IGlobalUnfix,<hseg> ; Prevent RIP if freeing locked DS
pop cx
dec ch
or ch,ch ; If still lock, do it again
jnz mf1a
endif
mf2:
cCall IGlobalFree,<hseg>
mf3:
cEnd
;-----------------------------------------------------------------------;
; EntProcAddress
;
; Returns the fixed address of a procedure.
;
; Entry:
;
; Returns:
; DX:AX = thunk for moveable
; DX:AX = procedure for fixed
; AX = constant, ES:BX => constant for absolutes
; Registers Destroyed:
;
; History:
; Wed 30-Nov-1988 19:39:05 -by- David N. Weise [davidw]
;
;-----------------------------------------------------------------------;
assumes ds, nothing
assumes es, nothing
cProc EntProcAddress,<PUBLIC,NEAR>,<si,di>
parmW hExe
parmW entno
if KDEBUG
parmW bNoRip ; if 1 don't RIP for error, 0 -> do the RIP
endif
cBegin
mov es,hExe
mov cx,entno
and cx,7fffh ; clear ResidentName bit (#5108 donc)
jcxz entfail
dec cx
mov si,es:[ne_enttab]
entloop:
mov ax, es:[si.PM_entstart]
cmp cx, ax ; Below this block?
jb entfail ; yes, must be invalid!
cmp cx, es:[si.PM_entend] ; Above this block?
jae entnext ; yes, go to next block
sub cx, ax ; Found the right block, get offset
mov bx, cx
shl cx, 1
add bx, cx
add bx, cx ; bx = cx*5
lea si, [si+bx+size PM_entstruc]
mov bx, si
jmps gotent
entnext:
mov si, es:[si.PM_entnext] ; Next block
or si, si
jnz entloop
jmps entfail
entfail:
if KDEBUG
cmp bNoRip,0
jnz dont_rip_here
mov bx,entno
krDebugOut <DEB_WARN or DEB_krLoadSeg>, "Invalid ordinal reference (##BX) to %ES1"
; kerror ERR_LDORD,<Invalid ordinal reference to >,es,bx
dont_rip_here:
endif
xor dx,dx
xor ax,ax
jmps entdone
; Here if the current block has the entry we want
gotabs:
add bx,pentoffset ; make ES:BX point to constant (SLIME!)
mov dx,-1 ; make != 0 since abs might be!
jmps gotent1 ; Offset is symbol value
gotent:
xor ax, ax
mov al, es:[bx].penttype ; Get segno/type field
mov si,es:[bx].pentoffset
cmp al,ENT_ABSSEG ; If segno field absoulute segment
je gotabs ; Yes, have absolute symbol
cmp al, ENT_MOVEABLE
je gotmoveable
.errnz 10 - SIZE NEW_SEG1
; ax = segno
push bx
mov bx, es:[ne_segtab] ; see if really fixed
mov cx, ax ; look up in seg table
dec cx
shl cx, 1 ; get segtable + (segno-1)*10
add bx, cx
shl cx, 2
add bx, cx
test es:[bx].ns_flags, NSMOVE + NSALLOCED
pop bx
jnz gotmoveable
mov cx,-1 ; Fixed, make sure it's loaded
cCall LoadSegment,<es,ax,cx,cx>
or ax,ax
mov dx,ax
jnz gotent1
jmp entfail
gotmoveable:
xor ax,ax
mov al,es:[bx].pentsegno ; Segment number
dec ax
shl ax,1
mov di,ax
shl ax,2
add di,ax
.errnz 10 - SIZE NEW_SEG1
add di,es:[ne_segtab]
mov dx,es:[di].ns_handle
or dx, dx
jnz ok
mov ax, dx ; No handle, probably from an aborted
jmps entdone ; LoadModule - just return 0:0
ok:
Handle_To_Sel dl
gotent1:
mov ax,si
entdone:
mov cx,ax
or cx,dx
cEnd
;-----------------------------------------------------------------------;
; FindOrdinal ;
; ;
; Searches the resident and non-resident name tables for a procedure ;
; name and return its corresponding entry ordinal. ;
; ;
; Arguments: ;
; parmW hExe ;
; parmD lpname pointer name, strings starts with length ;
; parmW fh file handle NOT to be discarded from cache ;
; ;
; Returns: ;
; AX = ordinal number ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; MyUpper ;
; LoadNRTable ;
; FreeNRTable ;
; ;
; History: ;
; ;
; Tue 09-May-1989 18:38:04 -by- David N. Weise [davidw] ;
; Added the batching if out of memory. ;
; ;
; Thu Sep 17, 1987 08:55:05p -by- David N. Weise [davidw] ;
; Added this nifty comment block and fixed it. ;
;-----------------------------------------------------------------------;
assumes ds, nothing
assumes es, nothing
CLNRBUFFER equ 150
cProc FindOrdinal,<PUBLIC,NEAR>,<si,di>
parmW hExe
parmD lpname
parmW fh
if ROM
localW fInROM
endif
localD oNRTable ; if batching, continue here
localV LoadNRbuffer,CLNRBUFFER ; if batching this is temp buffer
cBegin
xor ax,ax
mov oNRTable.hi,ax
mov oNRTable.lo,ax
if ROM
mov fInROM,ax ; assume module not in ROM
endif
les si,lpname
cmp byte ptr es:[si+1],'#'
je foint
fonorm: push ds
mov ds,hExe
if ROM
test ds:[ne_flags],NEMODINROM ; is module actually in ROM?
jz @f
inc fInROM
@@:
endif
mov si,ds:[ne_restab]
cld
foinit: xor ax,ax ; Skip module name or description
lodsb
add si,ax
inc si
inc si
foloop: lodsb ; get length of entry
les di,lpname
mov cx,ax
jcxz fodone ; no more entries?
cmp es:[di],al ; do lengths match?
jne noteq
inc di
fo_find:
mov al,es:[di]
call MyUpper
mov bl,ds:[si]
inc si
inc di
cmp al,bl
jne noteq1
loop fo_find
; repe cmpsb
; jne noteq
lodsw ; get ordinal number!
mov bx,ds
pop ds
cmp hExe,bx ; did we load the nrtable?
jnz foexit_j
jmp foexit1
foexit_j:
jmp foexit
noteq1: dec cx
noteq: add si,cx
inc si
inc si
jmps foloop
; Here if pName points to string of the form: #nnnn
foint: lods byte ptr es:[si] ; nbytes = *pName++
mov cl,al
xor ch,ch
dec cx ; ignore #
inc si
xor ax,ax ; sum = 0
foint0: mov dx,ax
lods byte ptr es:[si] ; c = *pName++
sub al,'0' ; if (!isdigit(c))
cmp al,9
ja fonorm ; treat like normal
xor ah,ah
mov bx,ax ; sum = (sum * 10) + (c - '0')
mov al,10
mul dx
add ax,bx
loop foint0
jmp foexit1
fodone: mov bx,ds
pop ds
;%out help me ; what was this line for?
mov cx,oNRTable.hi
cmp cx,oNRTable.lo
jnz fo_batching
cmp hExe,bx ; have we looked at NRTable yet?
if ROM
jne foexit_j
else
jne foexit
endif
if ROM
cmp fInROM,0 ; this module in ROM?
jz fo_nr_not_in_rom
cCall FindROMNRTable,<hExe> ; yes, get selector to ROM NR Table
mov fInROM,ax
push ds
mov ds,ax ; ds -> ROM NR table
xor bx,bx
mov bl,ds:[0] ; skip over first NR table entry
lea si,[bx+3] ; (the module description string)
xor ax,ax
jmp foloop
fo_nr_not_in_ROM:
endif
fo_batching:
xor bx,bx
mov ax,fh
;;; cmp ax,-1
;;; jz no_file_handle
SetKernelDS ES
;;; mov dx, topPDB
;;; mov es, curTDB
;;; UnSetKernelDS es
;;; mov ax, es:[TDB_PDB]
;;;
;;; cmp dx, cur_dos_pdb
;;; jz @F
;;; mov bx,ax
;;;@@:
mov bx, Win_PDB
UnSetKernelDS
mov dx, -1
cCall GetCachedFileHandle,<hexe,ax,dx>
no_file_handle:
push bx
lea cx,LoadNRbuffer
mov dx,CLNRBUFFER
cCall LoadNRTable,<hexe,ax,oNRTable,ss,cx,dx>
if KDEBUG
push es
push di
les di, [lpName]
krDebugOut <DEB_TRACE or DEB_krLoadSeg>, " looking for @ES:DI"
pop di
pop es
endif
pop si
or si,si
jz @F
;;; push ax
;;; push bx
;;; mov bx,si
;;; mov ah,50h
;;; DOSCALL
;;; pop bx
;;; pop ax
push es
SetKernelDS ES
mov Win_PDB, si
pop es
UnSetKernelDS ES
@@: mov oNRTable.hi,cx
mov oNRTable.lo,bx
push ds
mov ds,dx
mov si,ax
or ax,dx ; did we get a table?
jz @F
xor ax,ax
jmp foloop
@@: pop ds
foexit: push ax
if ROM
cmp fInROM,0 ; this module in ROM
jz @f
cCall FreeSelector,<fInROM> ; yes, free ROM NR table selector
jmps foexit0
@@:
endif
mov ax,ne_nrestab
cCall FreeNRTable,<hExe,ax>
foexit0:
pop ax
foexit1:
;??? commented out 3/7/88 by rong
;??? we should put this back in once everyone has the new keyboard driver
;if KDEBUG
; or ax,ax
; jnz foexit2
; les bx,lpname
; inc bx
; kerror ERR_LDNAME,<Invalid procedure name >,es,bx
; xor ax,ax
;foexit2:
;endif
cEnd
if ROM ;----------------------------------------------------------------
;-----------------------------------------------------------------------
; FindROMNRTable
;
; Returns a selector to the ROM copy of the Non-Resident name table for
; a module stored in ROM.
;
; Arguments:
; parmW hExe
;
; Returns:
; AX = selector mapping NR table
;
;-----------------------------------------------------------------------
assumes ds, nothing
assumes es, nothing
cProc FindROMNRTable,<PUBLIC,NEAR>,<ds>
parmW hExe
cBegin
mov ds,hExe
mov ax,word ptr ds:[ne_nrestab]
mov bx,word ptr ds:[ne_nrestab+2]
cCall alloc_data_sel16,<bx,ax,1000h>
if PMODE32
cCall HocusROMBase, <ax>
endif
if KDEBUG
or ax,ax
jnz @f
int 3
@@:
endif
cEnd
endif ;ROM ---------------------------------------------------------
; Search the list of new EXE headers for the passed executable file name
; (no path)
;
; this must be resident so we can search for modules in the file handle
; cache from the int 21 handler -- craigc
;
cProc ResidentFindExeFile,<PUBLIC,FAR>,<ds,si,di>
parmD pname
cBegin
SetKernelDS
mov ax,hExeHead
ffloop:
or ax,ax
jz ffdone
mov es,ax
mov di,es:[ne_pfileinfo]
or di,di
jz ffnext
;
; Double Byte Character is not able to search from the end of string,
; so this function must search from the top of string.
;
ifdef FE_SB
lea si,[di.opFile] ; get address of file name
mov cl,es:[di.opLen] ; get structure length
xor ch,ch
add cx,di
mov di,cx ; save end address
sub cx,si ; get length of file name
mov bx,si ; save top address of file name
cld
delineator_loop:
lods byte ptr es:[si]
call MyIsDBCSLeadByte
jc delineator_notlead ; if not DBCS lead byte
dec cx
jcxz delineator_next
inc si
loop delineator_loop
jmp delineator_next
delineator_notlead:
cmp al,"\"
jz found_delineator
cmp al,":"
jz found_delineator
loop delineator_loop
jmp delineator_next
found_delineator:
mov bx,si ; save delineator address
loop delineator_loop
delineator_next:
xchg bx,di ; set address of file name to di
sub bx,di ; get lenfth of file name
else
mov si,di
xor cx,cx
mov cl,es:[di]
add si,cx
dec si
std
xor bx,bx
delineator_loop: ; look for beginning of name
lods byte ptr es:[si]
cmp al,"\"
jz found_delineator
cmp al,":"
jz found_delineator
inc bx
loop delineator_loop
dec si
found_delineator: ; ES:SI -> before name
mov di,si
inc di
inc di
endif
lds si,pname
UnSetKernelDS
mov cx,bx
cld
repe cmpsb
mov ax,es
je ffdone
ffnext:
mov ax,word ptr es:[ne_pnextexe]
jmp ffloop
ffdone:
cEnd
sEnd CODE
externFP FarLoadSegment
sBegin NRESCODE
assumes CS,NRESCODE
assumes DS,NOTHING
assumes ES,NOTHING
externNP DelModule
externNP MapDStoDATA
cProc FindExeFile,<PUBLIC,NEAR>
parmD pFile
cBegin
cCall ResidentFindExeFile, <pFile>
cEnd
; Search the list of new EXE headers for the passed executable name
cProc FindExeInfo,<PUBLIC,NEAR>,<ds,si,di>
parmD pname
parmW nchars
cBegin
cCall MapDStoDATA
ReSetKernelDS
mov bx,nchars
mov ax,hExeHead
feloop:
or ax,ax
jz fedone
mov es,ax
mov di,es:[ne_restab]
cmp es:[di],bl
jne fenext
inc di
lds si,pname
UnSetKernelDS
mov cx,bx
repe cmpsb
je fedone
fenext:
mov ax,word ptr es:[ne_pnextexe]
jmp feloop
fedone:
cEnd
cProc FarFindExeInfo,<PUBLIC,FAR>
parmD pname
parmW nchars
cBegin
cCall FindExeInfo,<pname,nchars>
cEnd
;
; IncExeUsage( hExe ) - procedure to increment the usage count of this
; EXE header. Indirectly increments the usage count of all the EXE
; headers it points to.
;
cProc IncExeUsage,<PUBLIC,NEAR>,<ax,di>
parmW hexe
cBegin
mov cx,hexe
jcxz iexj
mov es,cx
cmp es:[ne_magic],NEMAGIC
jne iexj
test es:[ne_usage],8000h
jz iego
iexj:
krDebugOut <DEB_ERROR or DEB_KRLOADMOD>, "IncExeUsage(#ES) not DLL"
jmp iex
iego:
cmp es:[ne_usage], 4000h
jb OKusage
krDebugOut DEB_FERROR, "IncExeUsage: ne_usage overflow"
OKusage:
;
; Save time and space by saving stuff on stack
; rather than recursing.
;
or es:[ne_usage], 8000h
NextExe0:
or es:[ne_usage], 4000h ; Mark node visited
inc es:[ne_usage]
;if kdebug
; push ax
; mov ax, es:[ne_usage]
; krDebugOut <DEB_TRACE or DEB_krLoadMod>, "IncExeUsage(%ES0) #ax"
; pop ax
;endif
mov cx,es:[ne_cmod]
jcxz NoDeps0
mov di,es:[ne_modtab]
ieloop:
push es
cmp word ptr es:[di], 0
je ieloop1
lar ax, es:[di] ; Make sure valid selector
jnz ieloop1
mov es, es:[di]
cmp es:[ne_magic],NEMAGIC
jne ieloop1
test es:[ne_usage], 0C000h
jnz ieloop1
push cx
push di ; Fake recursion
jmp NextExe0
NextExeDone0: ; Return from fake recursion
pop di
pop cx
ieloop1:
pop es
add di,2
loop ieloop
NoDeps0:
mov cx, es
cmp cx, hExe
jne NextExeDone0
NextExe1:
and es:[ne_usage], NOT 4000h ; Mark node visited
mov cx,es:[ne_cmod]
jcxz NoDeps1
mov di,es:[ne_modtab]
UnMarkLoop:
push es
cmp word ptr es:[di], 0
je UnMarkLoop1
lar ax, es:[di] ; Make sure valid selector
jnz UnMarkLoop1
mov es, es:[di]
cmp es:[ne_magic],NEMAGIC
jne UnMarkLoop1
test es:[ne_usage], 08000h
jnz UnMarkLoop1
test es:[ne_usage], 04000h
jz UnMarkLoop1
push cx
push di ; Fake recursion
jmp NextExe1
NextExeDone1: ; Return from fake recursion
pop di
pop cx
UnMarkLoop1:
pop es
add di,2
loop UnMarkLoop
NoDeps1:
mov cx, es
cmp cx, hExe
jne NextExeDone1
xor es:[ne_usage], 8000h
iex:
cEnd
;-----------------------------------------------------------------------;
; DecExeUsage ;
; ;
; Decrements the usage count of the given EXE header. Indirectly ;
; decrements the usage count of all the EXE headers it points to. ;
; ;
; Arguments: ;
; parmW hexe ;
; ;
; Returns: ;
; ZF = 1 if usage count is now zero. ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; DI,SI,DS ;
; ;
; Registers Destroyed: ;
; AX,BX,CX,DX,ES ;
; ;
; Calls: ;
; DecExeUsage ;
; DelModule ;
; ;
; History: ;
; ;
; Mon Sep 21, 1987 01:21:00p -by- David N. Weise [davidw] ;
; Added this nifty comment block. ;
;-----------------------------------------------------------------------;
cProc DecExeUsage,<PUBLIC,NEAR>,<ds,di,si>
parmW hexe
cBegin
call MapDStoDATA
ReSetKernelDS
xor si,si
mov cx,hexe
xor ax,ax
jcxz dexj
mov es,cx
cmp es:[si].ne_magic,NEMAGIC
jne dexj
test es:[si].ne_usage,8000h
jz dego
dexj:
krDebugOut <DEB_ERROR or DEB_KRLOADMOD>, "DecExeUsage(#ES) not DLL"
jmp dex
dego:
;
; Save time and space by saving stuff on stack
; rather than recursing.
;
dec es:[si].ne_usage
or es:[si].ne_usage, 8000h
;if kdebug
; push ax
; mov ax, es:[si].ne_usage
; krDebugOut <DEB_TRACE or DEB_krLoadMod>, "DecExeUsage(%ES0) #ax"
; pop ax
;endif
NextExe2:
or es:[si].ne_usage, 4000h ; Mark node visited
mov cx,es:[si].ne_cmod
jcxz NoDeps2
mov di,es:[si].ne_modtab
MarkLoop2:
push es
cmp si, es:[di]
je MarkLoop3
lar ax, es:[di] ; Make sure valid selector
jnz MarkLoop3
mov es, es:[di]
cmp es:[si].ne_magic,NEMAGIC
jne MarkLoop3
test es:[si].ne_usage, 0C000h
jnz MarkLoop3
push cx
push di ; Fake recursion
jmp NextExe2
NextExeDone2: ; Return from fake recursion
pop di
pop cx
MarkLoop3:
pop es
add di,2
loop MarkLoop2
NoDeps2:
mov cx, es
cmp cx, hExe
jne NextExeDone2
xor cx, cx
push cx ; End of list of Exes to delete
mov di, hExeHead ; Scan Exes once to dec them
scan_exes:
or di, di
jz de_done
mov es, di
mov di, es:[si].ne_pnextexe
test es:[si].ne_usage, 4000h
jz scan_exes
and es:[si].ne_usage, NOT 4000h ; Remove the mark
test es:[si].ne_usage, 8000h ; Skip this one?
jnz scan_exes
; krDebugOut <DEB_TRACE or DEB_krLoadMod>, "DecExeUsage dependent %ES0"
dec es:[si].ne_usage
jnz scan_exes
push es ; We will delete this one
jmps scan_exes
de_done: ; Call WEP each module before
mov bx, sp ; we free any modules
de_done0:
mov cx, ss:[bx]
add bx, 2
jcxz de_done1
push bx
cCall CallWEP, <cx, 0>
pop bx
jmps de_done0
de_done1:
pop cx ; Get next module to delete
jcxz all_deleted
cCall DelModule,<cx> ; Delete him
jmps de_done1
all_deleted:
mov es, hExe
and es:[si].ne_usage,NOT 0C000h
dex:
cEnd
;
; StartProcAddress( hExe ) - procedure to return the fixed address of
; a new EXE start procedure
;
cProc StartProcAddress,<PUBLIC,NEAR>,<di>
parmW hexe
parmW fh
cBegin
mov es,hexe
mov di,ne_csip
xor dx,dx
mov ax,es:[di+2]
or ax,ax
jz sp1
mov di,es:[di]
cCall FarLoadSegment,<es,ax,fh,fh>
jcxz sp1
mov ax,di ; DX:AX is start address of module
sp1: ; (DX is really a handle)
mov cx,ax
or cx,dx
cEnd
; GetStackPtr - returns the initial SS:SP for a module.
;
cProc GetStackPtr,<PUBLIC,NEAR>,<si>
parmW hExe
cBegin
mov es,hExe
if KDEBUG
cmp es:[ne_sssp].sel,0
jnz @F
mov cx,ne_sssp
fkerror 0,<Invalid stack segment>,es,cx
@@:
endif
cmp es:[ne_sssp].off,0
jne re3
mov dx,es:[ne_stack]
mov bx,es:[ne_pautodata]
or bx,bx
jz re2
add dx,es:[bx].ns_minalloc
re2: and dx,0FFFEh ; Word aligned stack
mov word ptr es:[ne_sssp],dx
re3: mov dx,es:[ne_sssp].sel
mov ax,es:[ne_sssp].off
push ax
mov cx,-1
cCall FarLoadSegment,<es,dx,cx,cx>
pop ax ; Handle in DX and offset in AX
cEnd
;
; GetInstance( hExe ) - Procedure to return the instance handle for
; the current automatic data segment associated with the passed exe
;
cProc GetInstance,<PUBLIC,NEAR>
parmW hexe
cBegin
mov es,hexe
mov ax,es:[ne_flags]
test ax,NEINST+NESOLO
mov ax,es
jz gidone
mov bx,es:[ne_pautodata]
or bx,bx
jz gidone
mov ax,es:[bx].ns_handle
gidone:
mov cx,ax
cEnd
sEnd NRESCODE
end