Author Topic: scall macro  (Read 16100 times)

nobody

  • Guest
scall macro
« on: December 23, 2008, 04:42:43 AM »
Hi all
Here is my scall macro, I have been working on lately. It is intended to be used with Golink, no Imports.
It's the macro from Nagoa package that I have slightly modified.

Two problems:   -no matter how I rotate, I cannot get the right position for the argument passed with ADDR
               I will get ERROR  t1.asm:53: error: comma or end of line expected
               or I will get the address of the Argument to the left. Or it will create a string in data “ADDR” and return a                pointer to it
               -%elifid and %elifnum branches never execute. I think If I scall Function,1 it should go trough the
               %elifnum branch


%define ADDR "ADDR_",

%macro scall 1-*.nolist ;Windows StdCall: push last value first, no cleanup
%ifndef %1_defined      ;define external functions
   extern %1
%endif
%define _proc %1
%rep %0-1
    %rotate -1
   %ifidni %1,"ADDR_"
         ;%error "ADDR is used"
         ;%rotate -1
         lea    eax,   [%1]
         push   eax
         %rotate 1
   %elifstr %1
      ;;;;;%ifstr %-1
         ;%error "We have a string argument"
         mac_pushstring %1
   %elifid
         push dword %1
         %error "We have a label"
   %elifnum
         push dword %1
         %error "We have a number"
   %else
      ;%error "unspecified Argument"
      push dword %1
    %endif
%endrep
    call _proc
%endmacro   


PROC proc1,string
   LOCAL val,4
   LOCAL buf,4
   mov D[@val],1
   mov D[@buf],2
   scall HexPrint,ADDR [@string]      ;ebp+8
   scall HexPrint, ADDR [@val]      ;ebp-4
   scall HexPrint,ADDR [@buf]      ;ebp-8
ENDP


Start:
   lcall proc1,textout
   scall   ExitProcess, 0

Any suggestions would be most appriciated,

Klod

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: scall macro
« Reply #1 on: December 24, 2008, 07:27:57 PM »
Hi Klod,

Jeez, that's a tricky one!!! At first, I didn't see how this was going to work at all. "ADDR foo" is *one* parameter, we're going to have to "parse" it, right? Wrong! My tired old eyes were missing the comma in the %define. We're making *two* parameters out of it!

So what Pedro's doing is to rotate an extra time, check the "previous" (or "next") parameter for "ADDR_". If so, rotate to the "real" parameter, lea and push it, and "rotate back" to skip the "ADDR_" (fake) parameter. If it *isn't* ADDR_, undo the "extra" rotate and proceed...

Pedro introduces an "assemble-time variable", "i", which mirrors the parameter count, "%0", initially. This gets decremented an "extra" time if ADDR_, and causes an "early exit" from the %rep loop. There may be a way to get around this, but it may be necessary - my best attempt so far does the lea/push correctly(?), but since we've handled two parameters per loop (if ADDR), this pushes one too many (push Hexprint, e.g.) before "call Hexprint". Re-introducing that (I called it "repcount") seems to fix it

One thing I noticed that's going to cause you trouble is the brackets "[]". You've got "[%1]" in the macro, and call it as "ADDR_ [@string]". This results in "lea [[@string]]" - "expression syntax error"! Programmer's choice which place you do it, but not both.

I think your "%elifnum" will work if you make it "$elifnum %1". Arguably, Nasm ought to complain about just "%elifnum" without a parameter... but it doesn't.

This is what I've got... so far...

%define ADDR "ADDR_",

%macro scall 1-*.nolist ;Windows StdCall: push last value first, no cleanup
%ifndef %1_defined      ;define external functions
   extern %1
%endif
%define _proc %1
%assign repcount %0

%rep %0 - 1
    %rotate -1

%rotate -1  ; "extra" rotate
   %ifidni %1,"ADDR_"
         %error "ADDR is used"
         %rotate 1
         lea    eax,   [%1]
         push   eax
         %rotate -1
         %assign repcount repcount - 1
   %else
   %rotate 1  ; undo the "extra"
   %endif

