NASM - The Netwide Assembler

NASM Forum => Using NASM => Topic started by: Klod on October 19, 2010, 04:28:33 AM

Title: Loss of variable scope
Post by: Klod on October 19, 2010, 04:28:33 AM
This may be pushing the envelope to far and is purely experimental. Even though I have not seen any examples in this forum or on the net, I tried to create a macro from within a macro. I believe the following example should work.

Code: [Select]
%warning __NASM_VER__  2.10rc1-20101008
%macro definem 2+
    ;%warning %? %1 %2 %0 'parameters'
    mac %1,%2
%endmacro

%macro mac 2-*   
        %push mac
        %warning 'Parameters' %{1} %2
        %push mac
        %define %$name %{1}
        %warning 'Parameters' %{1} %2 %$name
    %macro %{1} 1-*
        %warning %? %1 %2 %0 %[%{$name}] %$name %{$name}
        push %2
        EXTERN %{1}
        ;call %1
    %endmacro
    %pop
%endm
[Section .Text]


Start:   
    definem ExitProcess,0
    definem strcpy,ptr
;      push 0
;      EXTERN ExitProcess
    strcpy,Start
      ExitProcess ,0
 
;Windows XP service pack 2
;\nasm\bin\NASM -f win32
;\nasm\bin\golink  @\nasm\bin\GFL.txt  /console /entry Start


NAsm reports:
Quote
\nasm\bin\NASM -f win32 "C:\NasmEd\Project\WorkInProgress\Stringparsing\invkDefine.asm"
C:\NasmEd\Project\WorkInProgress\Stringparsing\invkDefine.asm:1: warning: "2.10rc1-20101008" 2.10rc1-20101008
C:\NasmEd\Project\WorkInProgress\Stringparsing\invkDefine.asm:25: warning: (mac:2) 'Parameters' ExitProcess 0
C:\NasmEd\Project\WorkInProgress\Stringparsing\invkDefine.asm:25: warning: (mac:5) 'Parameters' ExitProcess 0 ExitProcess
C:\NasmEd\Project\WorkInProgress\Stringparsing\invkDefine.asm:26: warning: (mac:2) 'Parameters' strcpy ptr
C:\NasmEd\Project\WorkInProgress\Stringparsing\invkDefine.asm:26: warning: (mac:5) 'Parameters' strcpy ptr strcpy
C:\NasmEd\Project\WorkInProgress\Stringparsing\invkDefine.asm:29: warning: (strcpy:1) mac Start 2 %$name %$name %$name
C:\NasmEd\Project\WorkInProgress\Stringparsing\invkDefine.asm:30: warning: (ExitProcess:1) mac 0 2 %$name %$name %$name

This all works as I expected, both macros strcpy and Exitprocess are created. However, when I call the macros, the macro name "disappears". %? should show macroname as Exitprocess and strcpy  and not as mac (macro name of previous macro). %2 still gives the correct parameter but %1 "disappears". I thought first that %1 might have been shifted into macro name but not so. Also by creating a context and then attempting to use the local %$name suffers the same fate.

As I said earlier, purely experimental. Maybe I'm reading more in the docs than there is ???

Regards Klod
 
Title: Re: Loss of variable scope
Post by: Klod on November 04, 2010, 02:20:28 AM
This must be an unsupported use? ???
Title: Re: Loss of variable scope
Post by: Bryant Keller on November 04, 2010, 06:30:31 AM
Code: [Select]
%warning __NASM_VER__  2.10rc1-20101008
%macro definem 2+
    ;%warning %? %1 %2 %0 'parameters'
    mac %1,%2
%endmacro

%macro mac 2-*   
        %push mac
        %warning 'Parameters' %{1} %2
        %push mac
        %define %$name %{1}
        %warning 'Parameters' %{1} %2 %$name
    %macro %{1} 1-*
        %warning %? %1 %2 %0 %[%{$name}] %$name %{$name}
        push %2
        EXTERN %{1}
        ;call %1
    %endmacro
    %pop
%endm
[Section .Text]


Start:   
    definem ExitProcess,0
    definem strcpy,ptr
;      push 0
;      EXTERN ExitProcess
    strcpy,Start
      ExitProcess ,0
 
;Windows XP service pack 2
;\nasm\bin\NASM -f win32
;\nasm\bin\golink  @\nasm\bin\GFL.txt  /console /entry Start


