Author Topic: preprocessor local labels  (Read 22196 times)

Offline Rob Neff

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 429
  • Country: us
preprocessor local labels
« on: September 29, 2010, 10:09:15 PM »
While hacking around I realized it was possible to do the following:

Code: [Select]
myfunc1:
%define .myvar1 [ebp+8]
   .
   .
   mov eax, .myvar1
   ret

myfunc2:
%define .myvar1 [ebp+16]
   .
   .
   mov eax, .myvar1
   ret


In the documentation it states that a local label can be used by code which may perform branching to the label and what not.  However, as the previous code shows you can indeed override the local label and define your own local label.
Since this is not documented the question is - Can local labels always be used/overridden in this fashion "safely"? I would like to tie procedure specific defines together using this feature as it makes it wonderfully obvious that the define is associated with the procedure and allows another procedure defined later within the same source file to "reuse" the same name.
Thank you for you help.

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: preprocessor local labels
« Reply #1 on: September 30, 2010, 12:26:02 PM »
Hi Rob,

This is over my head, but fools rush in...

My first take on this was that nothing is being "overridden" - the first "local label" is actually "function1.myvar1", and the second one "function2.myvar1", Nasm allows us to refer to each by its "nickname" within its scope...

However, after fooling with it a bit, I have come to believe that the "local label" mechanism isn't involved at all here. Since ".myvar1" isn't actually a label, it isn't "local". Try it with "myvar1" without the '.' - still works! It's just a plain "%define". It surprises me a bit that we can redefine something without "%undef"ing it first (this is what I've been doing). However, this is documented (section 4.1.1):

Quote
This doesn't prevent single-line macros being redefined: you can perfectly well define a macro with

%define foo bar

and then re-define it later in the same source file with

%define foo baz

So I guess you can do it safely.

FWIW, I prefer to do the "%define"s without the "[]"s, and write:

Code: [Select]
mov eax, [.myvar1]
lea eax, [.myvar1]

rather than:

Code: [Select]
mov eax, .myvar1
lea eax, .myvar1

just to preserve the usual "[contents]" syntax - without it, it "looks like" an immediate, to me. I like using the '.', since it looks like the usual "local"... even though it apparently isn't (Gaz's old macros did it this way).

So I think you're "safe" to do it, even though it isn't really a "local label". Better, actually, since a "non-local" label won't "break the scope"...

Code: [Select]
function1:
%define .myvar1 ebp + 8
cmp al, '9'
jbe skip
add al, 7
skip:
mov eax, [.myvar1]

wouldn't work if it were a real "local label".

Hope someone who actually understands how this works will comment, but I think you're okay.

Best,
Frank


Offline cm

  • Jr. Member
  • *
  • Posts: 65
Re: preprocessor local labels
« Reply #2 on: September 30, 2010, 12:48:13 PM »
It surprises me a bit that we can redefine something without "%undef"ing it first (this is what I've been doing). However, this is documented (section 4.1.1):

How would this be a surprise? I always use this and figured that it should work this way. (Do C preprocessors differ there?)

However, after fooling with it a bit, I have come to believe that the "local label" mechanism isn't involved at all here. Since ".myvar1" isn't actually a label, it isn't "local".

I too think that this isn't invoking the local label mechanism really - because that's in the assembler, not in the preprocessor. As the assembler only gets the preprocessed lines, it never sees any local labels in your examples. For the same reason, the preprocessor can have macros declared with names of "reserved" assembler words - the assembler never sees the original text, only the macro's expansion.
C. Masloch

Offline Rob Neff

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 429
  • Country: us
Re: preprocessor local labels
« Reply #3 on: September 30, 2010, 02:24:34 PM »
Hi Frank,

My first take on this was that nothing is being "overridden" - the first "local label" is actually "function1.myvar1", and the second one "function2.myvar1", Nasm allows us to refer to each by its "nickname" within its scope...

And this was precisely where I was heading with NASMX ( ie %define myfunc.x [ebp+8] ) when it occurred to me to try using (abusing?) the local label mechanism:

Code: [Select]

;;// Note this is not exact syntax yet but close enough
;;// to show the concept.  There are a ton of issues in
;;// attempting to remain portable between 32 & 64-bit
;//  Linux/Windows being compensated for with macros.

import cdecl, xtrnfunc, qword a, qword b, qword x, qword y
proto fastcall, myfunc, qword x, qword y

proc fastcall, myfunc, qword x, qword y
locals
   local qword a
   local qword b
endlocals

   mov  .a, rdi
   mov  .b, rsi
   mov  rcx, .x
   mov  rdx, .y
   invoke xtrnfunc, .a, .b, .x, .y
   ret
endproc


FWIW, I prefer to do the "%define"s without the "[]"s, and write:

Code: [Select]
mov eax, [.myvar1]
lea eax, [.myvar1]

rather than:

Code: [Select]
mov eax, .myvar1
lea eax, .myvar1

just to preserve the usual "[contents]" syntax - without it, it "looks like" an immediate, to me. I like using the '.', since it looks like the usual "local"... even though it apparently isn't (Gaz's old macros did it this way).