%ifstr %1
      ;;;;;%ifstr %-1
         %error "We have a string argument"
         mac_pushstring %1
   %elifid %1
         push dword %1
         %error "We have a label"
   %elifnum %1
         push dword %1
         %error "We have a number"
   %else
      ;%error "unspecified Argument"
      push dword %1
    %endif
    %assign repcount repcount - 1

%if repcount >= 1
   %exitrep
    %endif

%endrep
    call _proc
%endmacro   

This "seems to work" - not well-tested, 'cause I had to comment out a lot of stuff, lacking the full macro-set (and Windows), to get it to assemble at all. See if it helps... I think you're closing in on it!

Best,
Frank

nobody

  • Guest
Re: scall macro
« Reply #2 on: December 29, 2008, 12:12:31 AM »
Thanks Frank for your help.
I had to play around a bit with the code. I thought I didn't need the  repcount mechanism, since I shifted right then left. I did not consider, that the argument to the right of ADDR would pushed as a regular parameter in the previous loop. I decided to take it one step further and make an invoke macro out of it. Local and global procs can be invoked with the same macro
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; Invk Macro Based on sources like Nguga,PedroC,Bryant Keller nuMitor and others, adapted to GoLink
; Written by    : Klod
; Assembler     : Netwide Assembler v2.00
; Linker       :GoLink
; Date          : 26-Dec-2008
; To Do      :Fix size bug will push dword byte/word if size other than dword specified
      :[global] will not  be pushed at all, has to be dword[global] or dword[@local]
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
%define ADDR    "ADDR_",

%MACRO invk 1-*
%define _proc %1
%ifndef  PROC_defined_%1
   ;%error extern %1
   extern %1
%endif
%assign repcount %0-1

%rep %0-1
    %rotate -1
   %ifidni %1,"ADDR_"
         ;%error "ADDR is used"
         %rotate 1   ;extra  rotate
         %assign repcount repcount -1
         lea   eax,   %1
         push   eax
         %rotate -1   ;undo extra rotate
   %elifstr %1
         ;%error "We have a string argument"
         mac_pushstring %1
         ;%assign repcount repcount -1
   %elifid %1
         ;%error "We have a label"
         push dword %1
   %elifnum %1
         ;%error "We have a number"
         push dword %1
         %assign repcount repcount -1
   %else
      ;%error "an unspecified argument has been supplied"
    %endif
    %if repcount <= 1
    %exitrep
    %endif
%endrep
   call _proc
%ENDMACRO

You were right, the brackets are a problem. I have to use  push dword %1 because of it. If I use ADDR @param Nasm will not compile I will get error: invalid operand type.

You mentioned string parsing in your reply. I have not tried it yet, but think it would be well worth to explore. My macro could be greatly simplified if ADDR_[@parm]could be treated as one argument. My initial idea was to use something like:
%substr %%arg %1 5,-1    ;to %define %%arg '[@parm]'???
lea eax,%%arg
push dword eax
Any thoughts on that notion?

Working with the macros I have encountered problems with definitions and scope. As an example:
%define addr(x) (lea eax,( x)\ push eax)
invk MsgBox,addr(dword[@lpName]),'test'
invk MsgBox,addr([@lpName]),'test'

This would be my prefered method, but cannot make it work at this time.

As always, your help and suggestions are very much appreciated.
Klod

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: scall macro
« Reply #3 on: December 30, 2008, 12:04:26 AM »
Hi Klod,

Haven't taken time to test this, but the logic looks wrong to me...


%rep %0-1
%rotate -1
%ifidni %1,"ADDR_"
;%error "ADDR is used"
%rotate 1 ;extra rotate
%assign repcount repcount -1
lea eax, %1
push eax
%rotate -1 ;undo extra rotate
%elifstr %1

I think we need to do an "extra rotate -1" *before* checking for "ADDR". Then, if we've got "ADDR", "unrotate", that is, rotate 1, lea/push the "real" parameter, then undo the "extra" rotate -1 before doing "non-ADDR parameters". That's why I put it in a separate if/else/endif in the code I posted - couldn't figure out how to do it as a single if/elif/elif... without putting the "unrotate" in *each* clause.

If this is working properly, "never mind...". :)

I'll try to get back to this. Both your "%define addr(x)" and "%substr" ideas sound interesting...

Best,
Frank