Hi,

Recently I wanted to take and print the address of a label.  When
compiling with -O2, I noticed that the address equals the function body
start address if the label is not used as a goto target.

Here is an example:

#include <stdio.h>
int main(void) {
    printf("main:   %p\n", main);
    printf("label1: %p\n", &&label1);
    label1:
    puts("---");
    return 0;
}

compile with:
$ gcc -O2 -o example1 example1.c

or more specifically:
$ gcc -O1 -fschedule-insns2 -o example1 example1.c

Output:
  main:   0x562ed396216e
  label1: 0x562ed396216e
  ---


(or compile with -S to see that the label is moved to the start of the
function)

That is not completely surprising because labels as values are not
really valid outside of the originating function [1].

However when I assign the two addresses to automatic variables (which
should be okay) and compare them, they are different (despite having
the same value; the substraction result is 0).  Passing them to an
external function yields equality again (if the function is not
inlined).

#include <stdio.h>
void compare(size_t x, size_t y) {
    printf("x == y : %d\n", x == y);
}
int main(void) {
    size_t m = (size_t)main;
    size_t l = (size_t)&&label1;
    printf("m: %p\n", m);
    printf("l: %p\n", l);
    printf("m == l : %d\n", m == l);
    printf("m - l  :% d\n", m - l);
    compare(m, l);
    label1:
    puts("---");
    return 0;
}

Output:
  m: 0x559a775cd16e
  l: 0x559a775cd16e
  m - l  : 0
  m == l : 0
  x == y : 1
  ---


The reasons for this behavior probably lies in constant
folding/propagation.

I'm not sure whether this is technically a bug (Labels as Values /
Computed Gotos are not Standard C anyway).  But this is at least
confusing.  Maybe the label should not be moved in the first place?

Regards,
Flo


[1] https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html
// Compile with:
// $ gcc -O2 -o example2 example2.c
// or
// $ gcc -O1 -fschedule-insns2 -o example2 example2.c

#include <stdio.h>

void compare(size_t x, size_t y) {
    printf("x == y : %d\n", x == y);
}

int main(void) {
    size_t m = (size_t)main;
    size_t l = (size_t)&&label1;
    printf("m: %p\n", m);
    printf("l: %p\n", l);
    printf("m == l : %d\n", m == l);
    printf("m - l  :% d\n", m - l);
    compare(m, l);
    label1:
    puts("---");
    return 0;
}
// Compile with:
// $ gcc -O2 -o example1 example1.c
// or
// $ gcc -O1 -fschedule-insns2 -o example1 example1.c

#include <stdio.h>

int main(void) {
    printf("main:   %p\n", main);
    printf("label1: %p\n", &&label1);
    label1:
    puts("---");
    return 0;
}

Reply via email to