Hi, All!

I'm new to asm, so please bear with me on this.

I was wondering how I would go about determining the number of arguments passed via INVOKE, if the proc I'm calling were to support a variable number of arguments that are terminated with a zero?

In looking at the Invoke macro, I figure that I can either divide %$args by four, or I can introduce a new macro var and increment it by one everytime %$args is incremented by four.

Then, just before call _proc, I push the value in the new var onto the stack.  This should end up after the terminating zero mentioned above, correct?


What I'm trying to accomplish is being able to use the proc like so (not real code):


invoke myproc,1,2,3,4,5


and have myproc call an external function, in a loop


proc myproc
argcnt argd

loop1:
  invoke extfunc,argv(something)
  cmp <register>,argcnt
  je somewhere
  dec argcnt ; **probably need to use a register
  jmp loop1
endproc


I know this is ugly and incorrect code, but I'm thinking this through before starting the actual code.  ;)

Thanks in advance for your replies!

AIR.
Posted on 2007-08-29 14:13:16 by Airr
Ah, I should have read the nasm manual.  It appears that %0 is what I was looking for... :oops:

AIR.
Posted on 2007-08-29 15:38:34 by Airr

Ah, I should have read the nasm manual.  It appears that %0 is what I was looking for... :oops:

AIR.


Yep. Keep that manual handy, as just when you think of a complex way to do things in NASM... a simpler one usually exists and just requires "discovery" ;)
Posted on 2007-08-29 19:51:02 by SpooK
I don't think the %0 macro directive is going to help you much here. It's for obtaining the number of parameters passed to a macro, in this case your problem is finding out how many arguments you have on the stack. Probably the easiest way to achieve this for you would be to do your procedure similar to what you are already doing but making a few minor changes.

invoke myproc,7,10,21,13,42,73,85,88
invoke myproc,9,94,16,44,55,12,52,62,30,78
...
;-------------------------------------------
; myproc(argcnt,...)
; argcnt - number of arguments in '...'
;-------------------------------------------
proc myproc
argcnt argd ; contains the number of arguments on the stack

; Note the numbers I used, I based argcnt on 1 index instead
; of 0 index. This adjusts for argcnt to be on the stack, we are
; just skipping over it in our loop. Also take into account in this
; loop we are executing through them right to left, just use an
; extra register to execute through them left to right and test the
; register against argcnt.

  mov ecx, argcnt
.loop1:
  invoke extfunc,argv(ecx*4)
  cmp ecx, 1
  je .done
  dec ecx
  jmp .loop1
.done:
  ret
endproc


I didn't test this code because I'm in the middle of class right now, but it's the basic idea that matters in this case. When I get home, if I remember I might throw some demo-code together for you. I hope this helps you.

Regards,
Bryant Keller
Posted on 2007-08-29 20:56:05 by Synfire
True. Using %0 will only work with things like INVOKE where there is a 1:1 correlation between arguments and parameters *AND* assuming that all parameters are DWORD values.

Didn't think about it too much since he specified NASM32/INVOKE.
Posted on 2007-08-29 21:26:45 by SpooK
What I was thinking of doing with %0 was pushing it on the stack last (from within the invoke macro), and then in the proc using argd to retrieve the count.  This would eliminate the need to specify the number of arguments manually in the invoke "call", as Synfire suggested.  If it works.

I *think* this might work, I'll let you know how it turns out....

AIR.

Posted on 2007-08-29 22:55:07 by Airr
Yea, that would work if you modified invoke, or made an invoke wrapper.

%imacro vinvoke 1-*
%define fname %1
%assign %$args 0
%rep %0-1
  %rotate -1
  %ifstr %1
    jmp %%endstr_%$args
    %%str_%$args: db %1, 0
    %%endstr_%$args:
    push dword %%str_%$args
  %else
    push dword %1
  %endif
  %assign %$args %$args+4
%endrep
invoke fname, %0
%undef fname
%endmacro


Or design it from the ground up. If you go from the ground up, make sure to pay close attention to how the various macros work together internally. Due to the vague reply I was under the impression that you were going to try and use %0 in the procedure itself, not create a new invoke macro. It was my bad.
Posted on 2007-08-29 23:57:06 by Synfire
One suggestion for Variable Argument procedures or functions: Use a calling convention such as STDCALL where parameters are pushed from right to left into the stack. After having pushed all of the parameters, then push the number of parameters that you have pushed onto the stack and not a zero. So if you have pushed 5 parameters onto the stack namely Param1, Param2, Param3, Param4 and Param5, then you have to push them like this:

  
  PUSH    Param5    ; Last Parameter
  PUSH    Param4    ; Second to last parameter
  PUSH    Param3    ; Third parameter
  PUSH    Param2    ; Second parameter
  PUSH    Param1    ; First parameter
  PUSH    DWORD 5  ; Total number of parmaters passed onto the stack



In your code, you can then simply access the last parameter pushed onto the stack and determine how many parameters are pushed in total.
Posted on 2007-08-30 23:52:39 by XCHG
After having pushed all of the parameters, then push the number of parameters that you have pushed onto the stack and not a zero.


That's what is being done. The %0 is a NASM macro directive which returns the number of arguments passed to a macro. So if invoke was called with 5 parameters %0 would be 5.

Correction to my code:
The line: invoke fname, %0
Should be: invoke fname, %0-1

I typed it up pretty quick and forgot to take into account the function name in the parameter list.
Posted on 2007-08-31 17:05:30 by Synfire
I think there was a misinterpretation on my side. Bryant, I did not post that code to give you the idea; in fact, I hadn't read any of the replies. I had just read the original post and when I noticedthat was talking about pushing a zero to the stack, I thought he/she wanted to push the DWORD value of 0x00000000 into the stack to mark the end of the arguments' list. I was not at all judging the accuracy of your code.
Posted on 2007-09-01 10:05:09 by XCHG
The correction to my code was just a side note because I noticed it while replying. Sorry for not really separating it better. :oops:
Posted on 2007-09-01 10:54:13 by Synfire