set(POSITION_INDEPENDENT_CODE True)
position-independent code (PIC) 编译动态库 .so
position-independent code (PIC)
:用于生成位置无关代码。位置无关代码,可以理解为代码无绝对跳转,跳转都为相对跳转。生成动态库时,需要加上-fPIC
选项。
在 Linux 系统中,动态链接文件称为动态共享对象 (Dynamic Shared Objects,DSO),一般是以.so
为扩展名的文件。在 Windows 系统中,动态链接文件称为动态链接库 (Dynamic Linking Library),一般是以 .dll
为扩展名。
一般的编译链接命令行为:
gcc -fPIC -shared func.c -o libfunc.so
或者:
gcc -fPIC -c func.c -o func.o
gcc -shared func.o -o libfunc.so
-fPIC
选项作用于编译阶段,告诉编译器产生与位置无关代码 (Position-Independent Code)。
无-fPIC
选项
不添加fPIC
也可以生成.so
文件,但是对于源文件有要求。因为不加fPIC
编译的.so
必须要在加载到用户程序的地址空间时重定向到所有表目。所以在它里面不能引用其他代码
编译错误
/*
============================================================================
Name : function_validation.c
Author : Foreverstrong Cheng
Version :
Copyright : Copyright 2019 ForeverStrong License
Description : function_validation in C, Ansi-style
============================================================================
*/
#include <stdio.h>
int function_validation(int num)
{
puts("!!!Hello World!!!"); /* prints !!!Hello World!!! */
num += 1;
return num;
}
编译通过
/*
============================================================================
Name : function_validation.c
Author : Foreverstrong Cheng
Version :
Copyright : Copyright 2019 ForeverStrong License
Description : function_validation in C, Ansi-style
============================================================================
*/
#include <stdio.h>
int function_validation(int num)
{
// puts("!!!Hello World!!!"); /* prints !!!Hello World!!! */
num += 1;
return num;
}
不添加fPIC
生成的动态库,生产时假定它被加载在地址0处,加载时它会被加载到一个地址(base),需要进行一次重定位(relocation),代码、数据段中所有地址加上这个base的值。这时代码运行时就能使用正确的地址了
有-fPIC
选项
添加fPIC
选项生成的动态库,是位置无关。这样的代码本身就能被放到线性地址空间的任意位置,无需修改就能运行。通常的方法是获取指令指针的值,加上一个偏移得到全局变量/函数的地址。添加 -fPIC
选项的源文件对于它引用的函数头文件编写有较宽松的尺度。比如只需要包含声明的函数的头文件,即使没有相应的 C 文件来实现,编译成 .so
库照样可以通过。
添加 -fPIC 选项实现真正意义上的多个进程共享.so
库。多个进程引用同一个-fPIC
动态库时,可以共用内存。这一个库在不同进程中的虚拟地址不同,操作系统会把它们映射到同一块物理内存上。
不添加-fPIC
选项,加载 .so
库时,需要对代码段引用的数据对象重定位,重定位会修改代码段的内容,造成每个使用这个.so
文件代码段的进程在内核里都会生成这个.so
文件代码段的copy
,每个 copy 都不一样,取决于这个 .so 文件代码段和数据段内存映射的位置。不添加-fPIC
选项,消耗内存,编译的.so
文件的优点是加载速度快。
不能使用 .so 库来静态编译 (-static) 一个可执行程序,会出现错误提示:
attempted static link of dynamic object
/*
============================================================================
Name : function_validation.c
Author : Foreverstrong Cheng
Version :
Copyright : Copyright 2019 ForeverStrong License
Description : function_validation in C, Ansi-style
============================================================================
*/
#include <stdio.h>
int function_validation(int num)
{
puts("!!!Hello World!!!"); /* prints !!!Hello World!!! */
num += 1;
return num;
}
strong@foreverstrong:~/dbscan_work/fPIC_validation$ pwd
/home/strong/dbscan_work/fPIC_validation
strong@foreverstrong:~/dbscan_work/fPIC_validation$
strong@foreverstrong:~/dbscan_work/fPIC_validation$ ll
total 12
drwxrwxr-x 2 strong strong 4096 Feb 27 10:11 ./
drwxrwxr-x 14 strong strong 4096 Feb 27 09:18 ../
-rw-rw-r-- 1 strong strong 492 Feb 27 10:11 function_validation.c
strong@foreverstrong:~/dbscan_work/fPIC_validation$
strong@foreverstrong:~/dbscan_work/fPIC_validation$ gcc -fPIC -shared function_validation.c -o validation.so
strong@foreverstrong:~/dbscan_work/fPIC_validation$
strong@foreverstrong:~/dbscan_work/fPIC_validation$ ls -l
total 12
-rw-rw-r-- 1 strong strong 492 Feb 27 10:11 function_validation.c
-rwxrwxr-x 1 strong strong 8144 Feb 27 10:12 validation.so
strong@foreverstrong:~/dbscan_work/fPIC_validation$