535 lines
16 KiB
C++
535 lines
16 KiB
C++
;/*
|
|
|
|
; Flags for Heap Header
|
|
L32F_NOHUSED equ 1
|
|
|
|
; Heap signature
|
|
L32_SIGNATURE equ 3233484Ch ; 'LH32'
|
|
|
|
; Flags for Local32Init
|
|
LINIT_MAX16HEAP equ 1
|
|
LINIT_TILEHEAP equ 2
|
|
|
|
; Flags for Local32Alloc
|
|
LMEM32_64K equ 1
|
|
LMEM32_ZEROINIT equ 2
|
|
|
|
; Address types
|
|
NOHPTR16 equ -2
|
|
NOHPTR32 equ -1
|
|
HANDLE16 equ 0
|
|
PTR16 equ 1
|
|
PTR32 equ 2
|
|
|
|
; if address type is < MINHTYPE, there is no handle associated with address
|
|
MINHTYPE equ 0
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Heap Header (lives at 64K-(SIZE L32HeapHeader))
|
|
;-----------------------------------------------------------------------;
|
|
L32HeapHeader struc
|
|
FreeLists dw 16 dup(?) ; array of ptrs to free handles in each page
|
|
FreeCounts dw 16 dup(?) ; array of counts of free handles in each page
|
|
FreeTails dw 16 dup(?) ; array of ptrs to tail of free lists
|
|
dwSelTable dd ? ; 32bit offset of handle->sel mapping table
|
|
wMaxBaseDelta dw ? ; # of 64K blocks in heap * 8
|
|
wSelAdjust dw ? ; (see L32FindHandleEntry, NOHPTR16 code)
|
|
dwBaseSel dd ? ; base selector
|
|
linBaseAddr dd ? ; base linear address of heap
|
|
hCommit dd ? ; highest committed handle
|
|
L32Flags dd ? ; flags field (L32F_*)
|
|
L32Signature dd ? ; heap signature (L32_SIGNATURE)
|
|
hHeap dd ? ; handle to heap
|
|
L32HeapHeader ends
|
|
|
|
L32HdrSize equ (size L32HeapHeader)
|
|
|
|
;Translation macro for fast handle->pointer conversion
|
|
|
|
.386p
|
|
|
|
EnumArgs macro arglist,prefix
|
|
argctr = 0
|
|
for arg,<arglist>
|
|
argctr = argctr + 1
|
|
@CatStr(prefix,%argctr) TEXTEQU <arg>
|
|
endm
|
|
@CatStr(prefix,<Cnt>) = argctr
|
|
|
|
endm
|
|
|
|
ProcessOptions macro optlist
|
|
|
|
; Initialize options to default values
|
|
THOptFULL = 0
|
|
THOffset = 10000h
|
|
THForce32 = 0
|
|
THNoValid = 0
|
|
|
|
irp opt,<optlist>
|
|
|
|
ifidni <opt>,<FULL>
|
|
THOptFULL = 1
|
|
endif
|
|
|
|
ifidni <opt>,<SEPARATE>
|
|
THOffset = 0
|
|
endif
|
|
|
|
ifidni <opt>,<FORCE32>
|
|
THForce32 = 1
|
|
endif
|
|
|
|
ifidni <opt>,<NOVALID>
|
|
THNoValid = 1
|
|
endif
|
|
endm
|
|
|
|
THHdrPos = THOffset
|
|
|
|
endm
|
|
|
|
|
|
InList macro reg,reglist
|
|
|
|
ifnb <reglist>
|
|
IsInList INSTR <reglist>,<reg>
|
|
exitm %IsInList
|
|
else
|
|
exitm %0
|
|
endif
|
|
|
|
endm
|
|
|
|
|
|
ChooseSegReg macro wSel
|
|
PopDS=1
|
|
ifidni <wSel>,<0>
|
|
sptr TEXTEQU <ds>
|
|
PopDS=0
|
|
else
|
|
irp creg,<ds,es,fs,gs>
|
|
ifidni <creg>,<wSel>
|
|
sptr TEXTEQU <wSel>
|
|
PopDS=0
|
|
endif
|
|
endm
|
|
endif
|
|
endm
|
|
|
|
UseSegReg macro wSel
|
|
|
|
if PopDS
|
|
push ds
|
|
mov ds,wSel
|
|
|
|
sptr TEXTEQU <ds>
|
|
endif
|
|
|
|
; Hack: We need to generate instructions like mov eax,[10000h]
|
|
; and MASM won't generate a 32-bit offset unless the
|
|
; segment is not assumed to be a 16-bit segment. We only
|
|
; need this for ds since we only generate these instructions
|
|
; for merged segments.
|
|
ifidni sptr,<ds>
|
|
assume ds:nothing
|
|
endif
|
|
|
|
endm
|
|
|
|
RestoreSegReg macro
|
|
|
|
if PopDS
|
|
pop ds
|
|
endif
|
|
|
|
; See note in UseSegReg.
|
|
ifidni sptr,<ds>
|
|
assumes ds,data
|
|
endif
|
|
|
|
endm
|
|
|
|
ParseDestReg macro hMem
|
|
|
|
; Sigh. elseif InList(...) doesn't compile so
|
|
; NoDestReg is a workaround. Somebody please
|
|
; get rid of it if they can figure out how!
|
|
NoDestReg = 1
|
|
if InList(<hMem>,<ax,bx,cx,dx>)
|
|
destreg32 TEXTEQU @CatStr(<e>, <hMem>)
|
|
destreg16 TEXTEQU <hMem>
|
|
destreg8 TEXTEQU @CatStr(@SubStr(<hMem>,1,1),<l>)
|
|
NoDestReg = 0
|
|
endif
|
|
if ((NoDestReg NE 0) AND (InList(<hMem>,<eax,ebx,ecx,edx>) NE 0))
|
|
destreg32 TEXTEQU <hMem>
|
|
destreg16 TEXTEQU @SubStr(<hMem>,2,2)
|
|
destreg8 TEXTEQU @CatStr(@SubStr(<hMem>,2,1),<l>)
|
|
NoDestReg = 0
|
|
endif
|
|
if ((NoDestReg NE 0) AND (InList(<hMem>,<si,di,esi,edi>) NE 0))
|
|
; these regs only work if opts is blank
|
|
destreg32 TEXTEQU <>
|
|
destreg16 TEXTEQU <hMem>
|
|
destreg8 TEXTEQU <>
|
|
NoDestReg = 0
|
|
endif
|
|
if NoDestReg
|
|
destreg32 TEXTEQU <eax>
|
|
destreg16 TEXTEQU <ax>
|
|
destreg8 TEXTEQU <al>
|
|
movzx destreg32,hMem
|
|
endif
|
|
endm
|
|
|
|
; Table to determine if two registers overlap
|
|
??al = 00000001b
|
|
??ah = 00000001b
|
|
??ax = 00000001b
|
|
??eax = 00000001b
|
|
??bl = 00000010b
|
|
??bh = 00000010b
|
|
??bx = 00000010b
|
|
??ebx = 00000010b
|
|
??cl = 00000100b
|
|
??ch = 00000100b
|
|
??cx = 00000100b
|
|
??ecx = 00000100b
|
|
??dl = 00001000b
|
|
??dh = 00001000b
|
|
??dx = 00001000b
|
|
??edx = 00001000b
|
|
??si = 00010000b
|
|
??esi = 00010000b
|
|
??di = 00100000b
|
|
??edi = 00100000b
|
|
|
|
??Paste macro arg1:req, arg2:req
|
|
exitm <arg1&arg2>
|
|
endm
|
|
|
|
TranslateHandle macro wSel,dwMem,wMemType,wRetType,reglist,dreg,opts
|
|
local THErr
|
|
local THOk
|
|
local DestOk
|
|
|
|
if (wMemType EQ HANDLE16)
|
|
EnumArgs <dreg>,regs
|
|
ProcessOptions <opts>
|
|
|
|
; choose appropriate segment register based on wSel
|
|
ChooseSegReg wSel
|
|
|
|
; choose appropriate destination register based on dreg
|
|
if (regsCnt EQ 1)
|
|
destreg TEXTEQU <regs1>
|
|
??destreg = ??Paste(??,%regs1)
|
|
else
|
|
destreg TEXTEQU <eax>
|
|
??destreg = ??eax
|
|
endif
|
|
|
|
??dwMem = ??Paste(??,dwMem)
|
|
|
|
; if trivial conversion (HANDLE->HANDLE) do it & exit
|
|
if (wRetType EQ HANDLE16)
|
|
mov destreg,dwMem
|
|
exitm
|
|
endif
|
|
|
|
; if wSel isn't in segment register load it in ds
|
|
UseSegReg wSel
|
|
|
|
|
|
if THForce32
|
|
mov ecx, THHdrPos
|
|
endif
|
|
|
|
;if full validation requested do it now
|
|
if THOptFULL
|
|
ParseDestReg <dwMem>
|
|
|
|
test destreg8,3 ; make sure hMem % 4 == 0
|
|
jnz THErr
|
|
|
|
cmp destreg16,L32HdrSize
|
|
jb THErr
|
|
|
|
if THForce32
|
|
cmp destreg16,word ptr sptr:[ecx].hCommit ; see if handle is below commit
|
|
else
|
|
cmp destreg16,word ptr sptr:[THHdrPos].hCommit ; see if handle is below commit
|
|
endif
|
|
ja THErr
|
|
|
|
ifdifi destreg32,<bx>
|
|
movzx ebx,destreg16
|
|
endif
|
|
|
|
if THForce32
|
|
mov destreg,sptr:[ebx+ecx] ; get 32bit offset in destreg
|
|
else
|
|
mov destreg,sptr:[ebx+THOffset] ; get 32bit offset in destreg
|
|
endif
|
|
|
|
cmp destreg,10000h ; see if its free
|
|
jb THErr
|
|
|
|
else
|
|
; fetch the address (assume dwMem is valid)
|
|
|
|
if THForce32
|
|
mov destreg,sptr:[dwMem+ecx]
|
|
else
|
|
mov destreg,sptr:[dwMem+THOffset]
|
|
endif
|
|
|
|
endif
|
|
|
|
ifdef DEBUG
|
|
ife THNoValid
|
|
cmp destreg,10000h ; see if its free
|
|
jae DestOk
|
|
int 3
|
|
endif
|
|
DestOk:
|
|
endif
|
|
|
|
|
|
|
|
; if HANDLE16->PTR16 compute the selector
|
|
if (wRetType EQ PTR16)
|
|
|
|
if InList(<bx>,<reglist>) OR InList(<ebx>,<reglist>)
|
|
push ebx
|
|
endif
|
|
if THForce32
|
|
mov ebx,sptr:[ecx].dwSelTable
|
|
else
|
|
mov ebx,sptr:[THHdrPos].dwSelTable
|
|
endif
|
|
|
|
; determine which registers to use...
|
|
if (regsCnt EQ 0)
|
|
; eax,dx:ax = PTR16
|
|
mov edx,eax
|
|
shr edx,15
|
|
and ax,7fffh
|
|
mov dx,sptr:[ebx+edx*2]
|
|
rol eax,16
|
|
mov ax,dx
|
|
rol eax,16
|
|
elseif (regsCnt EQ 1)
|
|
; regs1 = PTR16
|
|
destreg16 TEXTEQU @SubStr(dreg,2)
|
|
|
|
if InList(<dx>,<reglist>) OR InList(<edx>,<reglist>)
|
|
push edx
|
|
endif
|
|
|
|
mov edx,destreg
|
|
shr edx,15
|
|
and destreg16,7fffh
|
|
mov dx,sptr:[ebx+edx*2]
|
|
rol destreg,16
|
|
mov destreg16,dx
|
|
rol destreg,16
|
|
|
|
if InList(<dx>,<reglist>) OR InList(<edx>,<reglist>)
|
|
pop edx
|
|
endif
|
|
|
|
elseif (regsCnt EQ 2)
|
|
; regs1:regs2 = PTR16
|
|
if InList(<dx>,<reglist>) OR InList(<edx>,<reglist>)
|
|
push edx
|
|
endif
|
|
|
|
mov edx,eax
|
|
shr edx,15
|
|
mov regs1,sptr:[ebx+edx*2]
|
|
ifdifi <ax>,regs2
|
|
mov regs2,ax
|
|
endif
|
|
and regs2,7fffh
|
|
|
|
if InList(<dx>,<reglist>) OR InList(<edx>,<reglist>)
|
|
pop edx
|
|
endif
|
|
|
|
else
|
|
.err Too many destination regs passed to TranslateHandle
|
|
endif
|
|
|
|
if InList(<bx>,<reglist>) OR InList(<ebx>,<reglist>)
|
|
pop ebx
|
|
endif
|
|
endif
|
|
|
|
if THOptFULL
|
|
jmp THOk
|
|
THErr:
|
|
; determine which registers to use...
|
|
if (regsCnt EQ 0)
|
|
; eax,dx:ax = PTR16
|
|
xor eax,eax
|
|
xor edx,edx
|
|
elseif (regsCnt EQ 1)
|
|
; regs1 = PTR16
|
|
xor regs1,regs1
|
|
elseif (regsCnt EQ 2)
|
|
; regs1:regs2 = PTR16
|
|
xor regs2,regs2
|
|
mov regs1,regs2
|
|
else
|
|
.err Too many destination regs passed to TranslateHandle
|
|
endif
|
|
|
|
THOk:
|
|
endif
|
|
|
|
; if wSel wasn't in segment register restore ds
|
|
RestoreSegReg
|
|
elseif ((wMemType EQ PTR32) AND (wRetType EQ PTR16))
|
|
|
|
; input: eax = 32-bit offset
|
|
; output: eax = 16:16 ptr (ebx,ecx,edx trashed)
|
|
|
|
mov ebx,THHdrPos
|
|
|
|
mov edx,eax
|
|
shr edx,15
|
|
mov ecx,sptr:[ebx].dwSelTable
|
|
and eax,7fffh
|
|
rol eax,16
|
|
mov ax,sptr:[ecx+edx*2]
|
|
rol eax,16
|
|
|
|
else
|
|
|
|
ifnb <reglist>
|
|
Save <reglist>
|
|
endif
|
|
int 3
|
|
cCall Local32Translate,<wSel,dwMem,wMemType,wRetType>
|
|
ifnb <dreg>
|
|
mov dreg,eax
|
|
endif
|
|
endif
|
|
endm
|
|
|
|
;Validation macro for fast 32bit handle validation
|
|
|
|
|
|
ValidHandle32 macro wSel,hMem,opts
|
|
local VH32_Err
|
|
local VH32_End
|
|
|
|
ifb <opts>
|
|
test hMem,2 ; ZF=0 => 32-bit, ZF=1 => 16-bit
|
|
else
|
|
ParseDestReg <hMem>
|
|
ProcessOptions <opts>
|
|
ChooseSegReg wSel
|
|
|
|
UseSegReg wSel
|
|
|
|
|
|
if THForce32
|
|
mov ecx, THHdrPos
|
|
endif
|
|
|
|
test destreg8,3 ; make sure hMem % 4 = 0
|
|
jnz VH32_Err ; if not we know it isn't valid
|
|
|
|
cmp destreg16,L32HdrSize ; see if handle points in header
|
|
jb VH32_Err ;
|
|
|
|
if THForce32
|
|
cmp destreg32,sptr:[ecx].hCommit ; see if handle is
|
|
else
|
|
cmp destreg32,sptr:[THHdrPos].hCommit ; see if handle is
|
|
endif
|
|
; below commit line
|
|
|
|
ja VH32_Err
|
|
|
|
if THForce32
|
|
mov destreg32,sptr:[destreg32+ecx]
|
|
else
|
|
mov destreg32,sptr:[destreg32+THHdrPos]
|
|
endif
|
|
cmp destreg32,10000h ; see if its free
|
|
jae VH32_End ; if not we're happy
|
|
|
|
VH32_Err:
|
|
|
|
xor ax,ax ; set zero flag
|
|
|
|
VH32_End:
|
|
|
|
RestoreSegReg
|
|
endif
|
|
|
|
; cCall Local32ValidHandle,<wSel,hMem>
|
|
endm
|
|
|
|
|
|
ifndef ?INHEAP32
|
|
.286p
|
|
externFP Local32Init
|
|
externFP Local32Alloc
|
|
externFP Local32ReAlloc
|
|
externFP Local32Size
|
|
externFP Local32Translate
|
|
externFP Local32ValidHandle
|
|
externFP Local32Free
|
|
externFP Local32GetSel
|
|
endif
|
|
|
|
if 0
|
|
;*/
|
|
|
|
/* Flags for Local32Init */
|
|
#define LINIT_MAX16HEAP 1
|
|
#define LINIT_TILEHEAP 2
|
|
#define LINIT_EMS16HEAP 4
|
|
|
|
/* Flags for Local32Alloc */
|
|
#define LMEM32_64K 1
|
|
#define LMEM32_ZEROINIT 2
|
|
|
|
/* Address types */
|
|
#define NOHPTR16 (WORD) (-2)
|
|
#define NOHPTR32 (WORD) (-1)
|
|
#define HANDLE16 0
|
|
#define PTR16 1
|
|
#define PTR32 2
|
|
|
|
DWORD FAR PASCAL Local32Init(WORD wSel, DWORD dwcbInit, DWORD dwcbMax, DWORD dwFlags);
|
|
DWORD FAR PASCAL Local32Alloc(DWORD linHdr, DWORD dwcbRequest, WORD wType, DWORD dwFlags);
|
|
DWORD FAR PASCAL Local32ReAlloc(DWORD linHdr, DWORD dwMem, WORD wType, DWORD dwcbNew, DWORD dwFlags);
|
|
DWORD FAR PASCAL Local32Size(DWORD linHdr, DWORD dwMem, WORD wType);
|
|
DWORD FAR PASCAL Local32Translate(DWORD linHdr, DWORD dwMem, WORD wMemType,
|
|
WORD wRetType);
|
|
BOOL FAR PASCAL Local32ValidHandle(DWORD linHdr, HANDLE hMem);
|
|
BOOL FAR PASCAL Local32Free(DWORD linHdr, DWORD dwMem, WORD wMemType);
|
|
WORD FAR PASCAL Local32GetSel(DWORD linHdr);
|
|
|
|
#define TranslateHandle(a,b,c,d) Local32Translate((a),(b),(c),(d))
|
|
|
|
#ifndef _flat
|
|
#define _flat __based32(__segname("_DATA"))
|
|
#endif
|
|
|
|
#define HTOFLAT(p,h) \
|
|
{ \
|
|
DWORD _flat* _tp_ = (DWORD _flat*)((h)+0x10000); \
|
|
(p) = ((void _flat*)*_tp_); \
|
|
}
|
|
|
|
;/*
|
|
endif
|
|
;*/
|