Consider this program on godbolt:
#include <cassert>
#include <cstdint>
int64_t const x[] = { 42, 2, 3, 4 };
int64_t f() {
int64_t i;
asm volatile (
"xor %[i], %[i]\n\t"
"movq _ZL1x(,%[i],8), %[i]"
: [i]"=r"(i));
return i;
}
int64_t g() {
int64_t i;
asm volatile (
"xor %[i], %[i]"
: [i]"=r"(i));
i = x[i];
return i;
}
int main() {
assert(f() == 42);
}
It compiles, links and runs fine for gcc 13.1 but clang 16.0 gives a linker error:
[...]: relocation R_X86_64_32S against `.rodata.cst32' can not be used when making a PIE object; recompile with -fPIE
If I try the same code locally and compile it with g++ -O3 main.cpp
(same gcc version) I get the same error above. (Recompiling with -fPIE
doesn't fix.)
It's worth noticing that the code generated by gcc for f()
and g()
are identical:
_Z1fv:
xor %rax, %rax
movq _ZL1x(,%rax,8), %rax
ret
_Z1gv:
xor %rax, %rax
movq _ZL1x(,%rax,8), %rax
ret
and if I remove f
from the source file and use g
in main
, then all compilers are happy, locally and on godbolt.
I understand that directly writing _ZL1x
in my inline assembly is weird and very likely to be a bad practice but that's not the point here. I would like to know why gcc is happy on godbolt and not locally and, more importantly, how could I make it to work locally and (if possible) for clang as well.