I am writing an INVOKE macro that accepts the calling convention to be used, as the last parameter. The last parameter is optional actually. So the macro will be like

%MACRO INVOKE 1-*


I am defining these also

%DEFINE __STDCALL__


And other calling convention. The problem is that I can not compare a macro parameter with a %DEFINEd when I am not actually assigning a value to it.

For example, in this case, if I set:

%DEFINE __STDCALL__ 0xFFFFFFFF


For all I know, the user could pass 0xFFFFFFFF as a parameter and not the calling-convention specifier. Am I making sense here? I just need, inside the macro, to do a simple:

%IF %1 = __STDCALL__


And then the rest of the code without having to assign a value to __STDCALL__. Is this possible in NASM?
Posted on 2007-12-08 08:20:07 by XCHG
Is the parameter count fixed or variable? If it is fixed, you can check the number of parameters that the function being called is expecting, see if there are any beyond the expected number and process accordingly.

There is a slight problem with a variable number of parameters, as with some CDECL calls, since you can never assume that last parameter can be that optional specifier.

Overall, such ambiguity simply needs to be avoided. In a well defined API, each function already has an expected calling convention that should be adhered to.

What is it that you are trying to achieve with this system? Perhaps there is another solution that can be utilized.
Posted on 2007-12-08 12:23:03 by SpooK
I just need to do this:

%DEFINE __STDCALL__
%DEFINE __CDECL__
%MACRO INVOKE 1-*
  %ROTATE -1
  %IF %1 = __STDCALL__
  %ELIF %1 = __CDECL__
  %ELIF %1 = ...
  %ENDIF
%ENDIF


    :shock:
  /XX\
    ||
  _||_
Posted on 2007-12-08 13:14:50 by XCHG
If you don't ever expect the person to enter in numeric values (as I assume you don't from your last example), the following would be much easier to implement.


%MACRO INVOKE 1-*
    %ROTATE -1
    %IFIDN %1, __STDCALL__
        ; standard calling convention code
    %ELIFIDN %1, __CDECL__
        ; c calling convention code
    %ELIFIDN %1, ...
        ; ... you get the point ...
    %ENDIF
%ENDMACRO


Sorry for a late response, I've been a bit busy lately with finals for this quarter.

