在Mac平臺下,可以使用nm命令來檢視一個檔案的符號表資訊。nm命令列工具是附帶在Xcode中的,因此在使用之前請事先安裝好Xcode。

nm命令的格式大致如下:

nm  [ -agnoprumxjlfPA [ s segname sectname ] ] [ - ] [ -t format ] [ [ -arch arch_flag ]... ] [ file ... ]

如果不帶任何可選引數的話,使用nm命令將會列出指定檔案中的所有符號,符號出現的次序預設按照字元排序。如果符號代表的是一個由Object C語言編寫的函式,那麼其名字將是+-[Class_name(category_name) method:name:]。

對於每一個符號,其格式是“符號值符號型別符號名”:

不過可以看到,nm命令也有許多的引數可選,這些引數的大致作用如下:

-a,顯示所有符號,包括那些專門用來除錯的符號。

-g,只顯示全域性符號,不顯示區域性符號。

-n,按照數字而不是預設的字元排序。

-p,不排序,按照符號在符號表中出現的次序顯示。

-r,符號按照反序顯示(預設就是按照符號名字字元排序的反序,如果帶上-p引數就是按照在符號表中出現次序的反序,如果帶上-n引數就是按照符號名數字排序的反序)。

-u,只顯示未定義的符號。

-U,不顯示未定義的符號,與-u的作用剛好相反。

-j,只顯示符號的名字,而不顯示符號對應的數值和型別。

-s segname sectname

只解析位於檔案中segname段裡sectname節內的符號。

-arch archtype

OS X和iOS系統都是支援所謂的肥(Fat)檔案的,也就是一個大檔案中包含了分別對不同平臺支援的檔案。

預設情況下,nm會將其中每一個平臺檔案中所包含的符號都列出來。如果你只想看某一個平臺檔案中的符號,可以用這個選項指定。

例如,對於包含了32位armv7指令集和64位armv8指令集的iOS可執行檔案來說,如果只想看錶示32位armv7指令集部分的符號,可以加上-arch arm引數;而如果想看錶示64位armv8指令集部分的符號,可以加上-arch arm64引數。

-x,將以16進位制的形式顯示符號表中所有符號每一項的值,格式如下:

-A,在每一行符號的前面加上檔名。

-P,以簡單格式顯示每一個符號,格式如下:

-t format,如果使用前面的-P引數,則符號的數值將使用16進製表示,但是可以再加上-t引數來指定用別的格式顯示符號的值。主要有下面幾種:

d:以10進位制顯示;

o:以8進位制顯示;

x:以16進位制顯示(預設)。

一般來說,在每個符號的前面,都有一個字母來表示這個符號的型別。對於每一個符號來說,其型別如果是小寫字母表示的的,則說明該符號是本地(Local)的或者說是內部(Internal)的,而如果是大寫字母表示的,則說明該符號是全域性的,也就是可供外部(External)訪問的。

一共主要有以下幾種型別:

1)U,未定義符號

表示這個符號沒有在本檔案中定義,需要解析別的檔案從而找出對應符號的定義。

例如,當前檔案呼叫另一個檔案中定義的函式或者全域性變數,這個被呼叫的函式或全域性變數在當前檔案中就是未定義的。(但是,在定義它的檔案中,如果是函式則對應的型別是T,而如果是全域性變數則其符號型別為C)。

2)A,絕對符號

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

3)T,定義在__TEXT段__text區(程式碼區)中的符號

表示該符號位於程式碼區中,其值表示該符號在整個檔案當中的所處的位置。

有點奇怪的是符號“__mh_execute_header”竟然型別也為T,算作在程式碼區定義的符號。

4)D,定義在__DATA段__data區中的符號

表明該符號位於初始化資料區中,其值表示該符號在整個檔案當中的所處的位置。

5)B,定義在__DATA段__bss區中的符號

表明該符號位於非初始化資料區中,其值表示該符號在bss段中的偏移。

6)C,所謂的普通(Common)符號,定義在__DATA段__common區中的符號

普通符號是定義在一個未初始化資料段內的符號。該符號沒有包含於一個普通的區中,只有在連結過程中才進行分配,符號的值表示該符號需要的位元組數。例如在一個C檔案中,定義int test,並且該符號在別的地方會被引用,則該符號型別即為C,否則其型別為B。

7)I,間接符號

說明這個符號是僅僅是對另一個符號的間接引用。

8)S,其它符號

定義在除前所述其它地方的符號,例如出現在__TEXT段__const區中的符號。

.