| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442 |
- ;--------=========xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=========--------
- ;
- ; Copyright (C) 1999 by Andrew Zabolotny
- ; Miscelaneous NASM macros that makes use of new preprocessor features
- ;
- ; This library is free software; you can redistribute it and/or
- ; modify it under the terms of the GNU Library General Public
- ; License as published by the Free Software Foundation; either
- ; version 2 of the License, or (at your option) any later version.
- ;
- ; This library is distributed in the hope that it will be useful,
- ; but WITHOUT ANY WARRANTY; without even the implied warranty of
- ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- ; Library General Public License for more details.
- ;
- ; You should have received a copy of the GNU Library General Public
- ; License along with this library; if not, write to the Free
- ; Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- ;
- ;--------=========xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=========--------
- ; The macros in this file provides support for writing 32-bit C-callable
- ; NASM routines. For a short description of every macros see the
- ; corresponding comment before every one. Simple usage example:
- ;
- ; proc sin,1
- ; targ %$angle
- ; fld %$angle
- ; fsin
- ; endproc sin
- %ifndef __PROC32_ASH__
- %define __PROC32_ASH__
- [WARNING -macro-selfref]
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- ; Summary:
- ; Mangle a name to be compatible with the C compiler
- ; Arguments:
- ; The name
- ; Example:
- ; cname (my_func)
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- %ifdef EXTERNC_UNDERSCORE
- %define cname(x) _ %+ x
- %else
- %define cname(x) x
- %endif
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- ; Summary:
- ; Import an external C procedure definition
- ; Arguments:
- ; The name of external C procedure
- ; Example:
- ; cextern printf
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- %macro cextern 1
- %xdefine %1 cname(%1)
- %ifidni __OUTPUT_FORMAT__,obj
- extern %1:wrt FLAT
- %else
- extern %1
- %endif
- %endmacro
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- ; Summary:
- ; Export an C procedure definition
- ; Arguments:
- ; The name of C procedure
- ; Example:
- ; cglobal my_printf
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- %macro cglobal 1
- %xdefine %1 cname(%1)
- global %1
- %endmacro
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- ; Summary:
- ; Misc macros to deal with PIC shared libraries
- ; Comment:
- ; Note that we have a different syntax for working with and without
- ; PIC shared libraries. In a PIC environment we should load first
- ; the address of the variable into a register and then work through
- ; that address, i.e: mov eax,myvar; mov [eax],1
- ; In a non-PIC environment we should directly write: mov myvar,1
- ; Example:
- ; extvar myvar
- ; GetGOT
- ; %ifdef PIC
- ; mov ebx,myvar ; get offset of myvar into ebx
- ; %else
- ; lea ebx,myvar
- ; %endif
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- %ifdef PIC
- cextern _GLOBAL_OFFSET_TABLE_
- %macro GetGOT 0
- %ifdef .$proc.stkofs
- %assign .$proc.stkofs .$proc.stkofs+4
- %endif
- call %$Get_GOT
- %$Get_GOT:
- pop ebx
- add ebx,_GLOBAL_OFFSET_TABLE_ + $$ - %$Get_GOT wrt ..gotpc
- %endmacro
- %macro extvar 1
- cextern %1
- %xdefine %1 [ebx+%1 wrt ..got]
- %endmacro
- %else
- %define GetGOT
- %macro extvar 1
- cextern %1
- %endmacro
- %endif
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- ; Summary:
- ; Begin a procedure definition
- ; For performance reasons we don't use stack frame pointer EBP,
- ; instead we're using the [esp+xx] addressing. Because of this
- ; you should be careful when you work with stack pointer.
- ; The push/pop instructions are macros that are defined to
- ; deal correctly with these issues.
- ; Arguments:
- ; First argument - the procedure name
- ; Second optional argument - the number of bytes for local variables
- ; The following arguments could specify the registers that should be
- ; pushed at beginning of procedure and popped before exiting
- ; Example:
- ; proc MyTestProc
- ; proc MyTestProc,4,ebx,esi,edi
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- %macro proc 1-3+ 0
- cglobal %1
- %push %1
- align 16
- %1:
- %xdefine %$proc.name %1
- ; total size of local arguments
- %assign %$proc.locsize (%2+3) & 0xFFFC
- ; offset from esp to argument
- %assign %$proc.argofs 4+%$proc.locsize
- ; additional offset to args (tracks push/pops)
- %assign .$proc.stkofs 0
- ; offset from esp to local arguments
- %assign %$proc.locofs 0
- ; Now push the registers that we should save
- %define %$proc.save %3
- %if %$proc.locsize != 0
- sub esp,%$proc.locsize
- %endif
- push %$proc.save
- %endmacro
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- ; Summary:
- ; Declare an argument passed on stack
- ; This macro defines two additional macros:
- ; first (with the name given by first argument) - [esp+xx]
- ; second (with a underscore appended to first argument) - esp+xx
- ; Arguments:
- ; First argument defines the procedure argument name
- ; Second optional parameter defines the size of the argument
- ; Default value is 4 (a double word)
- ; Example:
- ; arg .my_float
- ; arg .my_double,8
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- %macro arg 1-2 4
- %ifndef %$proc.argofs
- %error "`arg' not in a proc context"
- %else
- ; Trick: temporary undefine .$proc.stkofs so that it won't be expanded
- %assign %%. .$proc.stkofs
- %undef .$proc.stkofs
- %xdefine %{1}_ esp+%$proc.argofs+.$proc.stkofs
- %xdefine %1 [esp+%$proc.argofs+.$proc.stkofs]
- %assign .$proc.stkofs %%.
- %assign %$proc.argofs %2+%$proc.argofs
- %endif
- %endmacro
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- ; Summary:
- ; Declare an local variable
- ; first (with the name given by first argument) - [esp+xx]
- ; second (with a slash prefixing the first argument) - esp+xx
- ; Arguments:
- ; First argument defines the procedure argument name
- ; Second optional parameter defines the size of the argument
- ; Default value is 4 (a double word)
- ; Example:
- ; loc .int_value
- ; loc .double_value,8
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- %macro loc 1-2 4
- %ifndef %$proc.locofs
- %error "`loc' not in a proc context"
- %elif %$proc.locofs + %2 > %$proc.locsize
- %error "local stack space exceeded"
- %else
- %assign %%. .$proc.stkofs
- %undef .$proc.stkofs
- %xdefine %{1}_ esp+%$proc.locofs+.$proc.stkofs
- %xdefine %1 [esp+%$proc.locofs+.$proc.stkofs]
- %assign .$proc.stkofs %%.
- %assign %$proc.locofs %$proc.locofs+%2
- %endif
- %endmacro
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- ; Summary:
- ; Get the type of given size into context-local variable %$type
- ; Arguments:
- ; Size of type we want (1,2,4,8 or 10)
- ; Example:
- ; type 4 ; gives "dword"
- ; type 10 ; gives "tword"
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- %macro type 1
- %if %1 = 1
- %define %$type byte
- %elif %1 = 2
- %define %$type word
- %elif %1 = 4
- %define %$type dword
- %elif %1 = 8
- %define %$type qword
- %elif %1 = 10
- %define %$type tword
- %else
- %define %$. %1
- %error "unknown type for argument size %$."
- %endif
- %endmacro
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- ; Summary:
- ; Same as `arg' but prepends "word", "dword" etc (typed arg)
- ; first (with the name given by first argument) - dword [esp+xx]
- ; second (with a slash prefixing the first argument) - esp+xx
- ; Arguments:
- ; Same as for `arg'
- ; Example:
- ; targ .my_float ; .my_float is now "dword [esp+xxx]"
- ; targ .my_double,8 ; .my_double is now "qword [esp+xxx]"
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- %macro targ 1-2 4
- %ifndef %$proc.argofs
- %error "`targ' not in a proc context"
- %else
- arg %1,%2
- type %2
- %assign %%. .$proc.stkofs
- %undef .$proc.stkofs
- %xdefine %1 %$type %1
- %assign .$proc.stkofs %%.
- %endif
- %endmacro
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- ; Summary:
- ; Same as `loc' but prepends "word", "dword" etc (typed loc)
- ; first (with the name given by first argument) - dword [esp+xx]
- ; second (with a slash prefixing the first argument) - esp+xx
- ; Arguments:
- ; Same as for `loc'
- ; Example:
- ; tloc int_value
- ; tloc double_value,8
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- %macro tloc 1-2 4
- %ifndef %$proc.locofs
- %error "`tloc' not in a proc context"
- %else
- loc %1,%2
- type %2
- %assign %%. .$proc.stkofs
- %undef .$proc.stkofs
- %xdefine %1 %$type %1
- %assign .$proc.stkofs %%.
- %endif
- %endmacro
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- ; Summary:
- ; Finish a procedure
- ; Gives an error if proc/endproc pairs mismatch
- ; Defines an label called __end_(procedure name)
- ; which is useful for calculating function size
- ; Arguments:
- ; (optional) The name of procedure
- ; Example:
- ; endproc MyTestProc
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- %push tmp ; trick: define a dummy context to avoid error in next line
- %macro endproc 0-1 %$proc.name
- %ifndef %$proc.argofs
- %error "`endproc' not in a proc context"
- %elifnidn %$proc.name,%1
- %define %$. %1
- %error "endproc names mismatch: expected `%$proc.name'"
- %error "but got `%$.' instead"
- %elif %$proc.locofs < %$proc.locsize
- %error "unused local space declared (used %$proc.locofs, requested %$proc.locsize)"
- %else
- %$exit:
- ; Now pop the registers that we should restore on exit
- pop %$proc.save
- %if %$proc.locsize != 0
- add esp,%$proc.locsize
- %endif
- ret
- __end_%1:
- %pop
- %endif
- %endmacro
- %pop
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- ; Summary:
- ; A replacement for "push" for use within procedures
- ; Arguments:
- ; any number of registers which will be push'ed successively
- ; Example:
- ; push eax,ebx,ecx,edx
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- %macro push 0-*
- ; dummy comment to avoid problems with "push" on the same line with a label
- %rep %0
- push %1
- %rotate 1
- %assign .$proc.stkofs .$proc.stkofs+4
- %endrep
- %endmacro
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- ; Summary:
- ; A replacement for "pop" for use within procedures
- ; Arguments:
- ; any number of registers which will be pop'ed in reverse order
- ; Example:
- ; pop eax,ebx,ecx,edx
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- %macro pop 0-*
- ; dummy comment to avoid problems with "pop" on the same line with a label
- %rep %0
- %rotate -1
- pop %1
- %assign .$proc.stkofs .$proc.stkofs-4
- %endrep
- %endmacro
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- ; Summary:
- ; Replacements for "pushfd" and "popfd" that takes care of esp
- ; Example:
- ; pushfd
- ; popfd
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- %macro pushfd 0
- pushfd
- %assign .$proc.stkofs .$proc.stkofs+4
- %endmacro
- %macro popfd 0
- popfd
- %assign .$proc.stkofs .$proc.stkofs-4
- %endmacro
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- ; Summary:
- ; Exit from current procedure (optionally on given condition)
- ; Arguments:
- ; Either none or a condition code
- ; Example:
- ; exit
- ; exit nz
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- %macro exit 0-1 mp
- j%1 near %$exit
- %endmacro
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- ; Summary:
- ; start an conditional branch
- ; Arguments:
- ; A condition code
- ; second (optional) argument - "short" (by default - "near")
- ; Example:
- ; if nz
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- %macro if 1-2 near
- ; dummy comment to avoid problems with "if" on the same line with a label
- %push if
- j%-1 %2 %$elseif
- %endmacro
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- ; Summary:
- ; define the "else" branch of a conditional statement
- ; Arguments:
- ; optionaly: "short" if jmp to endif is less than 128 bytes away
- ; Example:
- ; else
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- %macro else 0-1
- %ifnctx if
- %error "`else' without matching `if'"
- %else
- jmp %1 %$endif
- %$elseif:
- %define %$elseif_defined
- %endif
- %endmacro
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- ; Summary:
- ; Finish am conditional statement
- ; Arguments:
- ; none
- ; Example:
- ; endif
- ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
- %macro endif 0
- %ifnctx if
- %error "`endif' without matching `if'"
- %else
- %ifndef %$elseif_defined
- %$elseif:
- %endif
- %$endif:
- %pop
- %endif
- %endmacro
- %endif ; __PROC32_ASH__
|