I'm sitting on the fence, not sure which side to fall on, with this so far.  With using the local label concept it's like using shorthand ( although I see your point ).  The syntax would definately need to be nailed down before the next release.

Thanks for your input ;)

Offline Bryant Keller

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 360
  • Country: us
    • About Bryant Keller
Re: preprocessor local labels
« Reply #4 on: September 30, 2010, 05:36:06 PM »
I like the idea of the local label look but as Frank says, and as I'll explain shortly, keep the brackets. Also,  not completely related, why is there a need to include the calling convention in both the prototype and the procedure definition. When you prototype, set a nasmx variable specifically for that procedure which defines it's calling convention (%define __NX_DECL_%{$procname} %{1}) then check the value in PROC, if it doesn't exist, have a default setup for the specified BIT mode. :)

Definitely avoid including the brackets in the definition. I've already played around with that idea (giving it a more "MASM-ish" syntax) and horrible bugs come up when users want to manipulate arrays. For example:

Code: [Select]
proc myfunc
locals
   local byte, a, 256
   ; these are not actually supported by nasmx but you
   ; get the idea, allocate a block with RESx and equate as normal
endlocals

   xor eax, eax
   inc eax
   mov [.a + 10 * sizeof(byte)], al
   ret
endproc

Now, looking at that code, what it does is un-important I just threw some random instructions together, but the mov instructions are where the problem occurs. Lets preprocess these lines mentally real quick to see how they would look. If you don't include the brackets you get something like [ebp-256 + 10], k not bad and it works fine. the user only has to do  [.a] when the work normally. but lets see what occurs when you include the brackets in the definition, [[ebp-256] + 10] << syntax error, nasm can't handle (and shouldn't handle) something like that.

About Bryant Keller
bkeller@about.me

Offline Rob Neff

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 429
  • Country: us
Re: preprocessor local labels
« Reply #5 on: October 01, 2010, 12:25:48 PM »
Also,  not completely related, why is there a need to include the calling convention in both the prototype and the procedure definition.

That was actually just me copy/pasting and is not a requirement of macro proc nor currently of macro proto as there is a default convention set based upon output_format and bit-ness.  The programmer is free to use any of the predefined calling conventions should s/he wish to overide default behaviour ( which can again be changed using the new nasmx_declspec macro - more on that in a future post).

Definitely avoid including the brackets in the definition. I've already played around with that idea (giving it a more "MASM-ish" syntax) and horrible bugs come up when users want to manipulate arrays. For example:

Your array example pushed me off the fence landing on your's and Frank's side.
Thank you for your input.

Offline Bryant Keller

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 360
  • Country: us
    • About Bryant Keller
Re: preprocessor local labels
« Reply #6 on: October 01, 2010, 05:26:00 PM »
That was actually just me copy/pasting and is not a requirement of macro proc nor currently of macro proto as there is a default convention set based upon output_format and bit-ness.  The programmer is free to use any of the predefined calling conventions should s/he wish to overide default behaviour ( which can again be changed using the new nasmx_declspec macro - more on that in a future post).

Yeah, I have a tendency of doing that as well. I've (sorta) gotten over one of my bad habits of posting unusable code as "idea code" cause, as Homer pointed out to me, some people just don't seem to think on the same wave-length and the "idea code", if not fully functional, can cause more confusion than it can help.

Your array example pushed me off the fence landing on your's and Frank's side.
Thank you for your input.

No worries, I'm kinda glad you continue to stay so active on the forum with updates as to what's going on in the project. As I said, at the current point in my life I'm not really capable of working on anything major, but I love being able to help as much as possible. This allows me to at least pass on what I learned from my earlier tests instead of dropping the project cold turkey. :)

Regards,
Bryant Keller

About Bryant Keller
bkeller@about.me