What's the best way to define local labels in an assembler macro?

R. Diez rdiezmail-binutils@yahoo.de
Mon Apr 30 22:04:00 GMT 2012

Hallo Erik:

> You appear to have neither tried the given examples, nor read "info 
> as". Please do both, as advised. Then try the posted alternative to your
> example, to easily answer that question.
> [...]
> Learning by doing surpasses all other methods.

I don't think you've realised the scale of the problem. Let me put it in perspective for you. There are thousands of gas users who try to use the assembler as little as possible and need not become masters at it. There are millions of lines of code written by developers who don't care if you later encounter a label collision. Many people take a quick look at the documentation and not surprisingly decide life is too short to play with the different local label options. Most people hope for the best. Some reserve a number range (less people even document it). Few append $ to the label names. Nobody uses \@ or .altmacro. Too many write horrible multi-line macros for the C pre-processor.

I already said I read the manual, I hope it's not different to the info pages (which have a less than ideal user interface). The documentation is not clear about the behaviour of the different options I mentioned. There's no clear advice and few examples. I've googled around and I'm not the only one who found a little time to devote to this question. Users shouldn't have to test several things around in order to learn the best way to declare local labels. I don't wish to try it myself and miss something or make mistakes, I would like an authoritative answer I can rely on.

Here's an example of how to do it right, from the Yasm documentation:

4.3.2. Macro-Local Labels

NASM allows you to define labels within a multi-line macro definition in such a way as to make them local to
the macro call: so calling the same macro multiple times will use a different label each
time. You do this by prefixing %% to the label name. So you can invent an instruction which executes a RET if the Z flag is set by doing this:

%macro  retz 0
      jnz  %%skip

You can call this macro as many times as you want, and every time you call it NASM will make up a different “real” name to substitute for the label %%skip. The names NASM invents are of the form ..@2345.skip, where the number 2345 changes with every macro call. The ..@ prefix prevents macro-local labels from interfering with the local label mechanism, as described in Section 3.9. You should avoid defining your own labels in this form (the ..@ prefix, then a number, then another period) in case they interfere with macro-local labels.

By the way, I did take the time to do some more tests, and your first recommendation already proved wrong. I tried it like this for the OpenRISC arquitecture, and look what happens:

.macro MACRO_B

  1:    l.nop 2
        l.j 1b


.macro MACRO_A

  1:  l.nop 1
      l.j 1b


This is the generated code:

 100:    15 00 00 01     l.nop 0x1
 104:    15 00 00 02     l.nop 0x2
 108:    03 ff ff ff     l.j 104 <_start+0x4>
 10c:    03 ff ff fe     l.j 104 <_start+0x4>

Notice how both jumps target the same instruction, as the "1:" label inside MACRO_B masks the one in MACRO_A, so it's not safe to declare local labels like that in macro definitions.

I tried combinining 2 of the tricks for the label names like this:
and that seems to work well across nested macro invocations, although I've done very limited testing yet.


More information about the Binutils mailing list