在64位x86平台上比较PIE、PIC代码和可执行文件有什么区别?

在64位x86平台上比较PIE、PIC代码和可执行文件有什么区别?,c,linux,assembly,x86,elf,C,Linux,Assembly,X86,Elf,测试是在Ubuntu 12.04 64位上进行的。x86体系结构 我对位置独立可执行文件(PIE)和位置独立代码(PIC)的概念感到困惑,我猜它们不是正交的 这是我的快速实验 gcc -fPIC -pie quickSort.c -o a_pie.out gcc -fPIC quickSort.c -o a_pic.out gcc a.out objdump -Dr -j .text a.out > a1.temp objdu

测试是在Ubuntu 12.04 64位上进行的。x86体系结构

我对位置独立可执行文件(PIE)和位置独立代码(PIC)的概念感到困惑,我猜它们不是正交的

这是我的快速实验

gcc -fPIC -pie quickSort.c -o a_pie.out
gcc -fPIC      quickSort.c -o a_pic.out
gcc                           a.out

objdump -Dr -j .text a.out > a1.temp
objdump -Dr -j .text a_pic.out > a2.temp
objdump -Dr -j .text a_pie.out > a3.temp
我有以下发现

A.A.out包含一些PIC代码,但在libc序言和尾声函数中只有抵制,如下所示:

4004d0:       48 83 3d 70 09 20 00    cmpq   $0x0,0x200970(%rip)        # 600e48 <__JCR_END__> 
4004d0:48833d 700920000cmpq$0x0,0x200970(%rip)#600e48
在我的简单快速排序程序的汇编说明中,我没有找到任何PIC说明

B.a\u pic.out包含pic代码,我没有找到任何非pic指令。。。在我的快速排序程序的说明中,所有全局数据都由PIC说明访问,如下所示:

  40053b:       48 8d 05 ea 02 00 00    lea    0x2ea(%rip),%rax        # 40082c <_IO_stdin_used+0x4>
40053b:48 8d 05 ea 02 00 lea 0x2ea(%rip),%rax#40082c
C.与pic.out相比,pic.out包含语法相同的指令。但是,_pie.out的.text部分的内存地址范围为0x630到0xa57,而_pic.out的同一部分的内存地址范围为0x400410到0x400817

有人能给我解释一下这些现象吗?尤其是发现C。再一次,我对馅饼与PIC的比较感到困惑,不知道如何解释这个发现

我对位置独立可执行文件(PIE)和位置独立代码(PIC)的概念感到困惑,我猜它们不是正交的

PIE
PIC
之间唯一的真正区别是允许您在
PIC
中插入符号,但不能在
PIE
中插入符号。除此之外,它们几乎是等价的

您可以阅读有关符号插入的信息

与pic.out相比,pic.out包含语法相同的指令。但是,_pie.out的.text部分的内存地址范围为0x630到0xa57,而_pic.out的同一部分的内存地址范围为0x400410到0x400817

很难理解你对这件事的惊讶

饼图
二进制文件作为共享库链接,因此其默认加载地址(第一个
加载
段的
.p_vaddr
)为零。我们的期望是,某些东西会将这个二进制文件从零页重新定位,并将其加载到某个随机地址


另一方面,非饼图可执行文件总是在其链接地址处加载。在Linux上,
x86_64
二进制文件的默认地址是
0x400000
,因此
.text
就在不远处结束。

基本上
PIE
用于可执行文件,而
PIC
用于共享库。检查
PIC
可执行文件没有多大意义。还要注意,
gcc
相应地调用链接器。
-fPIC-pie
/facepalm。您应该使用
-fPIE
代码生成选项,而不是
-fPIC
-pie
是一个链接器选项,用于控制代码实际放入的可执行文件类型。(
-pie
单独将失败,因为它与32位绝对寻址不兼容)。有关PIE可执行文件与非PIE的更多信息,请参见。(请注意,大多数发行版构建GCC时默认使用
-fPIE-pie
)。