gcc或g++的編譯選項 -shared -fPIC 與 -g -rdynamic 部分轉載
動態庫
Linux 下動態連結庫(shared object file,共享物件檔案)的檔案字尾為.so
,它是一種特殊的目標檔案(object file),可以在程式執行時被載入(連結)進來。使用動態連結庫的優點是:程式的可執行檔案更小,便於程式的模組化以及更新,同時,有效記憶體的使用效率更高。
建立一個動態連結庫,可使用 GCC 的-shared
選項。輸入檔案可以是原始檔、彙編檔案或者目標檔案。另外還得結合-fPIC
選項。-fPIC 選項作用於編譯階段,告訴編譯器產生與位置無關程式碼(Position-Independent Code);這樣一來,產生的程式碼中就沒有絕對地址了,全部使用相對地址,所以程式碼可以被載入器載入到記憶體的任意位置,都可以正確的執行。這正是共享庫所要求的,共享庫被載入時,在記憶體的位置不是固定的。
gcc選項-g與-rdynamic的異同
-g ,是一個除錯選項,是一個編譯選項,即在原始碼編譯的過程中起作用,讓gcc把更多除錯資訊(也就包括符號資訊)收集起來並將存放到最終的目標檔案內。
-rdynamic 卻是一個 連線選項 ,它將指示聯結器把所有符號(而不僅僅只是程式已使用到的外部符號)都新增到動態符號表(即.dynsym表)裡,以便那些通過 dlopen() 或 backtrace() (這一系列函式使用.dynsym表內符號)這樣的函式使用。
新增-rdynamic選項後,.dynsym表就包含了所有的符號,不僅是已使用到的外部動態符號,還包括本程式內定義的符號,比如bar、foo、baz等。
[root@www c]# gcc -O0 -rdynamic -o t.rd t.c
[root@www c]# readelf -s t.rd
Symbol table '.dynsym' contains 20 entries:
Symbol table '.symtab' contains 67 entries:
[root@www c]# strip t.rd [root@www c]# readelf -s t.rd
簡單總結一下-g選項與-rdynamic選項的差別:
1,-g選項新新增的是除錯資訊(一系列.debug_xxx段),被相關除錯工具,比如gdb使用,可以被strip掉。
2,-rdynamic選項新新增的是動態連線符號資訊,用於動態連線功能,比如dlopen()系列函式、backtrace()系列函式使用,不能被strip掉,即強制strip將導致程式無法執行:
[root@www c]# ./t.rd test[root@www c]# strip -R .dynsym t.rd [root@www c]# ./t.rd
3 .symtab表在程式載入時會被載入器 丟棄 ,gdb等除錯工具由於可以直接訪問到磁碟上的二進位制程式檔案:
[root@www c]# gdb t.g -q
Reading symbols from /home/work/dladdr/c/t.g...done.
因此可以使用所有的除錯資訊,這包括.symtab表;
而backtrace()系列函式作為程式執行的邏輯功能,無法去讀取磁碟上的二進位制程式檔案,因此只能使用.dynsym表。
其它幾個工具可以動態指定檢視,比如nm、objdump:
[root@www c]# nm t.rd nm: t.rd: no symbols [root@www c]# nm -D t.rd 0000000000400848 R _IO_stdin_used w _Jv_RegisterC
[root@www c]# objdump -T t.rd t.rd: file format elf64-x86-64 DYNAMIC SYMBOL TABLE: 0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 printf
4,-rdynamic選項不產生任何除錯資訊,因此在一般情況下,新增的附加資訊比-g選項要少得多。除非是完全的靜態連線,否則即便是沒有加-rdynamic選項,程式使用到的外部動態符號,比如前面示例裡的printf,也會被自動加入到.dynsym表。
makefile編寫
[fdj@hs-192-168-33-206 tst]$ cat makefile
INCDIR = -I .
CC = g++
CFLAGS = -c -g
LFLAGS = -rdynamic
#so LFLAGS = -shared -fPIC
TARGET = demo
OBJS=testDst.o US_Time_Until.o
all: cleanobj $(TARGET)
testDst.o:testDst.cpp
$(CC) $(CFLAGS) testDst.cpp $(INCDIR)
US_Time_Until.o:US_Time_Until.cpp
$(CC) $(CFLAGS) US_Time_Until.cpp $(INCDIR)
$(TARGET):$(OBJS)
$(CC) $(LFLAGS) -o $(TARGET) $(OBJS)
cleanobj:
rm -f *.o
clean:cleanobj
clean all
相關文章
- gcc 和 g++ 的聯絡和區別,使用 gcc 編譯 c++GC編譯C++
- gcc g++支援C++11 標準編譯及其區別GCC++編譯
- gcc 和 g++ 的區別GC
- G++編譯連結的那些事!G++的特殊使用方法[常用]編譯
- cmake中新增 -g編譯選項編譯
- 【知識點】 gcc和g++的聯絡和區別GC
- ubuntu 20.04安裝GCC G++ 6.2,支援c++ 14UbuntuGCC++
- __cxa_pure_virtual報錯(g++編譯虛擬函式時)編譯函式
- Linux系統 g++ 連結 libopencv_world.a 靜態庫編譯程式LinuxOpenCV編譯
- Linux中gcc編譯工具LinuxGC編譯
- GCC編譯器背後的故事GC編譯
- 很有用的 GCC 命令列選項GC命令列
- vc 編譯連線選項編譯
- gcc g++ 新增標頭檔案路徑和庫檔案路徑的方法GC
- 命令列gcc -v和g++ -v輸出版本不一致命令列GC
- 記錄一次gcc的編譯GC編譯
- mingw編譯jsoncpp 轉載編譯JSON
- typescript 3.2 新編譯選項strictBindCallApplyTypeScript編譯APP
- -debug(C# 編譯器選項)C#編譯
- 探索gcc編譯最佳化細節 編譯器最佳化gcc -o3GC編譯
- GCC編譯過程(預處理->編譯->彙編->連結)GC編譯
- 記一次編譯GCC的經歷編譯GC
- GCC編譯和連結過程GC編譯
- C# 編譯器選項(Visual Studio配置)C#編譯
- gcc編譯階段列印巨集定義的內容GC編譯
- 32位支援:使用 GCC 交叉編譯GC編譯
- linux 改變GCC編譯器的位元組對齊方式LinuxGC編譯
- CentOS7編譯和安裝GCC7.5CentOS編譯GC
- Notepad++編譯和執行C語言 (GCC)編譯C語言GC
- Mingw GCC 編譯OpenCV報錯: Project files may be invalidGC編譯OpenCVProject
- 深入剖析Vue原始碼 - 例項掛載,編譯流程Vue原始碼編譯
- 原創 【CentOS Linux 7】實驗4【gcc編譯器】CentOSLinuxGC編譯
- Java編譯與反編譯Java編譯
- 編寫ORACLE效能報告的九大注意事項(轉載)Oracle
- Ubuntu 19.10將使用GCC 9作為預設編譯器UbuntuGC編譯
- CentOS 8上安裝GCC實現開發編譯功能CentOSGC編譯
- 在滴滴雲 DC2 編譯安裝最新 GCC 版本編譯GC
- 【踩坑記】Ubuntu 20.04.6 LTS下編譯安裝gcc 4.4.0Ubuntu編譯GC