注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

^_^ china.ygw的博客

软件开发/c/c++/数据库/开源/linux/windows/安全/网络...

 
 
 

日志

 
 
 
 

Linux下生成动态链接库是否必须使用 -fPIC 的问题  

2013-07-18 22:14:20|  分类: linux |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

        今天因为一个linux环境下编译动态库未加-fPIC选项导致程序运行时错误,上网查找资料时找到这篇“Linux公社”网站中的”Linux下生成动态链接库是否必须使用 -fPIC 的问题“文章,看了一下感觉不错,特备份如下:

        在 Linux 下制作动态链接库,“标准” 的做法是编译成位置无关代码(Position Independent Code,PIC),然后链接成一个动态链接库。经常遇到的一个问题是 -fPIC 是不是必需,因为好像不加经常也能正常运行,只是创建 .so 的时候会有一个警告。

        搜索、试验了一下,答案似乎是这样:

        (1) 通常的建议是始终加上 -fPIC 生成位置无关代码;

        (2) AMD64 下,必须使用位置无关代码,否则连接失败:

        relocation R_X86_64_32S against `a local symbol' can not be used when making a shared object; recompile with -fPIC

        (3) IA32 下,连接成功,但有警告:

        warning: creating a DT_TEXTREL in object.

        这样的 .so 文件可以完全正常工作。

        可执行文件在链接时就知道每一行代码、每一个变量会被放到线性地址空间的什么位置,因此这些地址可以都作为常数写到代码里面。对动态库,这就不行了,这要等到加载时才知道。无非下面两种方法:

        (1) 可重定位代码(relocatable code):Windows DLL 以及不使用 -fPIC 的 Linux SO。

        生成动态库时假定它被加载在地址 0 处。加载时它会被加载到一个地址(base),这时要进行一次重定位(relocation),把代码、数据段中所有的地址加上这个 base 的值。这样代码运行时就能使用正确的地址了。

        (2) 位置无关代码(position independent code):使用 -fPIC 的 Linux SO。

        这样的代码本身就能被放到线性地址空间的任意位置,无需修改就能正确执行。通常的方法是获取指令指针(如 IA32 的 EIP 寄存器)的值,加上一个偏移得到全局变量/函数的地址。

PIC vs. relocatable:

        (1) PIC 的缺点主要就是代码有可能长一些。例如 IA32,由于不能直接使用 [EIP+constant] 这样的寻址方式,甚至不能直接将 EIP 的值交给其他寄存器,要用到 GOT(global offset table)来定位全局变量和函数。这样导致代码的效率略低。

        (2) PIC 的加载速度稍快,因为不需要做重定位。

        (3) 多个进程引用同一个 PIC 动态库时,可以共用内存。这一个库在不同进程中的虚拟地址不同,但操作系统显然会把它们映射到同一块物理内存上。对于可重定位代码,则必须为每个库都在物 理内存中复制一份副本,因为需要修改其中的地址。当然,主流现代操作系统都启用了分页内存机制,这使得重定位时可以使用 COW(copy on write)来节省内存(32 位 Windows 就是这样做的);然而,页面的粒度还是比较大的(例如 IA32 上是 4KiB),至少对于代码段来说能节省的相当有限。

        注:对于 AMD64,由于 AMD64 实现了 [RIP+constant] 的寻址方式,第 (1) 点不成立。

        这样,把动态库编译成 PIC 只有好处没有坏处,因而 Linux AMD64 要求用于生成动态库的目标文件必须使用 -fPIC 编译也合情合理了。

  评论这张
 
阅读(198)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018