;_ macros.asm ; Copyright (C) 1985-1991 by Walter Bright ; All Rights Reserved ; Modified for COFF and ELF support by David Bustin ; $Revision: 1.1.1.1 $ ifdef _WIN32 ifndef __NT__ __NT__ equ 1 endif endif ifndef M_I386 ifdef _WINDOWS extrn MESSAGEFATALERROR : far endif ; modified for RATIONAL support by P Murray, April 1990 ; define DOS16RM for protected mode programs ; Determine which memory model we are assembling for. For .COM files, ; force S model. ifdef DOS16RM ifndef I8086L %out Only L model supported with RATIONAL DOS Extender. end endif else ifdef I8086T I8086S equ 1 else ifndef I8086S ifndef I8086M ifndef I8086C ifndef I8086L ;if none of the memory models are defined ifndef I8086V I8086S equ 1 ;default to S model endif ;I8086V endif ;I8086L endif ;I8086C endif ;I8086M endif ;I8086S endif ;I8086T endif ;DOS16RM ifdef __OS2__ .286C endif ifdef DOS16RM .286P endif ifndef I386 I386 equ 0 endif ;Decide if SI and DI are saved across function calls SAVESIDI equ 1 ;1 means SI and DI are saved across functions if 0 ;Lattice conventions no longer supported MSC equ 1 ;ifdef means use Microsoft C calling conventions ;ifndef means use Lattice endif ; Macros to bracket data segment stuff. ifndef STARTUP begdata macro ifdef DOS16RM ;Segment so we can find the start of DGROUP NULL segment para public 'BEGDATA' ;Note PARAGRAPH alignment NULL ends endif _DATA segment word public 'DATA' _DATA ends CONST segment word public 'CONST' CONST ends _BSS segment word public 'BSS' _BSS ends ifdef DOS16RM DGROUP group NULL,_DATA,CONST,_BSS else DGROUP group _DATA,CONST,_BSS endif _DATA segment assume ds:DGROUP endm endif ; STARTUP enddata macro _DATA ends endm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Macros specific to each memory model in an attempt to make it easier ; to write memory model independent code. ; begcode,endcode Use to bracket code sections ; P Offset on BP to first argument on stack ; (excluding any local variables) ; SPTR 1 if small data model ; LPTR 1 if large pointers (large data) ; LCODE 1 if large code model ; ESeqDS 1 if ES == DS at all times ; SSeqDS 1 if SS == DS at all times ; SIZEPTR # of bytes in a pointer ; func Declare a function as NEAR or FAR ; callm Call function as NEAR or FAR ;;;;;;;;;;;;;; SMALL MEMORY MODEL ;;;;;;;;;;;;;;;;; ifdef I8086S begcode macro module _TEXT segment word public 'CODE' assume cs:_TEXT endm endcode macro module _TEXT ENDS endm P equ 4 ; Offset of start of parameters on the stack frame SPTR equ 1 LPTR equ 0 LCODE equ 0 ESeqDS equ 0 SSeqDS equ 1 SIZEPTR equ 2 ; Size of a pointer p_func macro name name proc near endm p_endp macro name name endp endm callp macro name call near ptr name endm func macro name _&name proc near ifndef name name equ _&name endif endm callm macro name call near ptr _&name endm endif ;;;;;;;;;;;;;;;;; MEDIUM MEMORY MODEL ;;;;;;;;;;;;;;;;;;;;;;;;;;;; ifdef I8086M begcode macro module module&_TEXT segment para public 'CODE' assume cs:module&_TEXT endm endcode macro module module&_TEXT ends endm P equ 6 ; Offset of start of parameters on the stack frame SPTR equ 1 LPTR equ 0 LCODE equ 1 ESeqDS equ 0 SSeqDS equ 1 SIZEPTR equ 2 p_func macro name name proc far endm p_endp macro name name endp endm callp macro name call far ptr name endm func macro name _&name proc far ifndef name name equ _&name endif endm callm macro name call far ptr _&name endm endif ;;;;;;;;;;;;;;;;; COMPACT MEMORY MODEL ;;;;;;;;;;;;;; ifdef I8086C begcode macro module _TEXT segment word public 'CODE' assume cs:_TEXT endm endcode macro module _TEXT ends endm P equ 4 ; Offset of start of parameters on the stack frame SPTR equ 0 LPTR equ 1 LCODE equ 0 ESeqDS equ 0 SSeqDS equ 0 SIZEPTR equ 4 p_func macro name name proc near endm p_endp macro name name endp endm callp macro name call near ptr name endm func macro name _&name proc near ifndef name name equ _&name endif endm callm macro name call near ptr _&name endm endif ;;;;;;;;;;;;;;;; LARGE MEMORY MODEL ;;;;;;;;;;;;;;;;;;; ifdef I8086L begcode macro module module&_TEXT segment para public 'CODE' assume cs:module&_TEXT endm endcode macro module module&_TEXT ends endm P equ 6 ; Offset of start of parameters on the stack frame SPTR equ 0 LPTR equ 1 LCODE equ 1 ESeqDS equ 0 SSeqDS equ 0 SIZEPTR equ 4 p_func macro name name proc far endm p_endp macro name name endp endm callp macro name call far ptr name endm func macro name _&name proc far ifndef name name equ _&name endif endm callm macro name call far ptr _&name endm endif ;Macros to replace public, extrn, and endp for C-callable assembly routines, ; and to define labels: c_label defines labels, ; c_public replaces public, c_extrn replaces extrn, and c_endp replaces endp c_name macro name name equ _&name endm c_label macro name _&name: endm c_public macro a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z ifnb ;;Check for blank argument public _&a a equ _&a ifnb c_public b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z endif endif endm c_extrn macro a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z ifnb ;;Check for blank argument extrn _&a:b a equ _&a ifnb c_extrn c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z endif endif endm c_endp macro name _&name ENDP endm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Define function ctor as a static constructor static_ctor macro ctor if LCODE XIFB segment word public 'DATA' XIFB ends XIF segment word public 'DATA' dd ctor XIF ends XIFE segment word public 'DATA' XIFE ends else XIB segment word public 'DATA' XIB ends XI segment word public 'DATA' dw ctor XI ends XIE segment word public 'DATA' XIE ends endif endm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Define function ctor as a static destructor static_dtor macro dtor if LCODE XCFB segment word public 'DATA' XCFB ends XCF segment word public 'DATA' dd dtor XCF ends XCFE segment word public 'DATA' XCFE ends else XCB segment word public 'DATA' XCB ends XC segment word public 'DATA' dw dtor XC ends XCE segment word public 'DATA' XCE ends endif endm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Other more or less useful macros ; Commented out ones are obsolete ;setESeqDS macro ;set ES == DS, if not already true ; ife ESeqDS ; push DS ; pop ES ; endif ; endm .push macro list irp arg, push arg endm endm .pop macro list irp arg, pop arg endm endm _push macro list irp arg, push arg endm endm _pop macro list irp arg, pop arg endm endm ; Macros to save and restore regs destroyed by a function .save macro list if SAVESIDI irp arg, push arg endm endif endm .restore macro list if SAVESIDI irp arg, pop arg endm endif endm _save macro list if SAVESIDI irp arg, push arg endm endif endm _restore macro list if SAVESIDI irp arg, pop arg endm endif endm ; Macros to save and restore ES, but only if ESeqDS is 1. ;pushES macro ; if ESeqDS ; push ES ; endif ; endm ; ;popES macro ; if ESeqDS ; pop ES ; endif ; endm clr macro list ;clear a register irp reg, xor reg,reg endm endm tst macro reg test reg,reg endm jmps macro lbl jmp short lbl endm if @Version lt 600 ;For compatibility with MASM 5.10 .if macro arg1,cond,arg2,lbl cmp arg1,arg2 j&cond lbl endm endif _if macro arg1,cond,arg2,lbl cmp arg1,arg2 j&cond lbl endm ;sob macro arg,lbl ; ifidn , ; loop lbl ; else ; dec arg ; jnz lbl ; endif ; endm ifdef _WINDOWS extrn DOS3CALL : far endif ifndef nobdos bdos macro func ifnb mov AH,func endif ifndef _WINDOWS int 21h else call DOS3CALL endif endm dpmi macro func ifnb mov AX,func endif int 31h endm else __bdos macro func ifnb mov AH,func endif ifndef _WINDOWS int 21h else call DOS3CALL endif endm __dpmi macro func ifnb mov AX,func endif int 31h endm endif .retf macro val ;force assembler to build a far return ifnb db 0CAh dw val else db 0CBh endif endm _retf macro val ;force assembler to build a far return ifnb db 0CAh dw val else db 0CBh endif endm ; Sometimes MASM ignores my segment overrides. segES macro db 26h endm ; 32 bit negate neg32 macro reg1,reg2 neg reg1 neg reg2 sbb reg1,0 endm ; Push immediate (reg is for scratch) pushi macro reg,value if 0 push value ;for 286 code generation only else mov reg,value push reg endif endm ; Inc/dec BP if I8086V memory model incBP macro ifdef I8086V inc BP endif endm decBP macro ifdef I8086V dec BP endif endm WINENTER macro ifdef _WINDOWS ifndef I8086S ifndef I8086C inc BP endif endif endif push BP mov BP,SP endm WINLEAVE macro pop BP ifdef _WINDOWS ifndef I8086S ifndef I8086C dec BP endif endif endif endm WINENTER_NF macro ifdef _WINDOWS ifndef I8086S ifndef I8086C inc BP push BP mov BP,SP endif endif endif endm WINLEAVE_NF macro ifdef _WINDOWS ifndef I8086S ifndef I8086C pop BP dec BP endif endif endif endm else ;M_I386 .386P .387 ifdef DOS386 SEG_1ST_MEG equ 034h ;Selector of 1st Mbyte used by MSDOS SEG_SCREEN equ 01ch ;Selector for the video memory. SEG_PSP equ 024H ;PSP selector. SEG_DGROUP equ 014H ;DGROUP selector. SEG_ENV equ 02cH ;Selector of environment string. OMF equ 1 COFF equ 0 ELF equ 0 _FLAT equ 0 ;FLAT memory model _STDCALL equ 0 ;default to _stdcall _RETST0 equ 0 ;return floating point results in ST0 endif ;DOS386 ifdef X386 _FLAT equ 0 _STDCALL equ 0 _RETST0 equ 0 endif ifdef __OS2__ OMF equ 1 COFF equ 0 ELF equ 0 _FLAT equ 1 ;FLAT memory model _STDCALL equ 1 _RETST0 equ 1 _INLINE_8087 equ 1 ;defined if we always generate inline 8087 code endif ifdef __NT__ OMF equ 1 COFF equ 0 ELF equ 0 _FLAT equ 1 _STDCALL equ 0 _RETST0 equ 1 ;_NOCTOR equ 1 ;defined if no static constructors/destructors supported _INLINE_8087 equ 1 ;defined if we always generate inline 8087 code LONGDOUBLE equ 1 ;defined if memory model supports 80 bit long doubles endif ifdef M_XENIX OMF equ 1 ;Set to non-zero if OMF object format. COFF equ 0 ;Set to non-zero if COFF object format. ELF equ 0 _FLAT equ 0 _STDCALL equ 0 _RETST0 equ 0 endif ifdef M_UNIX ifndef OMF OMF equ 0 ;Set to non-zero if OMF object format. endif ifdef M_ELF ifndef ELF ELF equ 1 ;Set to non-zero if ELF object format. endif ifndef COFF COFF equ 0 ;Set to non-zero if COFF object format. endif else ;M_ELF ifndef ELF ELF equ 0 ;Set to non-zero if ELF object format. endif ifndef COFF COFF equ 1 ;Set to non-zero if COFF object format. endif endif ;M_ELF _FLAT equ 0 _STDCALL equ 0 _RETST0 equ 0 endif .ERRNZ OMF AND COFF AND ELF .ERRE OMF OR COFF OR ELF I386 equ 1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Macros specific to each memory model in an attempt to make it easier ; to write memory model independent code. ; begcode,endcode Use to bracket code sections ; begdata,enddata Use to bracket data sections ; begrcode,endrcode Use to bracket real mode code sections ; begrdata,endrdata Use to bracket real mode data sections ; (Pharlap DOS386 only) ; P Offset on EBP to first argument on stack ; Assuming EBP was pushed. ; PS Offset on ESP to first argument on stack ; Assuming nothing was pushed on the stack. ; ESeqDS 1 if ES == DS at all times ; FSeqDS 1 if FS == DS at all times ; GSeqDS 1 if GS == DS at all times ; SSeqDS 1 if SS == DS at all times ; SIZEPTR # of bytes in a pointer ; func Declare a function as NEAR or FAR ; callm Call function as NEAR or FAR ; LPTR Large data model? ; SPTR Small data model? ;Macro for start and end of real mode code segment. begcode_16 macro __X386_CODESEG_16 segment para use16 public 'CODE' assume ds:__X386_GROUP_16 assume cs:__X386_CODESEG_16 endm endcode_16 macro __X386_CODESEG_16 ends endm begcode macro module if _FLAT _TEXT segment para use32 public 'CODE' assume CS:FLAT,DS:FLAT,SS:FLAT else _TEXT segment dword public 'CODE' assume CS:_TEXT endif endm endcode macro module _TEXT ENDS endm begdata macro ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Set up segments for data ; Regular initialized data goes in _DATA _DATA segment dword public 'DATA' _DATA ends ifndef _NOCTOR ;Function pointers to constructors if OMF XIFCB segment dword public 'DATA' XIFCB ends XIFU segment dword public 'DATA' XIFU ends XIFL segment dword public 'DATA' XIFL ends XIFM segment dword public 'DATA' XIFM ends XIFCE segment dword public 'DATA' XIFCE ends XIB segment dword public 'DATA' XIB ends XI segment dword public 'DATA' XI ends XIE segment dword public 'DATA' XIE ends ;Function pointers to destructors XCB segment dword public 'DATA' XCB ends XC segment dword public 'DATA' XC ends XCE segment dword public 'DATA' XCE ends ;Constant data, such as switch tables, go here. CONST segment dword public 'CONST' CONST ends endif ;Segment for uninitialized data. This is set to 0 by the startup code/OS, ;so it does not consume room in the executable file. _BSS segment dword public 'BSS' _BSS ends if OMF ;Function pointers to destructors XOB segment dword public 'BSS' XOB ends XO segment dword public 'BSS' XO ends XOE segment dword public 'BSS' XOE ends endif if OMF ifdef DOS386 HUGE_BSS segment dword public 'HUGE_BSS' HUGE_BSS ends endif EEND segment dword public 'ENDBSS' EEND ends ifdef DOS386 STACK segment para stack 'STACK' STACK ends DGROUP group _DATA,XIFCB,XIFU,XIFL,XIFM,XIFCE,XOB,XO,XOE,XIB,XI,XIE,XCB,XC,XCE,CONST,_BSS,EEND,STACK else ifdef __OS2__ STACK segment para stack 'STACK' STACK ends DGROUP group _DATA,XIFCB,XIFU,XIFL,XIFM,XIFCE,XOB,XO,XOE,XIB,XI,XIE,XCB,XC,XCE,CONST,_BSS,EEND,STACK else ifdef __NT__ STACK segment para stack 'STACK' STACK ends DGROUP group _DATA,XIFCB,XIFU,XIFL,XIFM,XIFCE,XOB,XO,XOE,XIB,XI,XIE,XCB,XC,XCE,CONST,_BSS,EEND,STACK else DGROUP group _DATA,XIB,XI,XIE,XCB,XC,XCE,CONST,_BSS,EEND endif ;__NT__ endif ;__OS2__ endif ;DOS386 else ;OMF if OMF DGROUP group _DATA,XIFCB,XIFU,XIFL,XIFM,XIFCE,XOB,XO,XOE,XIB,XI,XIE,XCB,XC,XCE,CONST,_BSS else DGROUP group _DATA,_BSS endif endif endif _DATA segment if _FLAT assume DS:FLAT else assume DS:DGROUP endif endm enddata macro _DATA ends endm P equ 8 ; Offset of start of parameters on the stack frame ; From EBP assuming EBP was pushed. PS equ 4 ; Offset of start of parameters on the stack frame ; From ESP assuming EBP was NOT pushed. ;; For Win32, ESeqDS should be TRUE ifdef _WIN32 ESeqDS equ 1 else ESeqDS equ 0 endif FSeqDS equ 0 GSeqDS equ 0 SSeqDS equ 1 SIZEPTR equ 4 ; Size of a pointer LPTR equ 0 SPTR equ 1 LCODE equ 0 func macro name _&name proc near ifndef name name equ _&name endif endm callm macro name call _&name endm ;Macros to replace public, extrn, and endp for C-callable assembly routines, ; and to define labels: c_label defines labels, ; c_public replaces public, c_extrn replaces extrn, and c_endp replaces endp c_name macro name name equ _&name endm c_label macro name _&name: endm c_public macro a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z ifnb ;;Check for blank argument public _&a a equ _&a ifnb c_public b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z endif endif endm c_extrn macro a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z ifnb ;;Check for blank argument extrn _&a:b a equ _&a ifnb c_extrn c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z endif endif endm c_endp macro name _&name ENDP endm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Define function ctor as a static constructor static_ctor macro ctor ifndef _NOCTOR if 1 XIFCB segment dword public 'DATA' XIFCB ends XIFU segment dword public 'DATA' ;dd ctor XIFU ends XIFL segment dword public 'DATA' ;dd ctor XIFL ends XIFM segment dword public 'DATA' if _FLAT dd offset FLAT:ctor else dd ctor endif XIFM ends XIFCE segment dword public 'DATA' XIFCE ends else XIB segment dword public 'DATA' XIB ends XI segment dword public 'DATA' if _FLAT dd offset FLAT:ctor else dd ctor endif XI ends XIE segment dword public 'DATA' XIE ends endif endif endm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Define function dtor as a static destructor static_dtor macro dtor ifndef _NOCTOR if 1 XOB segment dword public 'DATA' XOB ends XO segment dword public 'DATA' if _FLAT dd offset FLAT:dtor else dd dtor endif XO ends XOE segment dword public 'DATA' XOE ends else XCB segment dword public 'DATA' XCB ends XC segment dword public 'DATA' if _FLAT dd offset FLAT:dtor else dd dtor endif XC ends XCE segment dword public 'DATA' XCE ends endif endif endm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Other more or less useful macros ;Aligns the code on dword boundary for max speed. _align macro ;MASM 6.0 has a bug where ALIGN 4 produces bogus code when ;2 or 3 bytes of filler are necessary. ifdef @Version if @Version eq 600 if 0 if (($ - _TEXT) and 3) eq 1 db 08Bh,0C0h ;MOV EAX,EAX nop else if (($ - _TEXT) and 3) eq 2 db 08Bh,0C0h ;MOV EAX,EAX else if (($ - _TEXT) and 3) eq 3 nop endif endif endif endif else align 4 ;for MASM 5.1 endif else align 4 ;for 386ASM endif endm _push macro list irp arg, push arg endm endm _pop macro list irp arg, pop arg endm endm _if macro arg1,cond,arg2,lbl cmp arg1,arg2 j&cond lbl endm _ifs macro arg1,cond,arg2,lbl cmp arg1,arg2 j&cond short lbl endm clr macro list ;clear a register irp reg, xor reg,reg endm endm jmps macro lbl jmp short lbl endm tst macro reg test reg,reg endm ifndef nobdos ifdef DOS386 bdos macro func ;DOS system call. ifnb mov AH,func endif int 21h endm endif ;DOS386 ifdef X386 bdos macro func ;DOS system call. ifnb mov AH,func endif int 21h endm endif ;DOS386 ifdef M_XENIX bdos macro func ; 386 XENIX system call. ifnb mov EAX,func endif db 9ah ; call far 0x7:0 dd 0 dw 07h endm endif ;M_XENIX ifdef M_UNIX bdos macro func ; UNIX system call. ifnb mov EAX,func endif db 9ah ; call far 0x7:0 dd 0 dw 07h endm endif ;M_UNIX endif ;nobdos _retf macro val ;force assembler to build a far return ifnb db 0CAh dw val else db 0CBh endif endm _ret macro val ;decide whether caller or callee cleans stack if _STDCALL ret val else ret endif endm ; Macros to save and restore regs destroyed by a function ; Give the macro the list of registers used by the function: ; uses ; ; At exit to function use 'unuse': ; unuse uses macro list irp reg, ifidn , ;Save ebx. push reg endif ifidn , ;Save EBX (bug in ifidni). push reg endif ifidn , ;Save esi. push reg endif ifidn , push reg endif ifidn , ;Save edi. push reg endif ifidn , push reg endif ifidn , ;Save bx. push reg endif ifidn , push reg endif ifidn , ;Save si. push reg endif ifidn , push reg endif ifidn , ;Save di. push reg endif ifidn , push reg endif ifidn , ;Save ds. push reg endif ifidn , push reg endif ifidn , ;Save es. push reg endif ifidn , push reg endif endm endm unuse macro list irp reg, ifidn , ;Restore ebx. pop reg endif ifidn , pop reg endif ifidn , ;Restore esi. pop reg endif ifidn , pop reg endif ifidn , ;Restore edi. pop reg endif ifidn , pop reg endif ifidn , ;Restore bx. pop reg endif ifidn , pop reg endif ifidn , ;Restore si. pop reg endif ifidn , pop reg endif ifidn , ;Restore di. pop reg endif ifidn , pop reg endif ifidn , ;Restore ds. pop reg endif ifidn , pop reg endif ifidn , ;Restore es. pop reg endif ifidn , pop reg endif endm endm endif ;M_I386 ; Executable type EXE_DOS equ 1 ; MSDOS EXE_DOS16RM equ 2 ; Rational 286 DOS Extender EXE_ZPM equ 4 ; ZPM 286 DOS Extender EXE_PHAR386 equ 8 ; Pharlap 386 DOS Extender EXE_DOSX equ 010h ; DOSX 386 DOS Extender EXE_WINDOWS equ 020h ; Windows 3 EXE_OS2 equ 040h ; OS/2 1.x EXE_SCOUNIX equ 080h ; SCO Unix EXE_OS2_2 equ 100h ; OS/2 2.0 EXE_WINDOWSNT equ 200h ; Windows NT