`
weiyinchao88
  • 浏览: 1175944 次
文章分类
社区版块
存档分类
最新评论

在x64位Linux上生成动态链接库必须使用编译选项-fPIC的问题

 
阅读更多
2008年09月26日 星期五 16:33
在 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 编译也合情合理了。

分享到:
评论

相关推荐

    boost_linux_fPIC.rar

    boost的linux静态库版本,添加了-fPIC选项,一般的boost静态库没有此选项,动态库在调用的时候会报下面的内容,用了这个库就不会出了(网上教的编译方法都是针对1.55版本的,后面的版本代码都不一样): /usr/bin/...

    gcc编译动态库

    在使用GCC编译程序时,只需加上-shared选项即可,这样生成的执行程序即为动态链接库。 其中-fPIC选项的作用是:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的, 所以动态载入时是通过代码拷贝...

    Linux C语言动态库及静态库的制作步骤讲解

     gcc -c -fPIC add.c sub.c div.c mul.c //-c表示生成.o目标文件,-f后加一些编译选项,PIC表示与位置无关  gcc -shared -o libmymath.so add.o sub.o mul.o div.o//创建共享库mymath,添加add.o,sub.o,...

    linux动态链接库

    通过shared和fPIC编译参数生产so动态链接库文件。程序在调用库函数时,只需要连接上这个库即可。例如下面实现一个简单的整数四则运输的动态链接库,定义的caculate.h和caculate.c两个文件,生产libcac.so动态链接库...

    libevent-2.0.22 windows和linux下的静态库,附源码和libevent使用手册

    libevent-2.0.22-stable.tar.gz源码编译的Windows和Linux下的静态库,另附源码,电子书《libevent...Linux环境下该libevent静态库修改Makefile加入编译选项-fPIC,这样可以使静态库被正确的链接到自己工程的动态库。

    Linux代码,以C++为基础.rar

    g++编译选项 -fPIC,告诉编译器产生与位置无关代码(Position-Independent Code),则产生的代码中,没有绝对地址,全部使用相对地址,这正是共享库所要求的 -shared,表明产生共享库 -lpthread,多线程使用,lpthread...

    gcc 中文帮助文档

    -fPIC 编译选项 -static 编译选项 AT&T的汇编格式 x86内联汇编 简述 内联汇编 程序模板 操作数 修饰寄存器列表 操作数约束 示例 寄存器约束 匹配约束 内存操作数约束 修饰寄存器 不同的CPU下最佳编译...

    Linux串口开发及共享库调用例程

    先在命令行运行make编译,生成串口读写共享库,然后运行gcc -s -shared -fPIC test.c -lSetupSerialPort -o test.so,编译串口读写测试程序。 文件说明: SetupSerialPort.h //串口读写库头文件 SetupSerialPort.c /...

    test-fpic.rar_The Test

    This test is used to check that -fpic is a default compiler option for the arm-linux-androideabi toolchain.

    64位下编译GD出错问题

    在64位下编译GD 如果/usr/bin/ld: /usr/local/lib/libz.a(compress.o): relocation R_X86_64_32 against `a local symbol' can not be used when making a shared object; recompile with -fPIC 这说明zlib没用用-...

    Linux动态链接库的使用

    通过shared和fPIC编译参数生产so动态链接库文件。程序在调用库函数时,只需要连接上这个库即可。例如下面实现一个简单的整数四则运输的动态链接库,定义的caculate.h和caculate.c两个文件,生产libcac.so动态链接库...

    Linux下串口读写例程

    先在命令行运行make编译,生成串口读写共享库,然后运行gcc -s -shared -fPIC test.c -lSetupSerialPort -o test.so,编译串口读写测试程序。 文件说明: SetupSerialPort.h //串口读写库头文件 SetupSerialPort.c /...

    重新编译Google串口开源库生成的.so动态库

    在Android.mk文件中加入LOCAL_LDFLAGS += -fPIC,重新编译的.so动态库

    Windows下32位的FFMPEG4.2.2的库,包括编译运行库和头文件

    在Windows下使用的32位FFMPEG4.2.2的库,包括编译运行库和头文件。 使用方法参考: https://blog.csdn.net/xiaolong1126626497/article/details/105446935

    linux下configure命令详细介绍

    如果通过源代码编译后在安装,当然事情就更为复杂一些;现在安装各种软件的教程都非常普遍;但万变不离其中,对基础知识的扎实掌握,安装各种软件的问题就迎刃而解了。Configure脚本配置工具就是基础之一,它是...

    so动态加载库Hotpatch.zip

    Hotpatch 是一个允许正在运行的进程动态加载一个 so 库的 C 库,类似于 Win32 上的 CreateRemoteThread() API。 和其他现有的动态加载方案相比,Hotpatch 的优点是在加载 so 库之后将会恢复原先进程的运行状态。 ...

    GCC静态库和共享库的生成及调用

    GCC静态库和共享库的生成及调用 GCC静态库和共享库的生成及调用

    GCC使用教程.pdf

    6. -fPIC 编译选项 7. -static 编译选项 5. AT&T 的汇编格式 6. x86 内联汇编 1. 简述 2. 内联汇编 3. 程序模板 4. 操作数 5. 修饰寄存器列表 6. 操作数约束 7. 示例 1. 寄存器约束 2. 匹配约束 3. 内存操作数约束 4...

    经典GCC_使用教程

    6. -fPIC 编译选项 7. -static 编译选项 5. AT&T的汇编格式 6. x86内联汇编 1. 简述 2. 内联汇编 3. 程序模板 4. 操作数 5. 修饰寄存器列表 6. 操作数约束 7. 示例 1. 寄存器约束 2. 匹配约束 3. 内存...

    suse linux下安装php5、Lighttpd .

    -f 标志使 Bzip2 根据另一个 Makefile 来编译,也就是这里的 Makefile-libbz2_so 文件,它创建一个动态的 libbz2.so 库文件,然后把 Bzip2 工具连接到这个库上 如果要重新安装 Bzip2 ,请先执行 rm -vf /usr/bin/bz*...

Global site tag (gtag.js) - Google Analytics