NAsm reports:
Quote
\nasm\bin\NASM -f win32 "C:\NasmEd\Project\WorkInProgress\Stringparsing\invkDefine.asm"
C:\NasmEd\Project\WorkInProgress\Stringparsing\invkDefine.asm:1: warning: "2.10rc1-20101008" 2.10rc1-20101008
C:\NasmEd\Project\WorkInProgress\Stringparsing\invkDefine.asm:25: warning: (mac:2) 'Parameters' ExitProcess 0
C:\NasmEd\Project\WorkInProgress\Stringparsing\invkDefine.asm:25: warning: (mac:5) 'Parameters' ExitProcess 0 ExitProcess
C:\NasmEd\Project\WorkInProgress\Stringparsing\invkDefine.asm:26: warning: (mac:2) 'Parameters' strcpy ptr
C:\NasmEd\Project\WorkInProgress\Stringparsing\invkDefine.asm:26: warning: (mac:5) 'Parameters' strcpy ptr strcpy
C:\NasmEd\Project\WorkInProgress\Stringparsing\invkDefine.asm:29: warning: (strcpy:1) mac Start 2 %$name %$name %$name
C:\NasmEd\Project\WorkInProgress\Stringparsing\invkDefine.asm:30: warning: (ExitProcess:1) mac 0 2 %$name %$name %$name

Before I start on the problem at hand, you might need to double check your definem macro, as you seem to have unbalanced the number of %push/%pop directives (you have two %push mac and only one %pop). I'm not sure if that was intentional but if you end up using your code a lot, it might really slow your code down.

This all works as I expected, both macros strcpy and Exitprocess are created. However, when I call the macros, the macro name "disappears". %? should show macroname as Exitprocess and strcpy  and not as mac (macro name of previous macro).

I'm pretty sure this behaviour is supposed to be expected. %? is getting expanded when your new macro is being created so I don't really know of any way around this. I'm honestly surprised your code worked. :)

%2 still gives the correct parameter but %1 "disappears". I thought first that %1 might have been shifted into macro name but not so. Also by creating a context and then attempting to use the local %$name suffers the same fate.

Arguments are fine, it's a usage problem. When you use your ExitProcess macro, you are passing a NULL parameter. See below:

Code: [Select]
Start:   
    definem ExitProcess,0
    definem strcpy,ptr
;      push 0
;      EXTERN ExitProcess
;      strcpy,Start << This is strcpy( "", Start )
      strcpy Start ;<< This is strcpy( Start )
;      ExitProcess ,0 << This is ExitProcess( "", 0 )
      ExitProcess 0 ;<< This is ExitProcess( 0 )

As you can see, the coma preceding your arguments creates a blank argument in %1. And as for loosing %$name, it's expected as well, when you create a new context, %$name becomes %$$name and a fresh context is provided for you (this allows you to redefine %$name locally to your macro while retaining the old one).
Title: Re: Loss of variable scope
Post by: Klod on November 07, 2010, 03:36:03 AM
Hi Bryant,
Quote
......check your definem macro, as you seem to have unbalanced the number of %push/%pop directives (you have two %push mac and only one %pop). I'm not sure if that was intentional but if you end up using your code a lot, it might really slow your code down.

You are correct. This was accidental, as I have been trying different things. In the heat of the moment I got sloppy.

Quote
I'm pretty sure this behaviour is supposed to be expected. %? is getting expanded when your new macro is being created so I don't really know of any way around this. I'm honestly surprised your code worked.

I have attached a working program with source. The "context local " approach does not work and of course none of the "macro locals" work. I have found a workaround but its not satisfactory....

Code: [Select]
      strcpy Start ;<< This is strcpy( Start )
;      ExitProcess ,0 << This is ExitProcess( "", 0 )

You are right here again but I think the problem lies here...
Code: [Select]
%macro %[%1] 0-*
       %warning %?? %0 ,%1,%2 %3 %0-1  ,%[%1]

The macro with name %[%1] gets created. Here however the preprocessor gets confused. Instead of using %[%1] as the new macro name, it reuses the previous macro name (mac), drops %[%1] and shifts the supplied parameters to the right and thus creates an empty parameter. I assume macro name mac is used as current macro name until it sees a matching %endm.

Quote
As you can see, the coma preceding your arguments creates a blank argument in %1.

Code: [Select]
printf missing1starg,NewlineThis compiles and runs fine

Code: [Select]
printf string3 <---  correct invocation This produces ERROR: Line 34: error: invalid combination of opcode and operands

The workaround works by defining %[%1] before the macro is created and then ignoring %1 and using %2 as first argument. There is a serious drawback in my implementation because %define name %1 creates persistence.

   definem printf,ptr
definem scanf,ptr
   printf, string




Title: Re: Loss of variable scope
Post by: Klod on November 07, 2010, 03:51:51 AM
I was fooling around with formatting and somehow my incomplete response got posted ;D

