简体   繁体   English

具有GCC内联组件的PC相对CALL

[英]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. 但是它会生成调用指令的“ r / m32中给出的近,绝对间接地址”(如[1]中给出的),由于地址被解释为绝对地址,它会因分段错误而失败。 Is there any way for generating PC relative call with GCC inline assembly? 有什么方法可以通过GCC内联汇编生成PC相对调用? 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 [1] http://x86.renejeschke.de/html/file_module_x86_id_26.html

All near and direct call instructions use relative addressing. 所有接近call和直接call指令均使用相对寻址。 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 . 这将创建一个相对于print_fn相对位移的call指令。 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. 它还告诉编译器,该指令将破坏内存和一大堆寄存器,即在Linux上的各个调用之间不会保留的寄存器。

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. 查看CALL的变体列表时,您会注意到,所有使用间接寻址的CALL指令都会自动将其解释为绝对地址。 Yet, specifying call *%0; 但是,指定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. 在gcc的内联汇编中,意味着您希望汇编器完全使用that:间接寻址,在这种情况下是通过寄存器。

Unfortunately, I don't know of any other way to make gcc emit a relative call instruction except when using a label. 不幸的是,除了使用标签时,我不知道让gcc发出相对call指令的任何其他方法。 However, this would automatically mean that you would need to incorporate the body of the function into the inline assembly. 但是,这将自动意味着您需要将函数主体合并到内联程序集中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM