home *** CD-ROM | disk | FTP | other *** search
- ;***
- ;cruntime.inc - multi-model assembly macros for interfacing to HLLs
- ;
- ; Copyright (c) 1988-1997, Microsoft Corporation. All rights reserved.
- ;
- ;Purpose:
- ; This file defines the current memory model being used.
- ;
- ;*******************************************************************************
-
- ;==============================================================================
- ;
- ;Use the following defines to control processor/segment model
- ;
- ; -DI86 8086/8088 processor
- ; -DI286 80286 processor
- ; -DI386 80386 processor with 32-bit code/data segment
- ;
- ; -Dmem_S Small memory model (near code, near data)
- ; -Dmem_M Medium memory model (far code, near data)
- ; -Dmem_C Compact memory model (near code, fat data)
- ; -Dmem_L Large memory model (far code, far data)
- ;
- ; -DSS_NEQ_DGROUP SS and DS point to different segments
- ;
- ; default is -DI86 -Dmem_S
- ;
- ;==============================================================================
- ;
- ;The following variables are defined by this file:
- ; cpu 86, 286, or 386
- ; sizeC code distance; 1 = far code, 0 = near code
- ; sizeD data distance; 1 = far data, 0 = near data
- ; mmodel english name of the memory model, i.e. "Medium"
- ; ISIZE, LSIZE, NSIZE size of ints, longs, shorts
- ; FLTSIZE, DBLSIZE, LDBLSIZE size of float, double, long double
- ; NPSIZE, FPSIZE size of near/far pointers
- ; CPSIZE, DPSIZE size of code/data pointers
- ; ISHIFT, LSHIFT bits to shift to convert byte to int/long
- ;
- ;The following macros allow easy writing of combined 16/32 bit code:
- ;
- ; 16/32 bit registers:
- ; rax, rbx, rcx, rdx, expand to native registers (rax = eax or ax)
- ; rsi, rdi, rsp, rbp
- ; 16/32 bit register instructions:
- ; JRCXZ jump when rcx is zero
- ; CBI convert byte to int (al to rax)
- ; CAXDX convert rax to rax:rdx
- ; ZXAL, ZXBL, ZXCL, ZXDL zero extend al,bl,cl,dl to rax,rbx,rcx,rdx
- ; Pointer instructions:
- ; LPDS, LPES load data pointer with ES or DS
- ; PDS, PES segment overrides when pointer loaded as above
- ; PCS, PSS segment override to get at code/stack segment
- ; LFPDS, LFPES load far pointer with ES or DS
- ; FPDS, FPES segment overrides when pointer loaded as above
- ; CPTR data type of code pointer
- ; CPDIST distance of code (near/far)
- ; DNPTR, DFPTR define near/far pointer
- ; DCPTR, DDPTR define code/data pointer
- ; DCPTR?, DDPTR? define uninitialized code/data pointer
- ; CPWORD, DPWORD data type of code or data pointer
- ; Numeric type instructions:
- ; IWORD, LWORD, SWORD data type of int, long, short
- ; DINT, DLONG, DSHORT define int, long, short
- ; DFLOAT, DDOUBLE, DLDOUBLE define float, double, long double
- ; Offsets:
- ; codeoffset, dataoffset offsets from code and data segments
- ; API calls:
- ; APIDIST distance of API calls (near/far)
- ; APIEXT ApiName extrn declaration for an API function
- ;
- ;The following utility macros are provided:
- ; codeseg define/declare code segment
- ; error <msg> stop assembly with message
- ; display <msg> display a message, unless QUIET defined
- ; savelist [<reg> ...] init list of regs to be save by 'proc uses'
- ; _if cond <instruction> assemble instruction only if cond is TRUE
- ; _ife cond <instruction> assemble instruction only if cond is FALSE
- ; _ifd symbol <instruction> assemble instruction only if symbol defined
- ; _ifnd symbol <instruction> assemble instruction only if symbol not defined
- ;
- ; lab LabelName assembles to "LabelName:" If DEBUG is defined
- ; LabelName is made public
- ;
- ; JS* (ex. JSE,JSZ,JSB ...) assemble to "je short","jz short","jb short"
- ;
- ; Cmacro look alikes
- ; static* Name, InitialValue, Repeat defines a static variable of type *
- ; global* Name, InitialValue, Repeat defines a global variable of type *
- ; label* Name, {PUBLIC,PASCAL,C} defines a label of type *
- ;
- ; PUSH16 SegmentReg pushes 16 bits in a use32 segment
- ; JMPFAR16 label will do a far 16:16 jmp from a use32 segment
- ;
- ;==============================================================================
-
- ; error <msg> - Output message and generate error
-
- error MACRO msg
- if2 ;; only on pass 2 can we generate errors
- %out **********************************************************
- %out *** E r r o r -- msg
- %out **********************************************************
- .err
- endif
- ENDM
-
- ; display msg - Output message unless QUIET defined
-
- display MACRO msg
- ifndef QUIET ;; only when quiet flag not set
- if1 ;; and on pass 1, then display message
- %out msg
- endif
- endif
- ENDM
-
- ; One line conditionals:
- ; here we create the capability of writing code lines like
- ;
- ; _if sizeD <push ds> as opposed to if sizeD
- ; push ds
- ; endif
-
- _if MACRO cond,text
- if cond
- text
- endif
- ENDM
-
- _ife MACRO cond,text
- ife cond
- text
- endif
- ENDM
-
- _ifd MACRO cond,text
- ifdef cond
- text
- endif
- ENDM
-
- _ifnd MACRO cond,text
- ifndef cond
- text
- endif
- ENDM
-
- ; set windows flag to 0
-
- ?WIN equ 0 ; disable windows-specific code
-
- ; check for _MT, requires 286 or greater processor
-
- ifdef _MT
- ifndef I386
- ifndef I286
- ; _MT implies 286 processor
- display <Multi-thread specified - assuming 80286 processor>
- I286 equ <>
- endif
- endif
- endif
-
- ; Process memory-model arguments
-
- ifdef mem_M
- ; Medium model
- sizeC equ 1
- sizeD equ 0
- mmodel equ <Medium>
- elseifdef mem_C
- ; Compact model
- sizeC equ 0
- sizeD equ 1
- mmodel equ <Compact>
- elseifdef mem_L
- ; Large model
- sizeC equ 1
- sizeD equ 1
- mmodel equ <Large>
- else
- ; Small model - default
- sizeC equ 0
- sizeD equ 0
- mmodel equ <Small>
- endif
-
- ; Process processor arguments
-
- ifdef _WIN32
- display <Processor: 486/586>
- cpu equ 586
- .586
- elseifdef _POSIX_
- display <Processor: 486/586>
- cpu equ 586
- .586
- elseifdef I286
- display <Processor: 80286>
- cpu equ 286
- .286
- elseifdef I386
- display <Processor: 80386>
- cpu equ 386
- .386
- else
- display <Processor: 8086/8088>
- cpu equ 86
- .8086
- endif
-
- ; 386 32-bit checking. Currently we are only expecting small model
- ; 32 bit segments, so we make a few checks to be sure nothing is
- ; incorrectly being defined.
-
- ifdef I386
- if sizeC or sizeD
- error <Must use Small memory model for 386 version.>
- endif
-
- ifdef _LOAD_DGROUP
- error <No loading DGROUP in 386 version.>
- endif
-
- ifdef SS_NEQ_DGROUP
- error <SS always equals DGROUP in 386 version.>
- endif
- endif
-
- ; Set memory model
-
- % display <Memory model: mmodel>
- % .model mmodel, C
-
- ;
- ; *** Temporary Workaround ***
- ; Currently, MASM will not recognize the 'FLAT' keyword unless it previously
- ; appears in an 'assume' statement. Presumably, when the '.model FLAT' feature
- ; is implemented, this will go away. [Use 'gs:' since we never use that
- ; segment register.
- ;
-
- ifdef I386
- ; ensure that MASM recognizes 'FLAT'
- assume gs:FLAT
- endif
-
-
- ; Define registers:
- ; Instead of using the "word" registers directly, we will use a set of
- ; text equates. This will allow you to use the native word size instead of
- ; hard coded to 16 bit words. We also have some instruction equates for
- ; instruction with the register type hard coded in.
-
- ifdef I386
-
- rax equ <eax>
- rbx equ <ebx>
- rcx equ <ecx>
- rdx equ <edx>
- rdi equ <edi>
- rsi equ <esi>
- rbp equ <ebp>
- rsp equ <esp>
-
- JRCXZ equ <jecxz>
- CBI equ <movsx eax, al> ; convert byte to int (al to rax)
- CAXDX equ <cdq> ; convert rax to rdx:rax
- ZXAL equ <movzx eax, al> ; zero extend al
- ZXBL equ <movzx ebx, bl> ; zero extend bl
- ZXCL equ <movzx ecx, cl> ; zero extend cl
- ZXDL equ <movzx edx, dl> ; zero extend dl
-
- else
-
- rax equ <ax>
- rbx equ <bx>
- rcx equ <cx>
- rdx equ <dx>
- rdi equ <di>
- rsi equ <si>
- rbp equ <bp>
- rsp equ <sp>
-
- JRCXZ equ <jcxz>
- CBI equ <cbw> ; convert byte to int (al to rax)
- CAXDX equ <cwd> ; convert rax to rdx:rax
- ZXAL equ <xor ah, ah> ; zero extend al
- ZXBL equ <xor bh, bh> ; zero extend bl
- ZXCL equ <xor ch, ch> ; zero extend cl
- ZXDL equ <xor dh, dh> ; zero extend dl
-
- endif
-
- ; The following equates deal with the differences in near versus
- ; far data pointers, and segment overrides.
- ;
- ; Use LPES and PES when loading a default size pointer -- it loads
- ; a 16-bit pointer register in 286 Small/Medium model,
- ; a 16-bit pointer register and 16-bit segment register in 8086/286
- ; Compact/Large model, and a 32-bit pointer register in 386 mode.
- ;
- ; Use LFPES and FPES when loading an always far pointer -- it loads a
- ; 16-bit pointer register and 16-bit segment register in 8086/286,
- ; all models; a 32-bit pointer register in 386 mode.
-
- if sizeD
- LPES equ <les>
- LPDS equ <lds>
- PDS equ <ds:>
- PES equ <es:>
- else
- LPES equ <mov>
- LPDS equ <mov>
- PDS equ <>
- PES equ <>
- endif
-
- ifdef I386
- LFPES equ <mov>
- LFPDS equ <mov>
- FPES equ <>
- FPDS equ <>
- else
- LFPES equ <les>
- LFPDS equ <lds>
- FPES equ <es:>
- FPDS equ <ds:>
- endif
-
- if sizeC or @WordSize eq 2
- PCS equ <cs:> ; large code model or non-386
- else
- IF 1 ;*** TEMP 16/32 TESTBED ***
- PCS equ <cs:>
- ELSE
- PCS equ <> ; 386 small code model
- ENDIF ;*** END TEMP CODE
- endif
-
- ifdef SS_NEQ_DGROUP
- PSS equ <ss:> ; SS != DS
- else
- PSS equ <> ; SS == DS
- endif
-
- ; Define offset macros:
- ; The 32-bit segments will not have 'groups'
-
- ifdef I386
- codeoffset equ <offset FLAT:>
- dataoffset equ <offset FLAT:>
- else
- codeoffset equ <offset @code:>
- dataoffset equ <offset DGROUP:>
- endif
-
- ; The next set of equates deals with the size of SHORTS, INTS, LONGS, and
- ; pointers in the 16 and 32 bit versions.
-
- ifdef I386 ;--- 32 bit segment ---
-
- ; parameters and locals
- IWORD equ <dword>
- LWORD equ <dword>
-
- ; static storage
- DINT equ <dd>
- DLONG equ <dd>
- DSHORT equ <dw>
-
- ; sizes for fixing SP, stepping through tables, etc.
- ISIZE equ 4
- LSIZE equ 4
- SSIZE equ 2
- NPSIZE equ 4
- FPSIZE equ 4
-
- ; bit shift count to convert byte cnt/ptr to int/long cnt/ptr
- ISHIFT equ 2 ; byte-to-int shift count
- LSHIFT equ 2 ; byte-to-long shift count
-
- ; sizes dependent upon memory model. dq -vs- df is not yet clear
- DNPTR equ <dd> ; near pointer
- DFPTR equ <dd> ; far pointer
-
- DCPTR equ <dd offset FLAT:>; 32 bit offset only
- DCPTR? equ <dd> ; No seg override for uninitialized values
- CPSIZE equ 4
- CPDIST equ <near> ; code pointers are near
- CPTR equ <near ptr>
-
- DDPTR equ <dd offset FLAT:>
- DDPTR? equ <dd>
- DPSIZE equ 4
-
- CPWORD equ <dword> ; code pointers are dwords
- DPWORD equ <dword> ; data pointers are dwords
-
- APIDIST equ <near> ; all API calls are NEAR in the 32 bit model
-
- ; macro to declare API functions
- EXTAPI macro apiname
- extrn pascal apiname:near
- endm
-
- else ;--- 16-bit segment ---
-
- ; parameters and locals
- IWORD equ <word>
- LWORD equ <dword>
-
- ; static storage
- DINT equ <dw>
- DLONG equ <dd>
- DSHORT equ <dw>
-
- ; sizes for fixing SP, stepping through tables, etc
- ISIZE equ 2
- LSIZE equ 4
- SSIZE equ 2
- NPSIZE equ 2
- FPSIZE equ 4
-
- ; bit shift count to convert byte cnt/ptr to int/long cnt/ptr
- ISHIFT equ 1 ; byte-to-int shift count
- LSHIFT equ 2 ; byte-to-long shift count
-
- ; sizes dependent upon memory model
- DNPTR equ <dw> ; near pointer
- DFPTR equ <dd> ; far pointer
-
- if sizeC
- DCPTR equ <dd> ; 16 bit segment and 16 bit offset
- DCPTR? equ <dd>
- CPSIZE equ 4
- CPDIST equ <far> ; code pointers are far
- CPTR equ <far ptr>
- CPWORD equ <dword> ; code pointers are dwords
- else
- DCPTR equ <dw> ; 16 bit offset only
- DCPTR? equ <dw>
- CPSIZE equ 2
- CPDIST equ <near> ; code pointers are near
- CPTR equ <near ptr>
- CPWORD equ <word> ; code pointers are words
- endif
-
- if sizeD
- DDPTR equ <dd>
- DDPTR? equ <dd>
- DPSIZE equ 4
- DPWORD equ <dword> ; data pointers are dwords
- else
- DDPTR equ <dw>
- DDPTR? equ <dw>
- DPSIZE equ 2
- DPWORD equ <word> ; data pointers are words
- endif
-
- APIDIST equ <far> ; API calls are FAR in 16 bit model
-
- ; macro to declare API functions
- EXTAPI macro apiname
- extrn pascal apiname:far
- endm
-
- endif ; --- 16/32 segment ---
-
- ; Float/double definitions
- ; (currently the same for 16- and 32-bit segments)
-
- FLTSIZE equ 4 ; float
- DBLSIZE equ 8 ; double
- LDBLSIZE equ 10 ; long double
-
- DFLOAT equ <dd>
- DDOUBLE equ <dq>
- DLDOUBLE equ <dt>
-
- ;
- ; savelist - Generate a list of regs to be saved by the proc 'uses' option.
- ;
- ; Input:
- ; reg1, reg2, reg3, reg4 = registers to be saved across function
- ; Output:
- ; reglist = text string of registers that can be passed to the 'uses'
- ; option on the 'proc' command.
- ;
-
- savelist MACRO reg1, reg2, reg3, reg4
- local ws, listsize
- ws catstr < > ; whitespace char
-
- IFNDEF I386
- rbx equ <> ; 8086/286 don't save rbx
- ENDIF
-
- IFNB <reg4>
- reglist catstr reg1, ws, reg2, ws, reg3, ws, reg4
- ELSEIFNB <reg3>
- reglist catstr reg1, ws, reg2, ws, reg3, ws
- ELSEIFNB <reg2>
- reglist catstr reg1, ws, reg2, ws, ws
- ELSEIFNB <reg1>
- reglist catstr reg1, ws, ws, ws
- ELSE
- reglist catstr <>
- ENDIF
-
- listsize sizestr reglist ; size of register list
-
- IF listsize LE 3 ; if list is only the 3 ws chars...
- reglist catstr <>
- ENDIF
-
- IFNDEF I386
- rbx equ <bx> ; restore rbx
- ENDIF
-
- ENDM ; savelist
-
- ;
- ; codeseg - Define/declare the standard code segment. Maps to the proper
- ; form of the .code directive.
- ;
- ; Input:
- ;
- ; Output:
- ; .code _TEXT ; for large code models
- ; .code ; for small code models
- ; assume cs:FLAT ; for 386
- ; assume ds:FLAT ; for 386
- ; assume es:FLAT ; for 386
- ; assume ss:FLAT ; for 386
- ;
-
- codeseg MACRO
-
- if sizeC
- .code _TEXT
- else
- .code
- endif
-
- ifdef I386
- assume ds:FLAT
- assume es:FLAT
- assume ss:FLAT
- endif
-
- ENDM
-
- ;*========
- ;*
- ;* Debug lab macro
- ;*
- ;*========
-
- lab macro name
- ifdef DEBUG
- public pascal name ;; define label public for Symdeb
- endif
- name:
- endm
-
-
- ;*========
- ;*
- ;* Conditional jump short macros
- ;*
- ;*========
-
-
- irp x,<Z,NZ,E,NE,S,NS,C,NC,P,NP,PE,PO,A,AE,B,BE,NB,G,GE,L,LE>
- JS&x equ <j&x short>
- endm
-
-
- ;*========
- ;*
- ;* Global data definition macros
- ;*
- ;* Usage:
- ;* globalI Name, InitialValue, Repeat
- ;*
- ;*========
-
-
- MakeGlobal macro suffix, DataType ;; makes all of the global* macros
-
- global&suffix macro name, data, rep
- public name
- ifb <rep>
- _repeat = 1
- else
- _repeat = (rep)
- endif
-
- name &DataType _repeat dup( data )
- endm
-
- endm
-
-
- MakeGlobal T, dt ; globalT
- MakeGlobal Q, dq ; globalQ
- MakeGlobal D, dd ; globalD
- MakeGlobal W, dw ; globalW
- MakeGlobal B, db ; globalB
-
- % MakeGlobal I, <DINT> ; globalI
-
- % MakeGlobal DP, <DDPTR> ; globalDP
- % MakeGlobal CP, <DCPTR> ; globalCP
- % MakeGlobal FP, <DFPTR> ; globalFP
- % MakeGlobal NP, <DNPTR> ; globalNP
-
-
-
- ;*========
- ;*
- ;* Static data definition macros
- ;*
- ;* Usage:
- ;* staticI Name, InitialValue, Repeat
- ;*
- ;*========
-
-
- MakeStatic macro suffix, DataType ;; makes all of the static* macros
-
- static&suffix macro name, data, rep
-
- ifdef DEBUG
- public pascal name ;; make statics public if DEBUG
- endif
-
- ifb <rep>
- _repeat = 1
- else
- _repeat = (rep)
- endif
-
- name &DataType _repeat dup( data )
- endm
-
- endm
-
-
- MakeStatic T, dt ; staticT
- MakeStatic Q, dq ; staticQ
- MakeStatic D, dd ; staticD
- MakeStatic W, dw ; staticW
- MakeStatic B, db ; staticB
-
- % MakeStatic I, <DINT> ; staticI
-
- % MakeStatic DP, <DDPTR> ; staticDP
- % MakeStatic CP, <DCPTR> ; staticCP
- % MakeStatic FP, <DFPTR> ; staticFP
- % MakeStatic NP, <DNPTR> ; staticNP
-
- ;*========
- ;*
- ;* Label definition macros
- ;*
- ;*========
- ;*
- ;* Label definition macros
- ;*
- ;* Usage:
- ;* labelI Name, {PUBLIC, PASCAL, C}
- ;*
- ;*========
-
- __MakePublic macro name, option ;; decides if a label should be
- ifidni <option>, <PUBLIC> ;; made public
- public name
- elseifidni <option>, <PASCAL>
- public pascal name
- elseifidni <option>, <C>
- public C name
- elseifb <option>
- ifdef DEBUG
- public pascal name ;; make public if DEBUG
- endif
- endif
- endm
-
-
- MakeLabel macro suffix, LabelType ;; makes all of the label* macros
-
- %@CatStr(<label>,<suffix>) macro name, option
- __MakePublic <name>,<option>
- name label &LabelType
- endm
-
- endm
-
-
- MakeLabel T, tbyte ; make labelT
- MakeLabel Q, qword ; make labelQ
- MakeLabel D, dword ; make labelD
- MakeLabel W, word ; make labelW
- MakeLabel B, byte ; make labelB
-
- MakeLabel P, proc ; make labelP
- MakeLabel FP, far ; make labelFP
- MakeLabel NP, near ; make labelNP
-
- % MakeLabel I, IWORD ; make labelI
-
-
- labelDP macro name, option ;; labelDP
- __MakePublic <name>,<option>
- ifdef I386
- if sizeD
- name label fword
- else
- name label dword
- endif
- else ;not I386
- if sizeD
- name label dword
- else
- name label word
- endif
- endif ;not I386
- endm
-
- labelCP macro name, option ;; labelCP
- __MakePublic <name>,<option>
- ifdef I386
- if sizeC
- name label fword
- else
- name label dword
- endif
- else ;not I386
- if sizeC
- name label dword
- else
- name label word
- endif
- endif ;not I386
- endm
-
-
- ;*
- ;* PUSH16 SegReg - pushes 16 bits in a use32 segment
- ;*
-
- PUSH16 macro SegReg
-
- ifdef I386
- nop
- db 66h ; operand size over-ride
- endif ; I386
-
- push SegReg
- endm
-
-
- ;*
- ;* JMPFAR16 label - jmps far from a use32 to a use16 segment
- ;*
-
- JMPFAR16 macro label
-
- ifndef I386
- error <JMPFAR16 can only be used in a use32 code segment>
- endif ;I386
-
- nop
- db 66h ;; operand size over-ride
- db 0eah ;; jmp far immediate op code
- dw offset label
- dw seg label
- endm
-