在 gcc 中编译共享库时,-fPIC 选项将代码编译为位置无关的。是否有任何原因(性能或其他)导致您不编译所有位置独立的代码?

有帮助吗?

解决方案

它增加了间接性。使用与位置无关的代码,您必须加载函数的地址,然后跳转到它。通常,函数的地址已经存在于指令流中。

其他提示

是的,有性能原因。某些访问实际上是在另一层间接下获取内存中的绝对位置。

还有GOT(全局偏移表),存储全局变量的偏移量。对我来说,这看起来就像一个 IAT 修正表,维基百科和其他一些来源将其归类为位置相关。

http://en.wikipedia.org/wiki/Position_independent_code

本文解释PIC如何工作并将其与替代方案进行比较 - 加载时间重定位。我认为这与你的问题有关。

除了接受的答案。严重损害PIC代码性能的一件事是缺少“IP相对寻址”。在x86上。使用“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亲属”。模式使得很多更简单。

因为实现完全独立于位置的代码会向代码生成器添加一个约束,这可能会阻止使用更快的操作,或者添加额外的步骤来保留该约束。

在没有虚拟内存系统的情况下进行多处理可能是一种可接受的权衡,在虚拟内存系统中,您可以信任进程不会侵入彼此的内存,并且可能需要在任何基址加载特定的应用程序。

在许多现代系统中,性能权衡是不同的,并且重定位加载器通常比优化器在自由统治时可以做的最便宜(首次加载代码时的成本)。此外,虚拟地址空间的可用性首先掩盖了位置独立性的大部分动机。

此外,大多数现代处理器(大多数现代操作系统使用)中的虚拟内存硬件意味着许多代码(所有用户空间应用程序,禁止使用mmap等),不需要与位置无关。每个程序都有自己的地址空间,它认为从零开始。

与位置无关的代码在大多数架构上都有性能开销,因为它需要额外的寄存器。

所以,这是出于性能目的。

现在,操作系统和编译器默认将所有代码都作为位置无关代码。尝试编译没有-fPIC标志,代码将编译正常,但你会得到一个警告.OS就像Windows使用一种称为内存映射的技术来实现这一点。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top