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;
}