c - 为什么 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]
为此使用计算。
问题:
- 为什么在汇编指令中
sum[rip]
使用,而不是简单的标签,例如?lea rax, sum[rip]
sum
lea rax, sum
mov rax, 0x5fa
指令会做同样的事情吗?因为我们知道sum
链接后的地址:call 0x5fa <sum>
指令只是直接使用它。
解决方案
我相信这可能取决于您的 GCC 版本,但在我使用的 Linux 发行版上,所有内容都设置为默认为 PIC 版本。那是位置无关代码。这对共享库和可执行文件都更好,因为结果可以映射到任何地方的内存中,而无需修复传递。因为可以应用ASLR,所以对安全性更好。
对于 x86-64,使用 PIC 并没有明显的损失,那么为什么不到处使用它呢?
推荐阅读
- javascript - 当数组返回 0 行时,如何在 php while 语句中回显某些内容?
- javascript - HTML5 画布线变成曲折线?
- logparser - Logparser 查询没有给我任何输出
- vue-router - 如何使用 Vue-Router 导航守卫?
- java - 当框出现在屏幕中间时更改框的背景颜色
- shell - 并行调用多个函数在 ksh 脚本中间歇性地工作
- regex - RegEx/XPath 以匹配 XML 中的某些 Adobe LiveCycle Designer 字段
- r - 将两个数据框连接到最近的记录
- python - 使用 Binet 公式在 python 中获取较大斐波那契数的准确值
- node.js - TypeError:无法读取未定义的属性“myDate”