Regards,
Bryant Keller
Posted on 2007-12-09 22:01:44 by Synfire
Hey thanks for the code but I think I didn't get how it works because it doesn't work for me :(

  %DEFINE     __STDCALL__
  ; --------------------------------------
  %MACRO DUMMY 1
    %IFIDN %1 , __STDCALL__
      WRITE  'It worked'
    %ELSE
      WRITE  'It does not work'
    %ENDIF
  %ENDM
  ; --------------------------------------
  DUMMY __STDCALL__


This always prints "It does not work"
Posted on 2007-12-10 00:37:47 by XCHG
No %DEFINE's required when using %IFIDN. Below is a self-building source (MAIN.BAT) I wrote up real quick as a demo/proof-of-concept for you. It's not really commented but you look like you got a decent grasp you're just barely missing it.

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; @ECHO OFF
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; SET PROJECT=DEMO
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; SET DRV=C
; SET BIN=\NASM32\BIN
; SET LIB=\NASM32\LIB\WIN32
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; SET AS=NASM.EXE
; SET LD=POLINK.EXE
; SET ASFLAGS=-f win32
; SET LDFLAGS=/SUBSYSTEM:WINDOWS /ENTRY:MAIN
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; SET LIBS=KERNEL32.LIB
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; GOTO BUILD
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; MAIN.BAT - INVK Demo/POC for XCHG
;
; Written by : Bryant Keller
; Assembler  : Netwide Assembler v2.00
; Date       : 10-Dec-2007
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
%MACRO INVK 1-*
%PUSH _INVK_
%DEFINE %$PROC %1
%ROTATE -1
%IFIDN %1, __STDCALL__
; standard calling convention code
%ERROR %$PROC Invoked With Standard Calling Convention
%ELIFIDN %1, __CDECL__
; c calling convention code
%ERROR %$PROC Invoked With C Calling Convention
%ELIFIDN %1, __FASTCALL__
; fast calling convention code
%ERROR %$PROC Invoked With Fast Calling Convention
%ELSE
; ... unknown ...
%ERROR %$PROC Invoked With An Unknown Calling Convention
%ENDIF
%POP
%ENDMACRO


GLOBAL MAIN
MAIN:
%ERROR INVK macro with __STDCALL__
INVK MyProc, 1, 2, 3, 4, __STDCALL__
%ERROR INVK macro with __CDECL__
INVK MyProc, 1, 2, 3, 4, __CDECL__
%ERROR INVK macro with __FASTCALL__
INVK MyProc, 1, 2, 3, 4, __FASTCALL__
%ERROR INVK macro with an unknown/undefined convention
INVK MyProc, 1, 2, 3, 4
XOR eax, eax
PUSH eax
EXTERN _ExitProcess@4
CALL _ExitProcess@4
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; :BUILD
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; IF EXIST MAIN.OBJ DEL MAIN.OBJ
; IF EXIST %PROJECT%.EXE DEL %PROJECT%.EXE
; IF NOT EXIST MAIN.BAT GOTO ERRAS
; %DRV%:%BIN%\%AS% %ASFLAGS% MAIN.BAT -o MAIN.OBJ
; IF ERRORLEVEL 1 GOTO ERRAS
; %DRV%:%BIN%\%LD% %LDFLAGS% /LIBPATH:"%DRV%:%LIB%" MAIN.OBJ %LIBS%
; IF ERRORLEVEL 1 GOTO ERRLD
; IF EXIST MAIN.OBJ DEL MAIN.OBJ
; IF EXIST MAIN.EXE REN MAIN.EXE %PROJECT%.EXE
; DIR /B /A-D
; GOTO DONE
; :ERRAS
; ECHO.
; ECHO Assembly Error
; GOTO DONE
; :ERRLD
; ECHO.
; ECHO Linker Error
; GOTO DONE
; :DONE
; ECHO.
; PAUSE
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::


This is pretty much just preprocessor code, only thing it generates is 'xor eax, eax';'push eax';'call _ExitProcess@4'. Which can be ignored along with the batch code for building. Just save the file as MAIN.BAT then run it and view the output, you will notice that for each INVK line, depending on what the final argument is it takes a different path in the macro (displaying a different error message to the screen at that point because of the %ERROR directives). If you want to learn more about this stuff, check the NASM Manual pages for %IFIDN/%IFIDNI and the negative versions %IFNIDN/%IFNIDNI. One of the most common uses I've seen for it is to overload PUSH/POP/MOV/etc. opcodes so they can "directly" access the EIP/IP register (or appear to anyways). Making code like 'MOV , EIP' possible by overloading MOV and using "%IFIDNI %2, EIP" then handling appropriately. Not really wise as it'll lead to confusion if someone later tries to port that code over to another assembler, but it can cut down on typing and does make EIP seem more like a GPR... But yea, basically those are just doing a direct comparison of the symbol you are passing rather than the symbol's value, so there is no need to use %DEFINE or %ASSIGN before hand.

Regards,
Bryant Keller
Posted on 2007-12-10 19:40:58 by Synfire
Jesus Christ. Read this post Bryant. It took me like 3 days to find what the problem was. Thanks for all the help by the way. It is working now.
Posted on 2007-12-13 08:24:30 by XCHG
Heh, no worries mate. Every once in a while you'll come across small quirks in NASM like that. I didn't check to see if that was causing your error because I figured when you %define'd the symbol with no value and tried to pass it to the macro it was being translated before it reached the %IFIDN so the condition was failing since %1 would no longer equal '__STDCALL__' rather ''. I'm glad you were able to work it out.
Posted on 2007-12-13 11:04:44 by Synfire