chamibuddhika
chamibuddhika

Reputation: 1439

PC relative CALL with GCC inline assembly

I wrote the following sample code. But it generates "near, absolute indirect, address given in r/m32" (as given at [1]) variant of the call instruction which fails with a segmentation fault since the address is interpreted as an absolute one. Is there any way for generating PC relative call with GCC inline assembly? By the way the code correctly calculates the relative distance so there is no issue with that.

#include <stdio.h>

void print_fn() {
  printf("Hello there..\n");
}

int main() {

  long relative = (long) ((unsigned char*)&&label - (unsigned char*)print_fn);
  __asm__ volatile ("call *%0;"
                :
                : "r"(relative)
                );
label:
 ;

 return 0;

}

The disassembler output is as follows.

Dump of assembler code for function main:
0x00000000004004d4 <+0>:     55 push   %rbp
0x00000000004004d5 <+1>:     48 89 e5   mov    %rsp,%rbp
0x00000000004004d8 <+4>:     ba f5 04 40 00 mov    $0x4004f5,%edx
0x00000000004004dd <+9>:     b8 c4 04 40 00 mov    $0x4004c4,%eax
0x00000000004004e2 <+14>:    48 89 d1   mov    %rdx,%rcx
0x00000000004004e5 <+17>:    48 29 c1   sub    %rax,%rcx
0x00000000004004e8 <+20>:    48 89 c8   mov    %rcx,%rax
0x00000000004004eb <+23>:    48 89 45 f8    mov    %rax,-0x8(%rbp)
0x00000000004004ef <+27>:    48 8b 45 f8    mov    -0x8(%rbp),%rax
0x00000000004004f3 <+31>:    ff d0  callq  *%rax
0x00000000004004f5 <+33>:    b8 00 00 00 00 mov    $0x0,%eax
0x00000000004004fa <+38>:    c9 leaveq 
0x00000000004004fb <+39>:    c3 retq

[1] http://x86.renejeschke.de/html/file_module_x86_id_26.html

Upvotes: 1

Views: 1434

Answers (2)

Ross Ridge
Ross Ridge

Reputation: 39581

All near and direct call instructions use relative addressing. So you don't really need to anything:

 __asm__ volatile ("call %P0" : : "i" (print_fn)
                   : "rax", "rcx", "rdx", "rsi", "rdi",
                     "r8", "r9", "r10", "r11",
                     "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5",
                     "xmm6", "xmm7", "xmm8", "xmm9", "xmm10", "xmm11",
                     "xmm12", "xmm13", "xmm14", "xmm15", "memory", "cc");

That will create a call instruction with a relative displacement to print_fn. It also tells the compiler that the instruction will clobber memory and a whole bunch of registers, namely the ones that aren't preserved across calls on Linux.

Upvotes: 4

Daniel Kamil Kozar
Daniel Kamil Kozar

Reputation: 19286

Actually, the link you've posted contains the answer. When you take a look at the list of variations of CALL, you'll notice that all CALL instructions that use indirect addressing automatically mean that the address it interpreted as an absolute one. Yet, specifying call *%0; in gcc's inline assembly means that you want the assembler to use exactly that : indirect addressing, in this case via a register.

Unfortunately, I don't know of any other way to make gcc emit a relative call instruction except when using a label. However, this would automatically mean that you would need to incorporate the body of the function into the inline assembly.

Upvotes: 2

Related Questions