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

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

or

gcc -fPIC -c func.c -o func.o
gcc -shared func.o -o libfunc.so

-fPIC 选项作用于编译阶段,告诉编译器产生与位置无关代码 (Position-Independent Code)。

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 <stdio.h>

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 <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 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 <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$
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yongqiang Cheng

梦想不是浮躁,而是沉淀和积累。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值