Reputation: 1439
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
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
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