position-independent code (PIC) 编译动态库 `.so`

2019-04-15 16:30发布

position-independent code (PIC) 编译动态库 .so

position-independent code (PIC),用于生成位置无关代码。位置无关代码,可以理解为代码无绝对跳转,跳转都为相对跳转。生成动态库时,需要加上 -fPIC 选项。

1. 无 -fPIC 选项

不添加 -fPIC 也可以生成 .so 文件,但是对于源文件有要求。因为不加 -fPIC 编译的 .so 必须要在加载到用户程序的地址空间时重定向所有表目,所以在它里面不能引用其它地方的代码。

1.1 编译错误

/* ============================================================================ Name : function_validation.c Author : Foreverstrong Cheng Version : Copyright : Copyright 2019 ForeverStrong License Description : function_validation in C, Ansi-style ============================================================================ */ #include int function_validation(int num) { puts("!!!Hello World!!!"); /* prints !!!Hello World!!! */ num += 1; return num; }

1.2 编译通过

/* ============================================================================ Name : function_validation.c Author : Foreverstrong Cheng Version : Copyright : Copyright 2019 ForeverStrong License Description : function_validation in C, Ansi-style ============================================================================ */ #include 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 09:30 ./ drwxrwxr-x 14 strong strong 4096 Feb 27 09:18 ../ -rw-rw-r-- 1 strong strong 492 Feb 27 09:30 function_validation.c strong@foreverstrong:~/dbscan_work/fPIC_validation$ strong@foreverstrong:~/dbscan_work/fPIC_validation$ gcc -shared function_validation.c -o validation.so /usr/bin/ld: /tmp/ccL12xkz.o: relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC /tmp/ccL12xkz.o: error adding symbols: Bad value collect2: error: ld returned 1 exit status strong@foreverstrong:~/dbscan_work/fPIC_validation$ strong@foreverstrong:~/dbscan_work/fPIC_validation$ gcc -shared function_validation.c -o validation.so strong@foreverstrong:~/dbscan_work/fPIC_validation$ ll total 20 drwxrwxr-x 2 strong strong 4096 Feb 27 09:34 ./ drwxrwxr-x 14 strong strong 4096 Feb 27 09:18 ../ -rw-rw-r-- 1 strong strong 495 Feb 27 09:34 function_validation.c -rwxrwxr-x 1 strong strong 7904 Feb 27 09:34 validation.so* strong@foreverstrong:~/dbscan_work/fPIC_validation$ 不添加 -fPIC 生成的动态库,生成时假定它被加载在地址 0 处。加载时它会被加载到一个地址 (base),需要进行一次重定位 (relocation),代码、数据段中所有的地址加上这个 base 的值。这时代码运行时就能使用正确的地址了。

2. 有 -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 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$