的visibility("hidden")
屬性不抑制一個符號從 一個目標文件,並不能防止通過nm
被提取的符號。它只是 指示動態鏈接器該符號不能從外部調用 包含它的共享庫。
考慮一個源文件file.c
包含您的功能。例如:
int f_b1(){
return 21 ;
}
int f_b3(){
return f_b1() ;
}
編譯文件:
gcc -c -o file.o file.c
運行nm file.o
列出的符號。輸出:
0000000000000000 T f_b1
000000000000000b T f_b3
現在運行objdump -t file.o
約符號更全面的信息。輸出:
file.o: file format elf64-x86-64
SYMBOL TABLE:
0000000000000000 l df *ABS* 0000000000000000 file.c
0000000000000000 l d .text 0000000000000000 .text
0000000000000000 l d .data 0000000000000000 .data
0000000000000000 l d .bss 0000000000000000 .bss
0000000000000000 l d .note.GNU-stack 0000000000000000 .note.GNU-stack
0000000000000000 l d .eh_frame 0000000000000000 .eh_frame
0000000000000000 l d .comment 0000000000000000 .comment
0000000000000000 g F .text 000000000000000b f_b1
000000000000000b g F .text 000000000000000b f_b3
這裏我們看到f_b1
和f_b3
是全球性的(G)功能(F)在.text
部分。
現在修改該文件是這樣的:
__attribute__((visibility ("hidden"))) int f_b1(void){
return 21 ;
}
__attribute__((visibility ("hidden"))) int f_b3(void){
return f_b1() ;
}
運行objdump
再次:
file.o: file format elf64-x86-64
SYMBOL TABLE:
0000000000000000 l df *ABS* 0000000000000000 file.c
0000000000000000 l d .text 0000000000000000 .text
0000000000000000 l d .data 0000000000000000 .data
0000000000000000 l d .bss 0000000000000000 .bss
0000000000000000 l d .note.GNU-stack 0000000000000000 .note.GNU-stack
0000000000000000 l d .eh_frame 0000000000000000 .eh_frame
0000000000000000 l d .comment 0000000000000000 .comment
0000000000000000 g F .text 000000000000000b .hidden f_b1
000000000000000b g F .text 000000000000000b .hidden f_b3
輸出是一樣的,不同之處在於符號f_b1
和f_b3
現在被標記 .hidden
。它們仍然具有外部(全局)鏈接,並且可以從包含它們的庫中的其他模塊靜態調用,例如 示例,但可能不會從該庫外部以dymamically方式調用 。
所以,如果你想從動態鏈接隱瞞f_b1
和f_b3
在共享 庫,你可以使用visibility ("hidden")
如圖所示。
如果你想在一個靜態 庫隱瞞f_b1
和f_b3
從靜態聯動,您不能使用visibility
屬性做到這一點的。
在靜態庫的情況下,你可以「隱藏」一個符號,只給它 內部而不是外部鏈接。要做到這一點的方法是在 標準static
關鍵字前添加。但內部聯動意味着符號爲 ,只能在其自己的彙編單位內可見:不能從 其他模塊引用。它根本不可用於鏈接器。
修改file.c
再次,像這樣:
static int f_b1(void){
return 21 ;
}
static int f_b3(void){
return f_b1() ;
}
,並再次運行objump
:
file.o: file format elf64-x86-64
SYMBOL TABLE:
0000000000000000 l df *ABS* 0000000000000000 file.c
0000000000000000 l d .text 0000000000000000 .text
0000000000000000 l d .data 0000000000000000 .data
0000000000000000 l d .bss 0000000000000000 .bss
0000000000000000 l F .text 000000000000000b f_b1
000000000000000b l F .text 000000000000000b f_b3
0000000000000000 l d .note.GNU-stack 0000000000000000 .note.GNU-stack
0000000000000000 l d .eh_frame 0000000000000000 .eh_frame
0000000000000000 l d .comment 0000000000000000 .comment
你看到f_b1
和f_b3
仍報告爲.text
部分功能,但現在分類當地(l),不是全球。這是內部聯繫。 運行nm file.o
和輸出是:
0000000000000000 t f_b1
000000000000000b t f_b3
這是相同的原始文件,但不是「T」標誌 我們現在有「T」標誌。兩個標誌都表示符號位於.text
部分, ,但'T'表示它是全局的,'t'表示它是本地的。
顯然,你想要nm
報告此文件是沒有符號的所有。 您現在應該明白nm file.o
會報告一個符號,如果它存在於 file.o
中,但它的存在與靜態或動態鏈接是否可見 無關。
爲了消失功能符號,編譯file.c
再次 (仍與static
關鍵字),這次與優化啓用:現在
gcc -c -O1 -o file.o file.c
,objdump
報道:
file.o: file format elf64-x86-64
SYMBOL TABLE:
0000000000000000 l df *ABS* 0000000000000000 file.c
0000000000000000 l d .text 0000000000000000 .text
0000000000000000 l d .data 0000000000000000 .data
0000000000000000 l d .bss 0000000000000000 .bss
0000000000000000 l d .note.GNU-stack 0000000000000000 .note.GNU-stack
0000000000000000 l d .comment 0000000000000000 .comment
f_b1
和f_b3
不見了,nm file.o
什麼也沒有報告。爲什麼? 因爲static
告訴編譯器,這些符號只能從它正在編譯的文件中調用 ,並且優化決定了 不需要引用它們;所以編譯器從 目標代碼中消除它們。但是,如果它們不是鏈接器不可見的,而沒有優化,那麼我們不能優化它們。
底線:nm
是否可以提取符號並不重要。如果 符號是本地/內部符號,則無法靜態或動態鏈接。 如果符號被標記爲.hidden
那麼它不能被動態地鏈接。您 可以使用visibility("hidden")
來標記符號.hidden
。使用標準 static
關鍵字使符號成爲本地/內部。
這是很好的解釋。 –
有沒有辦法隱藏對象文件名呢?我的'nm'命令輸出是這樣的。 ''b.o: 0000000000000000 T f_b2 0000000000000010 T f_b3 c.o: '''我想隱藏'b.o和c.o'的名字。謝謝.. –
是的:運行'strip -s file.o'。見'男子地帶'。請注意,當您刪除所有符號時,您無法調試目標文件。 –