...continued from previous post.

this gives Error:
31: error: invalid combination of opcode and operands
Error symbol `call' redefined for multiple invocations of the same macro

This is not what I was shooting for.

I do not know how Nasm implements macros but think if its similar in approach to context mechanism, it could be relatively easy to implement a "previous macro name" "context" mechanism which would also allow macros to be recursive??

Thanks for your input,
Klod
Title: Re: Loss of variable scope
Post by: Klod on November 07, 2010, 03:53:52 AM
Forgot to attach my proggie ;)

Klod
Title: Re: Loss of variable scope
Post by: Bryant Keller on November 07, 2010, 05:02:02 AM
You did it again in the posted version. Check out this source:

Code: [Select]
;Windows XP service pack 2
;\nasm\bin\NASM -f win32
;\nasm\bin\golink  @\nasm\bin\GFL.txt  /console /entry Start

%warning __NASM_VER__  2.10rc1-20101028
%macro definem 2+
     mac %1,%2
%endmacro

%macro mac 2-*
     %define name %1
     %warning %?? %0 'Parameters' %{1} %2 %3 name

     %macro %[%1] 0-*
          %warning %?? %0 ,%1,%2 %3 %0-1  ,%[%{1}]
          push %1

          EXTERN name
          call name
     %endmacro

%endmacro


[Section .data]
     string db 'hello',13,10,0
     string2 db 'Hello again',0
     string3 db 'and again Hello',0
     Newline db 13,10,0
     key db '%x'

[Section .text]
Start:
     definem printf,ptr
     printf string
     printf string2
     printf Newline
     printf string3
     printf Newline ;correct calling


     definem scanf,ptr
     scanf key

     definem ExitProcess, 0
     ExitProcess 0

I assembled it and got:

Code: [Select]
nestedMacrocall.asm:4: warning: "2.09.03" 2.10rc1-20101028
nestedMacrocall.asm:29: warning: (mac:2) mac 2 'Parameters' printf ptr printf
nestedMacrocall.asm:31: warning: (printf:1) mac 1 ,string, 1-1 ,string
nestedMacrocall.asm:32: warning: (printf:1) mac 1 ,string2, 1-1 ,string2
nestedMacrocall.asm:33: warning: (printf:1) mac 1 ,Newline, 1-1 ,Newline
nestedMacrocall.asm:34: warning: (printf:1) mac 1 ,string3, 1-1 ,string3
nestedMacrocall.asm:35: warning: (printf:1) mac 1 ,Newline, 1-1 ,Newline
nestedMacrocall.asm:37: warning: (mac:2) mac 2 'Parameters' scanf ptr scanf
nestedMacrocall.asm:38: warning: (scanf:1) mac 1 ,key, 1-1 ,key
nestedMacrocall.asm:39: warning: (mac:2) mac 2 'Parameters' ExitProcess 0 ExitProcess
nestedMacrocall.asm:41: warning: (ExitProcess:1) mac 1 ,0, 1-1 ,0

Since I'm on Linux, I can't actually link and test the code, but I'm assuming this is the output you were wanting. Re-read my post, what you are doing wrong is passing the empty param which is generating a call instruction without an argument (which is the reason for the "invalid combination of opcode and operand" error you're getting). Review this code, I'm sure you'll see what I'm saying. :)
Title: Re: Loss of variable scope
Post by: Klod on November 07, 2010, 11:58:39 PM
Hi Bryant, I have come to see the light :)

I originally used %macro %{1} %0 to work  out the  possibility of making it work. This is incorrect in as far as the macroname is counted as a parameter. %0 would be 2 instead of one.  %{0}-1 does not work, neither does %$count for parameter count. I was unaware of an extra parameter being added. once I could compile , the proggie would crash. I then found that I needed to push %2 to make it work. and this explains the printf,string syntax. And I thought Confucius was Chineese ;D ;D

Here is the correct working version:
Quote
%macro mac 2      
      %define name %1
      %warning %?? %0 'Parameters' %{1} %2
   %macro %{1} 1
       %warning %?? %0 'args' %1
        push %1
       EXTERN name
       call name   
   %endmacro
%endm

[Section .data]
string db 'first string',0
key      db '%c'

[Section .text]

Start:
   mac printf, ptr
   printf string
   
   mac scanf,ptr
   scanf key
   
   mac ExitProcess,0
   ExitProcess 0

In order to test for %ifmacro MyMacro 3
%macro MyMacro 3 would have to be defined. Nasm will neither accept %{0}-1 nor %$count count

Do you have any ideas if this could be done??

Regards Klod