Reputation: 3
minimalist example:
void someFunction(){
std::cout << "Hello World" << std::endl;
}
void (*functionPointer)();
functionPointer = someFunction;
int main(){
__asm__("call *%P0"::"m"(functionPointer):);
return 0;
}
In gcc 10.3.0, this results in the following error:
relocation truncated to fit: R_X86_64_32S against `.bss'
collect2.exe: error: ld returned 1 exit status
Any ideas?
Upvotes: 0
Views: 1014
Reputation: 365707
This is unsafe - First of all, a function call has to be assumed to clobber all the call-clobbered registers, and the red-zone below RSP, so it's a huge pain to do it safely from GNU C inline asm. Calling printf in extended inline ASM shows a safe example that declares clobbers on all the relevant integer, mmx, x87, and xmm registers, and avoids the red-zone.
*%P0
makes GCC print *functionPointer
instead of *functionPointer(%rip)
, which can't link into a PIE executable because it's a 32-bit-sign-extended absolute addressing mode. 32-bit absolute addresses no longer allowed in x86-64 Linux?
Remember, you're doing a memory-indirect jump so you want a normal data addressing mode, not the bare symbol name. So you want just *%0
, exactly like if it might be a register so you could let GCC emit call *%rax
if it wanted to, for an "rm"
constraint.
https://godbolt.org/z/hWeexz8cf
%P
only makes sense when you want a direct call, like asm("call %P0" : : "i"(callee));
, e.g. call callee
not call *callee
.
Upvotes: 1