0

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?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
mingcr
  • 3
  • 6
  • Your example compiled for me (as here https://godbolt.org/z/1zPKqKq38 ). Have you tried answers from this question: https://stackoverflow.com/questions/10486116/what-does-this-gcc-error-relocation-truncated-to-fit-mean ? – Renat Jul 13 '21 at 14:59
  • 1
    On what OS, and what compile/link options? – Nate Eldredge Jul 13 '21 at 15:38
  • 1
    Note that calling a function from inline asm needs more work to be done safely. The function may clobber registers, which you have not declared. On systems using the SysV ABI, it is much harder because of the red zone. – Nate Eldredge Jul 13 '21 at 15:39
  • @Renat: you made `functionPointer` a local inside main, so you get `call *-8(%rsp)`. (So the `"m"` constraint is really silly, forcing the compiler to do a store instead of using the register value.) – Peter Cordes Jul 13 '21 at 19:38

1 Answers1

1

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.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847