How to tell gcc to keep my unused labels?
Asked Answered
R

2

12

Edit: Thanks to @NateEldredge, I better defined my question in How to 'tag' a location in a C source file for a later breakpoint definition?


I use those labels to setup breakpoints in gdb. So no matter if I add/remove lines of code after/before the label, the breakpoint is still correct.

If I add -Wno-error=unused-label to the compilation options, the compiler does not yell at me, but the label disappears from the assembly.

If instead, I use __attribute__((unused)) in the code, the result is the same: no complain, but the label is gone.

Is there a correct way of getting this done (instead of just a hack)?

Here is my toy example:

int main(void){
    int a = 15;
 label: __attribute__((unused))
    a = a + 23;
    return a;
}

After compilation, it results in:

main:
        push    ebp
        mov     ebp, esp
        sub     esp, 16
        mov     DWORD PTR [ebp-4], 15
        add     DWORD PTR [ebp-4], 23
        mov     eax, DWORD PTR [ebp-4]
        leave
        ret

Here an interactive version of the same example: https://godbolt.org/z/zTqd9bM6q


$ gcc --version
gcc (GCC) 10.3.1 20210422 (Red Hat 10.3.1-1)
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Resigned answered 23/11, 2021 at 19:43 Comment(20)
You could goto right before the label.Standpipe
How about __asm__("label:");Elfriedeelfstan
This could be a good question. But: your example code should be presented here , IMHO.Payson
__attribute__((unused)) is unrelated to what you are trying to do. It is merely suppressing the "unused" warning.Fucoid
Since this is only for debugging, you could put uses of the labels inside statements that are conditionally compiled (inside something like #if DEBUG … #endif), such as volatile int x; switch(x) { case 0: goto foo; case 1: goto bar; … }.Parnell
thanks guys, this is very educational. __asm__("label:"); works as expected. Beautiful. Thanks. @Jester, If you could please post an answer based on your comment, I would gladly mark it as a correct answer. | Edit: It seems that there are some issues with this approach, as @EricPostpischil mentionsResigned
Be aware that __asm__("label:") can fail. During optimization, the compiler might decide to duplicate code, resulting in the label appear twice in assembly code, which will usually cause compilation to fail. Or it might be removed when the compiler determines execution can never pass through it (although then putting a breakpoint there would be useless anyway, as it would never be hit).Parnell
@EricPostpischil, that is quite interesting. I see what you mean with the second point. How can the first point be mitigated?Resigned
@EricPostpischil, on the #ifdef DEBUG ... #endif approach. I cannot achieve the desired output godbolt.org. Also, should I define/undefine DEBUG from the C file, or that can be done in the Makefile?Resigned
@EricPostpischil, regarding the __asm__("label:") approach; I am compiling with -O0 or -Og. Do you know if the compiler would perform those pernicious optimizations if I am asking to gcc not to touch my code too much?Resigned
I think semantically you want attribute((used)) not ((unused)), however I don't think that can apply to labels.Sarette
@Elfriedeelfstan The asm statement breaks in interesting ways when the function is inlined.Inn
@TomV, Seems like so, when I try it, I get error: 'used' attribute ignored. I don't know if that implies that in general unused does not apply to labels. But it doesn't work here.Resigned
@Jester, wouldn't in general be wrong to put labels within inline functions? (unless the compiler catches that and turns it into a unique label for each instance). If we assume the function is NOT inline. Would this break? I am still not certain about the pernicious optimizations EricPostpischil mentioned.Resigned
@Resigned What version of gcc? I couldn't get it to compile with the given options under 4.8.5, and after I trimmed them down I was able to set a breakpoint on "label" with and without the attribute.Standpipe
@Standpipe Question edited with the details.Resigned
Yeah well it's unclear what you want when inlining. You can of course use a unique assembler generated name but then how would you know what to use while debugging. Also, you are aware you can use source line numbers in gdb, right? So you effectively already have a unique label for each line.Elfriedeelfstan
@Jester: In recent GCC, non-empty Basic Asm statements have an implicit "memory" clobber, so doing that would affect the optimizer. (Possibly moreso than getting the compiler to emit an asm label). This is undocumented and thus not recommended to rely on; it's a sop to bad code that should be using Extended asm for a "memory" clobber to control ordering for stuff like asm("mfence") or enable/disable of interrupts.Alecalecia
But sure, if you only want to find your place in not fully optimized code, that's fine.Alecalecia
@Jester. Yes. source.c:line works, but if I add one line on the top of the file, everything gets shifted.Resigned
G
7

If you want to have a label that doesn't get removed or renamed, try this:

    asm volatile("mylabel:");

Note that having this label might affect how GCC optimizes your function. However, the volatile keyword will probably help prevent it from doing anything that would cause problems.

Also note that you can use __asm__ instead of asm. Both appear to work in GCC.

Gardant answered 24/11, 2021 at 0:26 Comment(3)
__asm__ works even with -std=c++11. asm only works with the default -std=gnu11, i.e. allow GNU extensions in parts of the global namespace that aren't reserved for implementation-defined stuff.Alecalecia
As discussed in comments under the question, this will have problems when inlining or loop unrolling, because the label will be in multiple places in one .s file (which is an error). Also, don't use GNU C Basic Asm; recent GCC versions treat non-empty Basic asm template strings as having a "memory" clobber, so will hurt optimization more than necessary. Either use asm("mylabel:" ::: "memory"); explicitly if you want to force the compiler to have memory (except for non-escaped locals) in sync with the C abstract machine, or asm("mylabel:" :::); if not.Alecalecia
And optionally use "mylabel%=:" in those extended statements to have GCC invent unique numbers as part of the label name; it may still tab-complete in GDB. How Do I Use Labels In GCC Inline Assembly?Alecalecia
R
4

You can silence the unused label warning... by using it:

int main(int argc, char** argv) {
    int a = 15;
    goto label; label:
    a = a + 23;
    return a;
}

This keeps the label in the assembly (albeit using an internal name):

main:
.LFB0:
        push    ebp
        mov     ebp, esp
        sub     esp, 16
        mov     DWORD PTR [ebp-4], 15
        nop
.L2:
        add     DWORD PTR [ebp-4], 23
        mov     eax, DWORD PTR [ebp-4]
        leave
        ret

I would suggest using a macro to reduce effort and show intent better:

#define DEBUG_LABEL(x) goto x; x:
Radiophone answered 23/11, 2021 at 22:21 Comment(6)
That nop isn't for alignment; when GCC wants alignment, it uses .p2align because it doesn't keep track of instruction sizes. It leaves that up to the assembler. GCC -O0 does sometimes include a nop in tiny functions even without goto shenanigans, like in void bar(){}. godbolt.org/z/9jGrGveYd. Of course, this trick only works at all with -O0, with any optimization the label disappears (godbolt.org/z/hfeeGzcd5), so efficiency is mostly irrelevant.Alecalecia
Doesn't this defeat the whole point of the label for my use case: to be used in gdb to set breakpoints. If the name is not the same, then I cannot reference it in my .gdbinit file.Resigned
@onlycparra: Well then C labels were useless for your use case all along, because they do not translate to labels with the same name in assembly. (That couldn't work, if you think about it: different functions can contain labels with the same name, not to mention inlining.)Kreisler
@onlycparra: As such, I think this is kind of an XY problem. The real question, which I think is a good one, would just be "how can I 'tag' a location in a source file so as to be able to set a breakpoint there".Kreisler
@NateEldredge You are right. I defined my question through a preconceived answer I had in my head. What is the correct stack-overflow protocol to reformulate my question? I feel that without intending it, this question stands on its own.Resigned
@onlycparra: At this point I would probably post it as a brand new question, maybe with a link to this one.Kreisler

© 2022 - 2024 — McMap. All rights reserved.