coff: Cover 'else' with cond compilation
[nasm/sigaren-mirror.git] / misc / proc32.ash
blobf513b733d885bb955db9afca1cc5eb2d65257c3c
1 ;--------=========xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=========--------
3 ;   Copyright (C) 1999 by Andrew Zabolotny
4 ;   Miscelaneous NASM macros that makes use of new preprocessor features
5
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.
10
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.
15
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:
26 ;       proc    sin,1
27 ;               targ    %$angle
28 ;               fld     %$angle
29 ;               fsin
30 ;       endproc sin
32 %ifndef __PROC32_ASH__
33 %define __PROC32_ASH__
35 [WARNING -macro-selfref]
37 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
38 ; Summary:
39 ;   Mangle a name to be compatible with the C compiler
40 ; Arguments:
41 ;   The name
42 ; Example:
43 ;               cname (my_func)
44 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
45 %ifdef EXTERNC_UNDERSCORE
46                 %define cname(x) _ %+ x
47 %else
48                 %define cname(x) x
49 %endif
51 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
52 ; Summary:
53 ;   Import an external C procedure definition
54 ; Arguments:
55 ;   The name of external C procedure
56 ; Example:
57 ;               cextern printf
58 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
59 %macro          cextern 1
60                 %xdefine %1 cname(%1)
61         %ifidni __OUTPUT_FORMAT__,obj
62                 extern  %1:wrt FLAT
63         %else
64                 extern  %1
65         %endif
66 %endmacro
68 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
69 ; Summary:
70 ;   Export an C procedure definition
71 ; Arguments:
72 ;   The name of C procedure
73 ; Example:
74 ;               cglobal my_printf
75 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
76 %macro          cglobal 1
77                 %xdefine %1 cname(%1)
78                 global  %1
79 %endmacro
81 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
82 ; Summary:
83 ;   Misc macros to deal with PIC shared libraries
84 ; Comment:
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
90 ; Example:
91 ;               extvar  myvar
92 ;               GetGOT
93 ;       %ifdef PIC
94 ;               mov     ebx,myvar       ; get offset of myvar into ebx
95 ;       %else
96 ;               lea     ebx,myvar
97 ;       %endif
98 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
99 %ifdef PIC
100                 cextern _GLOBAL_OFFSET_TABLE_
101         %macro  GetGOT  0
102                 %ifdef .$proc.stkofs
103                         %assign .$proc.stkofs .$proc.stkofs+4
104                 %endif
105                 call    %$Get_GOT
106         %$Get_GOT:
107                 pop     ebx
108                 add     ebx,_GLOBAL_OFFSET_TABLE_ + $$ - %$Get_GOT wrt ..gotpc
109         %endmacro
110         %macro  extvar  1
111                 cextern %1
112                 %xdefine %1 [ebx+%1 wrt ..got]
113         %endmacro
114 %else
115         %define GetGOT
116         %macro  extvar  1
117                 cextern %1
118         %endmacro
119 %endif
121 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
122 ; Summary:
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.
129 ; Arguments:
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
134 ; Example:
135 ;   proc        MyTestProc
136 ;   proc        MyTestProc,4,ebx,esi,edi
137 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
138 %macro          proc    1-3+ 0
139                 cglobal %1
140                 %push   %1
141                 align   16
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
156         %endif
157                 push    %$proc.save
158 %endmacro
160 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
161 ; Summary:
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
166 ; Arguments:
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)
170 ; Example:
171 ;               arg     .my_float
172 ;               arg     .my_double,8
173 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
174 %macro          arg     1-2 4
175         %ifndef %$proc.argofs
176                 %error  "`arg' not in a proc context"
177         %else
178         ; Trick: temporary undefine .$proc.stkofs so that it won't be expanded
179                 %assign %%. .$proc.stkofs
180                 %undef .$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
185         %endif
186 %endmacro
188 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
189 ; Summary:
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
193 ; Arguments:
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)
197 ; Example:
198 ;               loc     .int_value
199 ;               loc     .double_value,8
200 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
201 %macro          loc     1-2 4
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"
206         %else
207                 %assign %%. .$proc.stkofs
208                 %undef .$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
213         %endif
214 %endmacro
216 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
217 ; Summary:
218 ;   Get the type of given size into context-local variable %$type
219 ; Arguments:
220 ;   Size of type we want (1,2,4,8 or 10)
221 ; Example:
222 ;               type    4       ; gives "dword"
223 ;               type    10      ; gives "tword"
224 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
225 %macro          type    1
226         %if %1 = 1
227                 %define %$type byte
228         %elif %1 = 2
229                 %define %$type word
230         %elif %1 = 4
231                 %define %$type dword
232         %elif %1 = 8
233                 %define %$type qword
234         %elif %1 = 10
235                 %define %$type tword
236         %else
237                 %define %$. %1
238                 %error "unknown type for argument size %$."
239         %endif
240 %endmacro
242 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
243 ; Summary:
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
247 ; Arguments:
248 ;   Same as for `arg'
249 ; Example:
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======-----
253 %macro          targ    1-2 4
254         %ifndef %$proc.argofs
255                 %error  "`targ' not in a proc context"
256         %else
257                 arg     %1,%2
258                 type    %2
259                 %assign %%. .$proc.stkofs
260                 %undef .$proc.stkofs
261                 %xdefine %1 %$type %1
262                 %assign .$proc.stkofs %%.
263         %endif
264 %endmacro
266 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
267 ; Summary:
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
271 ; Arguments:
272 ;   Same as for `loc'
273 ; Example:
274 ;               tloc    int_value
275 ;               tloc    double_value,8
276 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
277 %macro          tloc    1-2 4
278         %ifndef %$proc.locofs
279                 %error  "`tloc' not in a proc context"
280         %else
281                 loc     %1,%2
282                 type    %2
283                 %assign %%. .$proc.stkofs
284                 %undef .$proc.stkofs
285                 %xdefine %1 %$type %1
286                 %assign .$proc.stkofs %%.
287         %endif
288 %endmacro
290 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
291 ; Summary:
292 ;   Finish a procedure
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
296 ; Arguments:
297 ;   (optional) The name of procedure
298 ; Example:
299 ;   endproc     MyTestProc
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
306                 %define %$. %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)"
311         %else
312 %$exit:
313         ; Now pop the registers that we should restore on exit
314                 pop     %$proc.save
315                 %if %$proc.locsize != 0
316                 add     esp,%$proc.locsize
317                 %endif
318                 ret
319 __end_%1:
320                 %pop
321         %endif
322 %endmacro
323 %pop
325 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
326 ; Summary:
327 ;   A replacement for "push" for use within procedures
328 ; Arguments:
329 ;   any number of registers which will be push'ed successively
330 ; Example:
331 ;               push    eax,ebx,ecx,edx
332 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
333 %macro          push    0-*
334 ; dummy comment to avoid problems with "push" on the same line with a label
335         %rep    %0
336                 push    %1
337                 %rotate 1
338                 %assign .$proc.stkofs .$proc.stkofs+4
339         %endrep
340 %endmacro
342 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
343 ; Summary:
344 ;   A replacement for "pop" for use within procedures
345 ; Arguments:
346 ;   any number of registers which will be pop'ed in reverse order
347 ; Example:
348 ;               pop     eax,ebx,ecx,edx
349 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
350 %macro          pop     0-*
351 ; dummy comment to avoid problems with "pop" on the same line with a label
352         %rep    %0
353                 %rotate -1
354                 pop     %1
355                 %assign .$proc.stkofs .$proc.stkofs-4
356         %endrep
357 %endmacro
359 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
360 ; Summary:
361 ;   Replacements for "pushfd" and "popfd" that takes care of esp
362 ; Example:
363 ;               pushfd
364 ;               popfd
365 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
366 %macro          pushfd  0
367                 pushfd
368                 %assign .$proc.stkofs .$proc.stkofs+4
369 %endmacro
370 %macro          popfd   0
371                 popfd
372                 %assign .$proc.stkofs .$proc.stkofs-4
373 %endmacro
375 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
376 ; Summary:
377 ;   Exit from current procedure (optionally on given condition)
378 ; Arguments:
379 ;   Either none or a condition code
380 ; Example:
381 ;               exit
382 ;               exit    nz
383 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
384 %macro          exit    0-1 mp
385                 j%1     near %$exit
386 %endmacro
388 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
389 ; Summary:
390 ;   start an conditional branch
391 ; Arguments:
392 ;   A condition code
393 ;   second (optional) argument - "short" (by default - "near")
394 ; Example:
395 ;               if      nz
396 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
397 %macro          if      1-2 near
398 ; dummy comment to avoid problems with "if" on the same line with a label
399                 %push   if
400                 j%-1    %2 %$elseif
401 %endmacro
403 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
404 ; Summary:
405 ;   define the "else" branch of a conditional statement
406 ; Arguments:
407 ;   optionaly: "short" if jmp to endif is less than 128 bytes away
408 ; Example:
409 ;               else
410 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
411 %macro          else    0-1
412         %ifnctx if
413                 %error  "`else' without matching `if'"
414         %else
415                 jmp     %1 %$endif
416 %$elseif:
417                 %define %$elseif_defined
418         %endif
419 %endmacro
421 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
422 ; Summary:
423 ;   Finish am conditional statement
424 ; Arguments:
425 ;   none
426 ; Example:
427 ;               endif
428 ;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======-----
429 %macro          endif   0
430         %ifnctx if
431                 %error  "`endif' without matching `if'"
432         %else
433                 %ifndef %$elseif_defined
434 %$elseif:
435                 %endif
436 %$endif:
437                 %pop
438         %endif
439 %endmacro
441 %endif ; __PROC32_ASH__