mirror of
				https://github.com/netwide-assembler/nasm.git
				synced 2025-10-10 00:25:06 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			442 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			442 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
;--------=========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__
 |