GCC -fPIC 选项
I have read about GCC's Options for Code Generation Conventions, but could not understand what "Generate position-independent code (PIC)" does. Please give an example to explain me what does it mean.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
位置无关代码意味着生成的机器代码不依赖于位于特定地址才能工作。
例如,跳跃将生成为相对的而不是绝对的。
伪汇编:
PIC:无论代码位于地址 100 还是 1000,这都有效。
非 PIC:仅当代码位于地址 100 时才有效
编辑:响应评论。
如果您的代码是使用 -fPIC 编译的,则它适合包含在库中 - 该库必须能够从内存中的首选位置重定位到另一个地址,在您的库首选的地址可能有另一个已加载的库。
Position Independent Code means that the generated machine code is not dependent on being located at a specific address in order to work.
E.g. jumps would be generated as relative rather than absolute.
Pseudo-assembly:
PIC: This would work whether the code was at address 100 or 1000
Non-PIC: This will only work if the code is at address 100
EDIT: In response to comment.
If your code is compiled with -fPIC, it's suitable for inclusion in a library - the library must be able to be relocated from its preferred location in memory to another address, there could be another already loaded library at the address your library prefers.
我将尝试以更简单的方式解释已经说过的内容。
每当加载共享库时,加载器(操作系统上加载您运行的任何程序的代码)都会根据对象加载到的位置更改代码中的一些地址。
在上面的例子中,非PIC代码中的“111”是加载程序第一次加载时写入的。
对于非共享对象,您可能希望它是这样的,因为编译器可以对该代码进行一些优化。
对于共享对象,如果另一个进程想要“链接”到该代码,它必须将其读取到相同的虚拟地址,否则“111”将毫无意义。但该虚拟空间可能已在第二个进程中使用。
I'll try to explain what has already been said in a simpler way.
Whenever a shared lib is loaded, the loader (the code on the OS which load any program you run) changes some addresses in the code depending on where the object was loaded to.
In the above example, the "111" in the non-PIC code is written by the loader the first time it was loaded.
For not shared objects, you may want it to be like that because the compiler can make some optimizations on that code.
For shared object, if another process will want to "link" to that code it must read it to the same virtual addresses or the "111" will make no sense. But that virtual-space may already be in use in the second process.
内置于共享库中的代码通常应该是与位置无关的代码,以便可以轻松地将共享库加载到(或多或少)内存中的任何地址。
-fPIC
选项确保 GCC 生成这样的代码。Code that is built into shared libraries should normally be position-independent code, so that the shared library can readily be loaded at (more or less) any address in memory. The
-fPIC
option ensures that GCC produces such code.进一步添加...
每个进程都有相同的虚拟地址空间(如果通过在 Linux 操作系统中使用标志来停止虚拟地址的随机化)
(有关更多详细信息禁用并重新启用地址空间布局随机化仅适用于我自己)
因此,如果它是一个没有共享链接的exe(假设场景),那么我们总是可以为相同的asm指令提供相同的虚拟地址,而不会造成任何损害。
但是,当我们想要将共享对象链接到 exe 时,我们不确定分配给共享对象的起始地址,因为它将取决于共享对象链接的顺序。也就是说,.so 中的 asm 指令将始终具有不同的虚拟地址取决于其链接到的进程。
因此,一个进程可以在自己的虚拟空间中为 .so 提供起始地址,如 0x45678910,而其他进程同时可以为 .so 提供起始地址 0x12131415,如果它们不使用相对寻址,则 .so 将根本不起作用。
因此他们总是必须使用相对寻址模式以及 fpic 选项。
Adding further...
Every process has same virtual address space (If randomization of virtual address is stopped by using a flag in linux OS)
(For more details Disable and re-enable address space layout randomization only for myself)
So if its one exe with no shared linking (Hypothetical scenario), then we can always give same virtual address to same asm instruction without any harm.
But when we want to link shared object to the exe, then we are not sure of the start address assigned to shared object as it will depend upon the order the shared objects were linked.That being said, asm instruction inside .so will always have different virtual address depending upon the process its linking to.
So one process can give start address to .so as 0x45678910 in its own virtual space and other process at the same time can give start address of 0x12131415 and if they do not use relative addressing, .so will not work at all.
So they always have to use the relative addressing mode and hence fpic option.
对已经发布的答案的一个小补充:未编译为位置独立的目标文件是可重定位的;它们包含重定位表条目。
这些条目允许加载程序(将程序加载到内存中的那段代码)重写绝对地址以调整虚拟地址空间中的实际加载地址。
操作系统将尝试与链接到同一共享对象库的所有程序共享加载到内存中的“共享对象库”的单个副本。
由于代码地址空间(与数据空间的各个部分不同)不需要是连续的,并且由于链接到特定库的大多数程序都具有相当固定的库依赖关系树,因此大多数情况下都会成功。在极少数存在差异的情况下,是的,内存中可能需要有两个或更多共享对象库的副本。
显然,任何在程序和/或程序实例之间随机化库的加载地址的尝试(以减少创建可利用模式的可能性)都会使这种情况变得常见,而不是罕见,因此如果系统启用了此功能,人们应该尽一切努力将所有共享对象库编译为位置无关的。
由于从主程序主体对这些库的调用也将变得可重定位,这使得必须复制共享库的可能性大大降低。
A minor addition to the answers already posted: object files not compiled to be position independent are relocatable; they contain relocation table entries.
These entries allow the loader (that bit of code that loads a program into memory) to rewrite the absolute addresses to adjust for the actual load address in the virtual address space.
An operating system will try to share a single copy of a "shared object library" loaded into memory with all the programs that are linked to that same shared object library.
Since the code address space (unlike sections of the data space) need not be contiguous, and because most programs that link to a specific library have a fairly fixed library dependency tree, this succeeds most of the time. In those rare cases where there is a discrepancy, yes, it may be necessary to have two or more copies of a shared object library in memory.
Obviously, any attempt to randomize the load address of a library between programs and/or program instances (so as to reduce the possibility of creating an exploitable pattern) will make such cases common, not rare, so where a system has enabled this capability, one should make every attempt to compile all shared object libraries to be position independent.
Since calls into these libraries from the body of the main program will also be made relocatable, this makes it much less likely that a shared library will have to be copied.