gcc或g++的編譯選項 -shared -fPIC 與 -g -rdynamic 部分轉載

字正腔圓發表於2020-09-30

動態庫

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

相關文章