天天看點

linux+nm+内容詳解,【Linux】nm指令中符号類型詳解

DATE: 2018.11.13

nm指令介紹的很多,但大多不介紹其函數符号标志的含義。

最近在調試動态庫時常用到,其中用的最多的用法:

nm -A * |grep “aaa” | c++filt  // -A 為了顯示檔案, c++filt轉換為可讀風格,好像有個參數也能實作類似功能

其他内容整理如下(原作者未知):

nm用于列出目标檔案的符号清單,如果沒有指定目标檔案,則預設為“a.out”。nm的格式如下:

nm [‘-a’|‘--debug-syms’] [‘-g’|‘--extern-only’]

[‘-B’] [‘-C’|‘--demangle’[=style]] [‘-D’|‘--dynamic’]

[‘-S’|‘--print-size’] [‘-s’|‘--print-armap’]

[‘-A’|‘-o’|‘--print-file-name’][‘--special-syms’]

[‘-n’|‘-v’|‘--numeric-sort’] [‘-p’|‘--no-sort’]

[‘-r’|‘--reverse-sort’] [‘--size-sort’] [‘-u’|‘--undefined-only’]

[‘-t’ radix|‘--radix=’radix] [‘-P’|‘--portability’]

[‘--target=’bfdname] [‘-f’format|‘--format=’format]

[‘--defined-only’] [‘-l’|‘--line-numbers’] [‘--no-demangle’]

[‘-V’|‘--version’] [‘-X 32_64’] [‘--help’] [objfile...]

對于每一個符号,nm列出其值(the symbol value),類型(the symbol type)和其名字(the symbol name)。

如下例:

00000024 T cleanup_before_linux

00000018 T cpu_init

00000060 T dcache_disable

00000054 T dcache_enable

0000006c T dcache_status

00000000 T do_reset

0000003c T icache_disable

00000030 T icache_enable

00000048 T icache_status

上面的顯示是使用nm cpu.o的輸出,對于cleanup_before_linux這個符号來說,00000024是以16進制顯示的其值,T為其類型,而cleanup_before_linux是其名字。可以看出,上面顯示的cleanup_before_linux這個symbol的值實際上是該函數在text section中的偏移。但是,每個符号的值的具體含義依其類型而異。當然,對于每個符号的值,其類型、其值以及它們所屬的section是密切相關的。

下面說明符号類型:對于每一個符号來說,其類型如果是小寫的,則表明該符号是local的;大寫則表明該符号是global(external)的。

符号

類型

說明

A

該符号的值是絕對的,在以後的連結過程中,不允許進行改變。這樣的符号值,常常出現在中斷向量表中,例如用符号來表示各個中斷向量函數在中斷向量表中的位置。

B

該符号的值出現在非初始化資料段(bss)中。例如,在一個檔案中定義全局static int test。則該符号test的類型為b,位于bss section中。其值表示該符号在bss段中的偏移。一般而言,bss段配置設定于RAM中

C

該符号為common。common symbol是未初始話資料段。該符号沒有包含于一個普通section中。隻有在連結過程中才進行配置設定。符号的值表示該符号需要的位元組數。例如在一個c檔案中,定義int test,并且該符号在别的地方會被引用,則該符号類型即為C。否則其類型為B。

D

該符号位于初始話資料段中。一般來說,配置設定到data section中。例如定義全局int baud_table[5] = {9600, 19200, 38400, 57600, 115200},則會配置設定于初始化資料段中。

G

該符号也位于初始化資料段中。主要用于small object提高通路small data object的一種方式。

I

該符号是對另一個符号的間接引用。

N

該符号是一個debugging符号。

R

該符号位于隻讀資料區。例如定義全局const int test[] = {123, 123};則test就是一個隻讀資料區的符号。注意在cygwin下如果使用gcc直接編譯成MZ格式時,源檔案中的test對應_test,并且其符号類型為D,即初始化資料段中。但是如果使用m6812-elf-gcc這樣的交叉編譯工具,源檔案中的test對應目标檔案的test,即沒有添加下劃線,并且其符号類型為R。一般而言,位于rodata section。值得注意的是,如果在一個函數中定義const char *test = “abc”, const char test_int = 3。使用nm都不會得到符号資訊,但是字元串“abc”配置設定于隻讀存儲器中,test在rodata section中,大小為4。

S

符号位于非初始化資料區,用于small object。

T

該符号位于代碼區text section。

U

該符号在目前檔案中是未定義的,即該符号的定義在别的檔案中。例如,目前檔案調用另一個檔案中定義的函數,在這個被調用的函數在目前就是未定義的;但是在定義它的檔案中類型是T。但是對于全局變量來說,在定義它的檔案中,其符号類型為C,在使用它的檔案中,其類型為U。

V

該符号是一個weak object。

W

The symbol is a weak symbol that has not been specifically tagged as a weak object symbol.

-

該符号是a.out格式檔案中的stabs symbol。

?

該符号類型沒有定義