1 ;--------=========xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=========--------
3 ; Copyright (C) 1999 by Andrew Zabolotny
4 ; Miscelaneous NASM macros that makes use of new preprocessor features
6 ; This library is free software; you can redistribute it and/or
7 ; modify it under the terms of the GNU Library General Public
8 ; License as published by the Free Software Foundation; either
9 ; version 2 of the License, or (at your option) any later version.
11 ; This library is distributed in the hope that it will be useful,
12 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 ; Library General Public License for more details.
16 ; You should have received a copy of the GNU Library General Public
17 ; License along with this library; if not, write to the Free
18 ; Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 ;--------=========xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=========--------
22 ; The macros in this file provides support for writing 32-bit C-callable
23 ; NASM routines. For a short description of every macros see the
24 ; corresponding comment before every one. Simple usage example:
32 %ifndef __PROC32_ASH__
33 %define __PROC32_ASH__
35 [WARNING -macro-selfref]
37 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
39 ; Mangle a name to be compatible with the C compiler
44 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
45 %ifdef EXTERNC_UNDERSCORE
46 %define cname(x) _ %+ x
51 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
53 ; Import an external C procedure definition
55 ; The name of external C procedure
58 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
61 %ifidni __OUTPUT_FORMAT__,obj
68 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
70 ; Export an C procedure definition
72 ; The name of C procedure
75 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
81 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
83 ; Misc macros to deal with PIC shared libraries
85 ; Note that we have a different syntax for working with and without
86 ; PIC shared libraries. In a PIC environment we should load first
87 ; the address of the variable into a register and then work through
88 ; that address, i.e: mov eax,myvar; mov [eax],1
89 ; In a non-PIC environment we should directly write: mov myvar,1
94 ; mov ebx,myvar ; get offset of myvar into ebx
98 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
100 cextern _GLOBAL_OFFSET_TABLE_
103 %assign .$proc.stkofs .$proc.stkofs+4
108 add ebx,_GLOBAL_OFFSET_TABLE_ + $$ - %$Get_GOT wrt ..gotpc
112 %xdefine %1 [ebx+%1 wrt ..got]
121 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
123 ; Begin a procedure definition
124 ; For performance reasons we don't use stack frame pointer EBP,
125 ; instead we're using the [esp+xx] addressing. Because of this
126 ; you should be careful when you work with stack pointer.
127 ; The push/pop instructions are macros that are defined to
128 ; deal correctly with these issues.
130 ; First argument - the procedure name
131 ; Second optional argument - the number of bytes for local variables
132 ; The following arguments could specify the registers that should be
133 ; pushed at beginning of procedure and popped before exiting
136 ; proc MyTestProc,4,ebx,esi,edi
137 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
143 %xdefine %$proc.name %1
144 ; total size of local arguments
145 %assign %$proc.locsize (%2+3) & 0xFFFC
146 ; offset from esp to argument
147 %assign %$proc.argofs 4+%$proc.locsize
148 ; additional offset to args (tracks push/pops)
149 %assign .$proc.stkofs 0
150 ; offset from esp to local arguments
151 %assign %$proc.locofs 0
152 ; Now push the registers that we should save
153 %define %$proc.save %3
154 %if %$proc.locsize != 0
155 sub esp,%$proc.locsize
160 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
162 ; Declare an argument passed on stack
163 ; This macro defines two additional macros:
164 ; first (with the name given by first argument) - [esp+xx]
165 ; second (with a underscore appended to first argument) - esp+xx
167 ; First argument defines the procedure argument name
168 ; Second optional parameter defines the size of the argument
169 ; Default value is 4 (a double word)
173 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
175 %ifndef %$proc.argofs
176 %error "`arg' not in a proc context"
178 ; Trick: temporary undefine .$proc.stkofs so that it won't be expanded
179 %assign %%. .$proc.stkofs
181 %xdefine %{1}_ esp+%$proc.argofs+.$proc.stkofs
182 %xdefine %1 [esp+%$proc.argofs+.$proc.stkofs]
183 %assign .$proc.stkofs %%.
184 %assign %$proc.argofs %2+%$proc.argofs
188 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
190 ; Declare an local variable
191 ; first (with the name given by first argument) - [esp+xx]
192 ; second (with a slash prefixing the first argument) - esp+xx
194 ; First argument defines the procedure argument name
195 ; Second optional parameter defines the size of the argument
196 ; Default value is 4 (a double word)
199 ; loc .double_value,8
200 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
202 %ifndef %$proc.locofs
203 %error "`loc' not in a proc context"
204 %elif %$proc.locofs + %2 > %$proc.locsize
205 %error "local stack space exceeded"
207 %assign %%. .$proc.stkofs
209 %xdefine %{1}_ esp+%$proc.locofs+.$proc.stkofs
210 %xdefine %1 [esp+%$proc.locofs+.$proc.stkofs]
211 %assign .$proc.stkofs %%.
212 %assign %$proc.locofs %$proc.locofs+%2
216 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
218 ; Get the type of given size into context-local variable %$type
220 ; Size of type we want (1,2,4,8 or 10)
222 ; type 4 ; gives "dword"
223 ; type 10 ; gives "tword"
224 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
238 %error "unknown type for argument size %$."
242 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
244 ; Same as `arg' but prepends "word", "dword" etc (typed arg)
245 ; first (with the name given by first argument) - dword [esp+xx]
246 ; second (with a slash prefixing the first argument) - esp+xx
250 ; targ .my_float ; .my_float is now "dword [esp+xxx]"
251 ; targ .my_double,8 ; .my_double is now "qword [esp+xxx]"
252 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
254 %ifndef %$proc.argofs
255 %error "`targ' not in a proc context"
259 %assign %%. .$proc.stkofs
261 %xdefine %1 %$type %1
262 %assign .$proc.stkofs %%.
266 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
268 ; Same as `loc' but prepends "word", "dword" etc (typed loc)
269 ; first (with the name given by first argument) - dword [esp+xx]
270 ; second (with a slash prefixing the first argument) - esp+xx
275 ; tloc double_value,8
276 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
278 %ifndef %$proc.locofs
279 %error "`tloc' not in a proc context"
283 %assign %%. .$proc.stkofs
285 %xdefine %1 %$type %1
286 %assign .$proc.stkofs %%.
290 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
293 ; Gives an error if proc/endproc pairs mismatch
294 ; Defines an label called __end_(procedure name)
295 ; which is useful for calculating function size
297 ; (optional) The name of procedure
300 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
301 %push tmp ; trick: define a dummy context to avoid error in next line
302 %macro endproc 0-1 %$proc.name
303 %ifndef %$proc.argofs
304 %error "`endproc' not in a proc context"
305 %elifnidn %$proc.name,%1
307 %error "endproc names mismatch: expected `%$proc.name'"
308 %error "but got `%$.' instead"
309 %elif %$proc.locofs < %$proc.locsize
310 %error "unused local space declared (used %$proc.locofs, requested %$proc.locsize)"
313 ; Now pop the registers that we should restore on exit
315 %if %$proc.locsize != 0
316 add esp,%$proc.locsize
325 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
327 ; A replacement for "push" for use within procedures
329 ; any number of registers which will be push'ed successively
331 ; push eax,ebx,ecx,edx
332 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
334 ; dummy comment to avoid problems with "push" on the same line with a label
338 %assign .$proc.stkofs .$proc.stkofs+4
342 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
344 ; A replacement for "pop" for use within procedures
346 ; any number of registers which will be pop'ed in reverse order
348 ; pop eax,ebx,ecx,edx
349 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
351 ; dummy comment to avoid problems with "pop" on the same line with a label
355 %assign .$proc.stkofs .$proc.stkofs-4
359 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
361 ; Replacements for "pushfd" and "popfd" that takes care of esp
365 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
368 %assign .$proc.stkofs .$proc.stkofs+4
372 %assign .$proc.stkofs .$proc.stkofs-4
375 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
377 ; Exit from current procedure (optionally on given condition)
379 ; Either none or a condition code
383 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
388 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
390 ; start an conditional branch
393 ; second (optional) argument - "short" (by default - "near")
396 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
398 ; dummy comment to avoid problems with "if" on the same line with a label
403 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
405 ; define the "else" branch of a conditional statement
407 ; optionaly: "short" if jmp to endif is less than 128 bytes away
410 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
413 %error "`else' without matching `if'"
417 %define %$elseif_defined
421 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
423 ; Finish am conditional statement
428 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
431 %error "`endif' without matching `if'"
433 %ifndef %$elseif_defined
441 %endif ; __PROC32_ASH__