为什么不是所有的代码编译位置独立?
在gcc中编译共享库时,-fPIC选项将代码编译为位置无关的代码。 是否有任何理由(性能或其他)为什么你不会编译所有的代码位置独立?
它增加了间接性。 使用位置独立的代码,你必须加载你的函数的地址,然后跳转到它。 通常该函数的地址已经存在于指令stream中。
是的,有性能的原因。 一些访问有效地在另一层间接的层面上来获得内存中的绝对位置。
还有存储全局variables偏移的GOT(全局偏移量表)。 对我来说,这看起来像一个IAT修正表,根据维基百科和其他一些资料来看,它被归类为位置依赖。
本文解释PIC如何工作,并将其与替代加载时间重定位进行比较。 我认为这与你的问题有关。
除了接受的答案。 有一件事伤害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相对”模式,使事情变得简单得多。
由于实现完全独立于位置的代码会向代码生成器添加一个约束,从而可以防止使用更快的操作,或者添加额外的步骤来保留该约束。
这可能是一个可以接受的折衷scheme,在不使用虚拟内存系统的情况下进行多处理,您可以信任进程不会侵入彼此的内存,并且可能需要在任何基址上加载特定的应用程序。
在许多现代系统中,性能权衡是不同的,重定位加载器通常比较便宜(它首先加载任何时间代码),而不是优化器可以做的最好的方法。 此外,虚拟地址空间的可用性首先隐藏了位置独立的大部分动机。
此外,大多数现代处理器(大多数现代操作系统使用的)中的虚拟内存硬件意味着大量的代码(所有的用户空间应用程序,禁止使用mmap等)都不需要独立于位置。 每个程序都有自己认为从零开始的地址空间。
position-independent code
在大多数架构上都有性能开销,因为它需要一个额外的寄存器。
所以,这是为了性能目的。
现在的操作系统和编译器默认将所有的代码作为位置独立的代码。 尝试编译没有-fPIC标志,代码将编译好,但你只会得到一个warning.OS的像Windows使用称为内存映射的技术来实现这一点。