从源代码编译二进制文件时,生成 PIC objects 之间的实际差异是什么?或不?在什么时候有人会说,“我应该在编译 MySQL 时生成/使用 PIC 对象。”或不?
我已阅读 Gentoo's Introduction to Position Independent Code , Position Independent Code internals , HOWTO fix -fPIC errors , Libtool's Creating object files , 和 Position Independent Code .
来自 PHP ./configure --help
:
--with-pic: Try to use only PIC/non-PIC objects [default=use both].
来自 MySQL 的
cmake -LAH .
:-DWITH_PIC: Generate PIC objects
这些信息是一个好的开始,但给我留下了很多问题。
据我了解,它开启
-fPIC
在编译器中,它反过来在生成的二进制文件/库中生成 PIC 对象。我为什么要这样做?或相反亦然。也许它风险更大,或者可能会使二进制文件不太稳定?也许在某些架构上编译时应该避免它(在我的情况下是 amd64/x86_64)?默认的 MySQL build设置 PIC=OFF。官方 MySQL 版本build设置 PIC=ON。而 PHP“试图同时使用两者”。在我的测试设置中
-DWITH_PIC=ON
导致稍大的二进制文件: PIC=OFF PIC=ON
mysql 776,160 778,528
mysqld 7,339,704 7,476,024
最佳答案
有两个概念不应混淆:
他们都处理类似的问题,但在不同的层面上。
问题
大多数处理器架构有两种寻址方式:绝对寻址和相对寻址。寻址通常用于两种类型的访问:访问数据(读、写等)和执行代码的不同部分(跳转、调用等)。两者都可以绝对完成(调用位于固定地址的代码,在固定地址读取数据)或相对(跳转到五个指令,相对于指针读取)。
相对寻址通常会同时消耗速度和内存。速度,因为处理器必须根据指针和相对值计算绝对地址,然后才能访问实际内存位置或实际指令。内存,因为必须存储一个额外的指针(通常在一个寄存器中,它非常快但内存也非常稀缺)。
绝对寻址并不总是可行的,因为如果天真地实现,则必须在编译时知道所有地址。在许多情况下,这是不可能的。从外部库调用代码时,人们可能不知道操作系统将在哪个内存位置加载库。在对堆上的数据寻址时,我们不会事先知道操作系统将为该操作保留哪个堆块。
然后还有很多技术细节。例如。处理器架构只允许相对跳转到一定的限制;所有更宽的跳跃都必须是绝对的。或者在地址范围很宽(例如64位甚至128位)的体系结构上,相对寻址会导致代码更紧凑(因为相对地址可以使用16位或8位,但绝对地址必须始终为64位或128 位)。
可重定位的二进制文件
当程序使用绝对地址时,它们会对地址空间的布局做出非常强的假设。操作系统可能无法满足所有这些假设。为了缓解这个问题,大多数操作系统可以使用一个技巧:二进制文件中包含额外的元数据。操作系统然后使用此元数据在运行时更改二进制文件,因此修改后的假设适合当前情况。通常元数据描述指令在二进制中的位置,使用绝对定位。当操作系统随后加载二进制文件时,它会在必要时更改存储在这些指令中的绝对地址。
这些元数据的一个例子是 ELF 文件格式的“重定位表”。
一些操作系统使用了一个技巧,因此它们在运行之前不需要总是处理每个文件:它们预处理文件并更改数据,因此它们的假设很可能在运行时适合情况(因此不需要修改)。此过程在 Mac OS X 上称为“预绑定(bind)”,在 Linux 上称为“预链接”。
可重定位二进制文件是在链接器级别生成的。
位置无关代码 (PIC)
编译器可以生成仅使用相对寻址的代码。这可能意味着数据和代码的相对寻址或仅这些类别之一。 gcc 上的选项“-fPIC”,例如意味着强制执行代码的相对寻址(即仅相对跳转和调用)。然后代码可以在任何内存地址上运行而无需任何修改。在某些处理器架构上,这样的代码并不总是可能的,例如当相对跳转的范围受到限制时(例如,允许最多 128 条指令宽的相对跳转)。
位置无关代码在编译器级别处理。仅包含 PIC 代码的可执行文件不需要重定位信息。
什么时候需要PIC代码
在某些特殊情况下,绝对需要 PIC 代码,因为加载时重定位是不可行的。一些例子:
什么时候应该避免 PIC
建议/结论
由于某些特殊限制,可能需要 PIC 代码。在所有其他情况下,坚持使用默认值。如果您不了解此类约束,则不需要“-fPIC”。
关于gcc - 编译 WITH_PIC (-DWITH_PIC, --with-pic) 实际上有什么作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18026333/