gcc编译参数-fPIC的一些问题

ppc_85xx-gcc -shared -fPIC liberr.c -o liberr.so

-fPIC 作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code),
   则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意
  位置,都可以正确的执行。 这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。

gcc -shared -fPIC -o 1.so 1.c
这里有一个-fPIC参数
PIC就是position independent code
PIC使.so文件的代码段变为真正意义上的共享
如果不加-fPIC,则加载.so文件的代码段时,代码段引用的数据对象需要重定位, 重定位会修改代码段的内容,这就造成每个使用这个.so文件代码段的进程在内核里都会生成这个.so文件代码段的copy.每个copy都不一样,取决于 这个.so文件代码段和数据段内存映射的位置.


不加fPIC编译出来的so,是要再加载时根据加载到的位置再次重定位的.(因为它里面的代码并不是位置无关代码)
如果被多个应用程序共同使用,那么它们必须每个程序维护一份so的代码副本了.(因为so被每个程序加载的位置都不同,显然这些重定位后的代码也不同,当然不能共享)
我们总是用fPIC来生成so,也从来不用fPIC来生成a.
fPIC与动态链接可以说基本没有关系,libc.so一样可以不用fPIC编译,只是这样的so必须要在加载到用户程序的地址空间时重定向所有表目.

因此,不用fPIC编译so并不总是不好.
如果你满足以下4个需求/条件:
1.该库可能需要经常更新
2.该库需要非常高的效率(尤其是有很多全局量的使用时)
3.该库并不很大.
4.该库基本不需要被多个应用程序共享

如果用没有加这个参数的编译后的共享库,也可以使用的话,可能是两个原因:
1:gcc默认开启-fPIC选项
2:loader使你的代码位置无关

从GCC来看,shared应该是包含fPIC选项的,但似乎不是所以系统都支持,所以最好显式加上fPIC选项。参见如下


`-shared'
     Produce a shared object which can then be linked with other
     objects to form an executable.  Not all systems support this
     option.  For predictable results, you must also specify the same
     set of options that were used to generate code (`-fpic', `-fPIC',
     or model suboptions) when you specify this option.(1)



-fPIC 的使用,会生成 PIC 代码,.so 要求为 PIC,以达到动态链接的目的,否则,无法实现动态链接。

non-PIC 与 PIC 代码的区别主要在于 access global data, jump label 的不同。
比如一条 access global data 的指令,
non-PIC 的形势是:ld r3, var1
PIC 的形式则是:ld r3,   var1-offset@GOT ,意思是从 GOT 表的 index 为 var1-offset 的地方处
指示的地址处装载一个值,即 var1-offset@GOT 处的4个 byte 其实就是 var1 的地址。这个地址只有在运行的时候才知道,是由 dynamic-loader(ld-linux.so) 填进去的。

再比如 jump label 指令
non-PIC 的形势是:jump printf ,意思是调用 printf。
PIC 的形式则是:jump   printf-offset@GOT ,
意思是跳到 GOT 表的 index 为 printf-offset 的地方处
指示的地址去执行,
这个地址处的代码摆放在 .plt section

每个外部函数对应一段这样的代码,其功能是呼叫dynamic-loader(ld-linux.so) 来查找函数的地址(本例中是 printf),然后将其地址写到 GOT 表的 index 为 printf-offset 的地方,

同时执行这个函数。这样,第2次呼叫 printf 的时候,就会直接跳到 printf 的地址,而不必再查找了。

GOT 是 data section, 是一个 table, 除专用的几个 entry,每个 entry 的内容可以再执行的时候修改;
PLT 是 text section, 是一段一段的 code,执行中不需要修改。
每个 target 实现 PIC 的机制不同,但大同小异。比如 MIPS 没有 .plt, 而是叫 .stub,功能和 .plt 一样。

可见,动态链接执行很复杂,比静态链接执行时间长;但是,极大的节省了 size,PIC 和动态链接技术是计算机发展史上非常重要的一个 里程碑。

gcc manul上面有说
-fpic        If the GOT size for the linked executable exceeds a machine-specific maximum size, you get an error message from the linker indicating that -fpic does not work; in that case, recompile with -fPIC instead. (These maximums are 8k on the SPARC and 32k on the m68k and RS/6000. The 386 has no such limit.)

