inline assembly function pointer calling

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

Answers (1)

Peter Cordes
Peter Cordes

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

Related Questions