bug-binutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Bug gas/32391] \@ incorrectly handled in nested macros


From: regis.duchesne at broadcom dot com
Subject: [Bug gas/32391] \@ incorrectly handled in nested macros
Date: Thu, 28 Nov 2024 13:33:13 +0000

https://sourceware.org/bugzilla/show_bug.cgi?id=32391

--- Comment #2 from Regis Duchesne <regis.duchesne at broadcom dot com> ---
Hi Nick, thanks for looking at this bug.

> I think that this is more of a lack-of-documentation issue than a bug.  
> Specifically - I would expect \@ to evaluate to the same number anywhere 
> inside a macro, including any nested macros.

I respectfully disagree, I'll attempt below to argument in favor of my point of
view.

1) I agree that normally, an inner macro can use an argument of an outer macro
and see the same value.

For example this code

   .macro outer arg
      outer_\arg:
         nop
      .macro inner
         inner_\arg:
            nop
      .endm
      inner
   .endm
   outer foo

produces this output

   outer_foo:
      nop
   inner_foo:
      nop

i.e. the arg argument is visible/available to the inner macro, although it is
not explicitly an argument of the inner macro.

2) But I claim that \@ is special, and should be treated differently.

\@ is special because it is not an explicit argument. It is _implicitly_
created by each macro, when the macro starts executing, and given its value at
that moment in time.

\@ is also special because its _sole purpose_ (i.e. the reason it exists) is to
create unique names. If in my entire code base, I decide that by convention all
the labels defined in my macros will start with "_m\@_", then I should be
guaranteed that these labels never collide. But currently that is not what is
happening (and that is why I claim the current behavior is problematic):

For example this code

   .macro outer
      _m\@_:
         nop
   .endm
   .macro inner
      _m\@_:
         nop
   .endm
   outer
   inner

correctly produces this output:

   _m0_:
      nop
   _m1_:
      nop

but this code (the only change is that the inner macro goes inside the outer
one):

   .macro outer
      _m\@_:
         nop
      .macro inner
         _m\@_:
            nop
      .endm
      inner
   .endm
   outer

produces the error

   Error: symbol `_m0_' is already defined

and that is completely unexpected: I just re-organized my code, but now it does
not assemble anymore! It goes against the principle of least surprise. Now I'm
in a bind: how should I name the label in my inner macro to guarantee no
collision? I could certainly adopt another label naming convention for all my
nested macros, but what if I don't know upfront whether a macro will be nested
or not? (In the case that prompted me to file this bug, the inner macro is
generated inside the outer macro with cpp.) What is the macro nesting is deeper
(a macro inside a macro inside a macro)? Should my label naming convention
depend on the level of nesting to avoid collisions? That is a bit insane, and
it does not scale.

So instead I claim that the output that should be produced should be the same
as if the macros were not nested, i.e.

   _m0_:
      nop
   _m1_:
      nop

3) Could the behavior I want prevent implementing Nick's example?

Not really. To implement Nick's example with the behavior I want, one can
always use an explicit parameter for the inner macro

   .macro outer
      before_inner_\@:
      .macro inner label
         .word \label
      .end
      inner before_inner_\@
      inner before_inner_\@
   .endm
   outer

which will output the expected code.

4) Sad behavior of explicit nested arguments

To further make a point about what I wrote above "\@ is special because it is
not an explicit argument. It is _implicitly_ created by each macro, when the
macro starts executing", I wanted to show what would happen with an explicitly
named argument (with the same name) for both the outer and the inner macro. So
I tried this:

.macro outer arg
      outer_\arg:
         nop
      .macro inner arg
         inner_\arg:
            nop
      .endm
      inner bar
   .endm
   outer foo

and I was extremely sad to discover that the output was

   outer_foo:
      nop
   inner_foo:
      nop

i.e. the value of the outer argument is given precedence over the value of the
inner argument! That seems completely _insane_ to me, and contrary to how all
languages handle local variables.

So while I realize that at least gas is consistent with how it deals with
arguments (whether they are explicitly named "arg" or implicitly named "@"), I
find the current gas behavior absolutely terrible, in that it does not scale:
it is _impossible_ to write a small piece of code in a macro, and have a
guarantee that it will always work. Depending on where that macro is actually
instantiated (such as inside another macro), that macro may not work.

So the problem I'm reporting is actually more generic than just \@. I should
have titled this bug "arguments with same name incorrectly handled in nested
macros".

If you tell me this is desirable behavior, well to me it is a big gotcha. To
the very least, that should be documented. But really, it should be fixed :)

Cheers, --RĂ©gis

-- 
You are receiving this mail because:
You are on the CC list for the bug.


reply via email to

[Prev in Thread] Current Thread [Next in Thread]