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.pswp.cn/news/383412.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/383412.shtml
英文地址,請注明出處:http://en.pswp.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指令可以查…