在gcc中编译共享库时,-fPIC选项将代码编译为位置无关。是否有任何原因(性能或其他原因)您不能编译所有代码位置独立?
答案 0 :(得分:59)
它增加了间接性。使用与位置无关的代码,您必须加载函数的地址,然后跳转到它。通常,函数的地址已经存在于指令流中。
答案 1 :(得分:26)
是的,有性能原因。有些访问实际上在另一层间接下,以获得内存中的绝对位置。
还有GOT(全局偏移表)存储全局变量的偏移量。对我来说,这看起来就像是一个IAT修正表,它被维基百科和其他一些来源归类为位置依赖。
答案 2 :(得分:26)
This article解释了PIC的工作原理并将其与替代方法进行了比较 - load time relocation。我认为这与你的问题有关。
答案 3 :(得分:17)
除了接受的答案。严重损害PIC代码性能的一件事是在x86上缺乏“IP相对寻址”。使用“IP相对寻址”,您可以从当前指令指针请求X字节的数据。这将使PIC代码更加简单。
跳转和通话,通常是EIP相对的,所以这些并不会造成问题。但是,访问数据需要一些额外的诡计。有时,寄存器将暂时保留为代码所需数据的“基指针”。例如,一种常见的技术是滥用调用在x86上的工作方式:
call label_1
.dd 0xdeadbeef
.dd 0xfeedf00d
.dd 0x11223344
label_1:
pop ebp ; now ebp holds the address of the first dataword
; this works because the call pushes the **next**
; instructions address
; real code follows
mov eax, [ebp + 4] ; for example i'm accessing the '0xfeedf00d' in a PIC way
这种技术和其他技术为数据访问添加了一层间接。例如,gcc编译器使用的GOT(全局偏移表)。
x86-64添加了“RIP相对”模式,使得 lot 更简单。
答案 4 :(得分:2)
因为实现完全独立于位置的代码会向代码生成器添加一个约束,这可能会阻止使用更快的操作,或者添加额外的步骤来保留该约束。
在没有虚拟内存系统的情况下进行多处理可能是一种可接受的权衡,在虚拟内存系统中,您可以信任进程不会侵入彼此的内存,并且可能需要在任何基址加载特定的应用程序。
在许多现代系统中,性能权衡是不同的,并且重定位加载器通常比优化器在自由统治时可以做的最便宜(首次加载代码时的成本)。此外,虚拟地址空间的可用性首先掩盖了位置独立性的大部分动机。
答案 5 :(得分:1)
此外,大多数现代处理器(大多数现代操作系统使用)中的虚拟内存硬件意味着许多代码(所有用户空间应用程序,禁止使用mmap等)不需要与位置无关。每个程序都有自己的地址空间,它认为从零开始。
答案 6 :(得分:1)
position-independent code
在大多数架构上都有性能开销,因为它需要额外的寄存器。
所以,这是出于性能目的。
答案 7 :(得分:1)
该问题的日期为2009年。已经过去了十年,现在所有代码实际上都是与位置无关的。现在由操作系统和编译器强制执行。无法选择退出。所有代码都使用PIE强制编译,并且-no-pic / -no-pie标志被忽略,这是此ASLR借口的一部分。这样做的原因是,以提高安全性为幌子,放慢了以前快速的应用程序的速度,并出售了更新的硬件。这是完全不合理的,因为现在大容量的内存使我们完全摆脱了动态链接的麻烦,可以静态地编译所有应用程序。
以前发生过同样的事情,人们默默地接受实模式,而其他自由正在被夺走。我想请您注意,由于上下文切换和地址转换延迟,MMU的速度大大降低。您不会在性能至关重要的系统中找到MMU,就像科学家用来对物理实验进行采样的系统一样。
您没有抱怨,因为您甚至都不知道所有这些培训轮子都妨碍了您的代码。我能说什么立即使用其PIC享受慢2倍的软件!甚至随着LLVM的到来,很快将强制实施JIT(托管代码),而无法访问x86内联汇编,这将进一步减慢任何C / C ++代码的速度。 “为安全而牺牲自由的人都不应该得到。”
答案 8 :(得分:0)
现在,操作系统和编译器默认将所有代码都作为位置无关代码。尝试编译没有-fPIC标志,代码将编译正常,但你会得到一个警告.OS就像Windows使用一种称为内存映射的技术来实现这一点。