-fPIC       If supported for the target machine, emit position-independent code, suitable for dynamic linking and avoiding any limit on the size of the global offset table. This option makes a difference on the m68k, PowerPC and SPARC. Position-independent code requires special support, and therefore works only on certain machines.

关键在于GOT全局偏移量表里面的跳转项大小。
intel处理器应该是统一4字节,没有问题。
powerpc上由于汇编码或者机器码的特殊要求,所以跳转项分为短、长两种。

-fpic为了节约内存,在GOT里面预留了“短”长度。
而-fPIC则采用了更大的跳转项。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/383412.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

双向链表的操作(创建,插入,删除)

双向链表的代码看似复杂,其实很简单,只要画图便可明白, 删除 假如要删除的结点叫pos. pos->prev->nextpos->next; pos->next->prevpos->prev; free(pos);

我使用过的Linux命令之hwclock - 查询和设置硬件时钟

我使用过的Linux命令之hwclock - 查询和设置硬件时钟 本文链接:http://codingstandards.iteye.com/blog/804830 (转载请注明出处) 用途说明 hwclock命令,与clock命令是同一个命令,主要用来查询和设置硬件时钟&#x…

二叉树的操作(前,中,后序遍历也叫深度优先遍历,非空结点的个数)递归实现

定义一个二叉树的结点 二叉树的前序遍历, 先访问根结点,再访问左,再访问右。 每次访问都要先看根结点是否为空,然后打印根结点,把此时根结点的左结点作为下一次递归的根结点,当把左结点遍历完后&#xff0…

makefile编译问题记录

1.-c选项和-C选项: -c(gcc选项):编译.c或汇编源文件,但是不作连接. 编译器输出对应于源文件的目标文件. 如:$(CC) -c ${CFLAGS} ${SRCS} -C(makefile选项):-C的是make…

二叉树的相关题(叶子结点个数,最大深度,找特殊值结点(值不重复),判断两个树是否相同,判断两个数是否为镜像树,是否为子树,)

叶子结点就是没有孩子结点,所以当当前根结点没有孩子结点的时候,就返回1,就是找到一个叶子结点,然后访问完每个不为空的结点就行,每次访问都是把当前结点的左/右结点作为新的结点,来判断。 求最大深度&…

为何线程有PID?

在linux下用 top -H -p <pid> 查询某个进程的线程 按理说&#xff0c;都是某个进程下的线程&#xff0c; 应该进程id PID一样啊&#xff0c;但实际却都不一样 实际是被PID的名字给弄混了&#xff0c;线程进程都会有自己的ID&#xff0c;这个ID就叫做PID&#xff0c;P…

关于树和二叉树的一些基本概念,基本名词解释。

二叉树的概念 概念 一棵二叉树是结点的一个有限集合&#xff0c;该集合或者为空&#xff0c;或者是由一个根节点加上两棵别称为左子树和右子树 的二叉树组成。 二叉树的特点&#xff1a; 每个结点最多有两棵子树&#xff0c;即二叉树不存在度大于2的结点。二叉树的子树有左右…

在VI中删除行尾的换行符

在vi中&#xff0c;如果要删除行尾的换行符&#xff0c;可以用如下方法 第一种情况&#xff1a;只删除单行 如有文件如下&#xff1a; [fanzfSWserver ~/tmp]$ cat names.tmp 101 Nate H. 102 John M. 104 Cassy T. 106 Mary L. 107 Isaac …

用c语言构建二叉树(重点)

结点创建 二叉树创建 我们以‘#’为NULL&#xff0c;我们要把输入进来的一个字符串转变为二叉树&#xff0c;所以我们要记住递归的每一步走到数组了哪个位置 所以我们要记住创建过程中用掉的前序个数&#xff0c;并返回&#xff0c;除此之外&#xff0c;还要加上当时的那个结点…

linux 同步IO: sync msync、fsync、fdatasync与 fflush

最近阅读leveldb源码&#xff0c;作为一个保证可靠性的kv数据库其数据与磁盘的交互可谓是极其关键&#xff0c;其中涉及到了不少内存和磁盘同步的操作和策略。为了加深理解&#xff0c;从网上整理了linux池畔同步IO相关的函数&#xff0c;这里做一个罗列和对比。大部分为copy&a…

