首页 > 解决方案 > 为什么 gcc 在汇编中使用函数指针的相对地址?

问题描述

C源:

int sum(int a, int b) {    
    return a + b;    
}    

int main() {    
    int (*ptr_sum_1)(int,int) = sum;   // assign the address of the "sum" 
    int (*ptr_sum_2)(int,int) = sum;   // to the function pointer 
    int (*ptr_sum_3)(int,int) = sum;    

    int a = (*ptr_sum_1)(2,4);   // call the "sum" through the pointer 
    int b = sum(2,4);            // call the "sum" by usual way

    return 0;    
}

汇编代码的关键部分:

lea rax, sum[rip]
mov QWORD PTR -24[rbp], rax
lea rax, sum[rip]
mov QWORD PTR -16[rbp], rax
lea rax, sum[rip]
mov QWORD PTR -8[rbp], rax

来自 GDB 的执行程序指令:

   0x5fa <sum>: push   rbp
   0x5fb <sum+1>:   mov    rbp,rsp
   0x5fe <sum+4>:   mov    DWORD PTR [rbp-0x4],edi
   0x601 <sum+7>:   mov    DWORD PTR [rbp-0x8],esi
   0x604 <sum+10>:  mov    edx,DWORD PTR [rbp-0x4]
   0x607 <sum+13>:  mov    eax,DWORD PTR [rbp-0x8]
   0x60a <sum+16>:  add    eax,edx
   0x60c <sum+18>:  pop    rbp
   0x60d <sum+19>:  ret    
   0x60e <main>:    push   rbp
   0x60f <main+1>:  mov    rbp,rsp
   0x612 <main+4>:  sub    rsp,0x20
   0x616 <main+8>:  lea    rax,[rip+0xffffffffffffffdd]        # 0x5fa <sum>
   0x61d <main+15>: mov    QWORD PTR [rbp-0x18],rax
   0x621 <main+19>: lea    rax,[rip+0xffffffffffffffd2]        # 0x5fa <sum>
   0x628 <main+26>: mov    QWORD PTR [rbp-0x10],rax
   0x62c <main+30>: lea    rax,[rip+0xffffffffffffffc7]        # 0x5fa <sum>
   0x633 <main+37>: mov    QWORD PTR [rbp-0x8],rax
   0x637 <main+41>: mov    rax,QWORD PTR [rbp-0x18]
   0x63b <main+45>: mov    esi,0x4
   0x640 <main+50>: mov    edi,0x2
   0x645 <main+55>: call   rax
   0x647 <main+57>: mov    DWORD PTR [rbp-0x20],eax
   0x64a <main+60>: mov    esi,0x4
   0x64f <main+65>: mov    edi,0x2
   0x654 <main+70>: call   0x5fa <sum>
   0x659 <main+75>: mov    DWORD PTR [rbp-0x1c],eax
   0x65c <main+78>: mov    eax,0x0
   0x661 <main+83>: leave  
   0x662 <main+84>: ret  

我认为sum标签只是sum程序的起始地址 - 0x5fa,所以我不明白为什么gcc不能直接使用它,而是sum[rip]为此使用计算。

问题:

  1. 为什么在汇编指令中sum[rip]使用,而不是简单的标签,例如?lea rax, sum[rip]sumlea rax, sum
  2. mov rax, 0x5fa指令会做同样的事情吗?因为我们知道sum链接后的地址:call 0x5fa <sum>指令只是直接使用它。

标签: cgccassemblyx86-64

解决方案


我相信这可能取决于您的 GCC 版本,但在我使用的 Linux 发行版上,所有内容都设置为默认为 PIC 版本。那是位置无关代码。这对共享库可执行文件都更好,因为结果可以映射到任何地方的内存中,而无需修复传递。因为可以应用ASLR,所以对安全性更好。

对于 x86-64,使用 PIC 并没有明显的损失,那么为什么不到处使用它呢?


推荐阅读