我写了以下示例代码。但它产生了在r / m32"中给出的接近,绝对间接的地址。 (如[1]所示)调用指令的变体,由于地址被解释为绝对的,因此失败并出现分段错误。有没有办法用GCC内联汇编生成PC相对调用?顺便说一句,代码正确地计算了相对距离,所以没有问题。
#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;
}
反汇编输出如下。
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
答案 0 :(得分:4)
所有近端和直接call
指令都使用相对寻址。所以你真的不需要做任何事情:
__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");
这将创建call
指令,其相对位移为print_fn
。它还告诉编译器该指令将破坏内存和一大堆寄存器,即在Linux上的调用之间不保留的寄存器。
答案 1 :(得分:2)
实际上,您发布的链接包含答案。当您查看CALL
的变体列表时,您会注意到所有使用间接寻址的CALL
指令都会自动表示它被解释为绝对地址的地址。然而,在gcc的内联汇编中指定call *%0;
意味着您希望汇编器使用它:间接寻址,在这种情况下通过寄存器。
不幸的是,除了使用标签之外,我不知道使gcc发出相对call
指令的任何其他方法。但是,这自动意味着您需要将函数体添加到内联汇编中。