二叉树的广度优先遍历(层序遍历)

先定义一个二叉树的结点 再创建二叉树&#xff0c;这里就不写了&#xff0c;之前的有创建二叉树的博客。 层序遍历 用到栈的思想&#xff0c; 1 先让根 节点进队列&#xff0c;2 然后读队顶元素&#xff0c;3 让他出队列4 打印它的值5 让队顶元素的左右子树进栈&#xff0…

用前序中序创建二叉树(用中序后序创建二叉树)

定义二叉树结点 比如就拿这个二叉树 前序中序创建 因为前序遍历的顺序是 根 &#xff0c; 左 &#xff0c;右。 中序的遍历是 左 根 右。 我们会很不好想&#xff0c;但我们可以用前序和中序把上面那个二叉树的遍历一边 前序遍历&#xff1a;ABDEHCFG中序遍历&#xff1a;D…

Epoll详解及源码分析

文章来源&#xff1a;http://blog.csdn.net/chen19870707/article/details/42525887 Author&#xff1a;Echo Chen&#xff08;陈斌&#xff09; Email&#xff1a;chenb19870707gmail.com Blog&#xff1a;Blog.csdn.net/chen19870707 Date&#xff1a;Jan.7th, 2015 1…

非递归实现二叉树(前序,中序,后序)c/c++实现

这里还是用到栈的思想&#xff0c;为了方便用了c的一些内容&#xff0c;把出栈&#xff0c;进栈&#xff0c;读栈顶元素用一个个函数封装起来了&#xff0c;前面做了一些处理来使用这些函数。 前序非递归 思想&#xff1a;一直走左边&#xff0c;依次进栈。等左边为空的时候&…

Linux 中统计一个进程的线程数

如果你想看到 Linux 中每个进程的线程数&#xff0c;有以下几种方法可以做到这一点。 方法一: /proc proc 伪文件系统&#xff0c;它驻留在 /proc 目录&#xff0c;这是最简单的方法来查看任何活动进程的线程数。 /proc 目录以可读文本文件形式输出&#xff0c;提供现有进程和系…

Linux_linux基础命令(增删查,权限,Linux下的重要目录,重要命令(. du, df, top, free, pstack, su, sudo).安装gcc/g++, gdb, vim )

r&#xff1a;表示可读w&#xff1a;表示可写x&#xff1a;表示可执行也可以用数字表示这一点我们会在修改文件权限说明。对于文件夹的rwx表示&#xff1a;r表示可读及可以查看文件夹内容可以ls查看w表示可写及可以向文件夹中传送内容如文件x表示可执行及可以向文件夹中可以cd进…

pthread_create会导致内存泄露

这几天一直在调试一个系统&#xff0c;系统的功能就是定时发送数据、接收数据然后解析收到的数据&#xff0c;转换成一定的格式存入数据库中。我为了并发操作&#xff0c;所以每接收到一个数据包&#xff0c;就调用pthread_create函数创建一个默认属性的线程进行处理。 系统…

Linux_linux常用工具之make/makefile详解

make/makefile make/makefile: 项目自动化构建工具 makefile:普通文本文件&#xff0c;记录了项目的构建流程规则。 make: 一个解释程序&#xff0c;到当前执行make命令的目录下寻找makefile文件&#xff0c;并且对makefile 中记录的项目构建规则进行解释执行。makefile: 编写…

Linux_linux常用工具(git,vim ,gcc ,gdb,权限)超详解

git :项目版本控制工具 项目克隆&#xff1a;git clone项目提交&#xff1a;git add&#xff08;本地仓库提交&#xff09; git commit -m “bak msg”&#xff08;-m 备注信息&#xff09;同步到服务器&#xff1a;git push origin master&#xff08;提交到主分支&…

T20调试札记

最近在调试T20的内存&#xff0c;使用的指令在此记录一下 1. pmap指令查看指定进程中的内存分布。该指令需要在busybox中开启 pmap -x 111 2.应用与so需要执行strip操作&#xff0c;可以减小存储空间的大小 mips-linux-gnu-strip libsysutils.so 3.nm指令和file指令可以查…