編譯nm
在Linux環境下,當你遇到鏈接庫問題時,深入理解庫的編譯內容變得尤為重要。這時,nm指令就成為一個有效的工具,幫助我們揭示靜態庫和動態庫內的編譯細節。
首先,對於靜態庫,我們可以使用命令
nm -g libname.a
執行後,如圖所示,它會列出靜態庫中的全局變數和函數介面,讓你清晰地看到庫的內部結構。
而對於動態庫,其查看方式為
nm -g libname.so
同樣會顯示出動態庫的編譯內容,包括函數和符號,這對於定位和修復與庫相關的bug時非常有用。
因此,在鏈接第三方庫或處理bug時,記得利用nm指令來記錄和分析庫的編譯內容,它能提供寶貴的線索和信息。
2. linux系統c語言的nm是什麼意思
不是C語言吧?是系統命令。用來列舉object文件(比如編譯出的a.out)的symbols.
用法是:
nm [-a|--debug-syms] [-g|--extern-only]
[-B] [-C|--demangle[=style]] [-D|--dynamic]
[-S|--print-size] [-s|--print-armap]
[-A|-o|--print-file-name]
[-n|-v|--numeric-sort] [-p|--no-sort]
[-r|--reverse-sort] [--size-sort] [-u|--undefined-only]
[-t radix|--radix=radix] [-P|--portability]
[--target=bfdname] [-fformat|--format=format]
[--defined-only] [-l|--line-numbers] [--no-demangle]
[-V|--version] [-X 32_64] [--help] [objfile...]
具體而言,nm用來列出目標文件的符號清單。
如果沒有為nm命令指出目標文件,則nm假定目標文件是a.out。下面列出該命令的任選項,大部分支持「-」開頭的短格式和「-「開頭的長格式。
-A、-o或--print-file-name:在找到的各個符號的名字前加上文件名,而不是在此文件的所有符號前只出現文件名一次。
例如nmlibtest.a的輸出如下:
CPThread.o:
00000068TMain__8CPThreadPv
00000038TStart__8CPThread
00000014T_._8CPThread
00000000T__8CPThread
00000000?__FRAME_BEGIN__
…………………………………
則nm-A的輸出如下:
libtest.a:CPThread.o:00000068TMain__8CPThreadPv
libtest.a:CPThread.o:00000038TStart__8CPThread
libtest.a:CPThread.o:00000014T_._8CPThread
libtest.a:CPThread.o:00000000T__8CPThread
libtest.a:CPThread.o:00000000?__FRAME_BEGIN__
…………………………………………………………..
-a或--debug-syms:顯示調試符號。
-B:等同於--format=bsd,用來兼容MIPS的nm。
-C或--demangle:將低級符號名解碼(demangle)成用戶級名字。這樣可以使得C 函數名具有可讀性。
-D或--dynamic:顯示動態符號。該任選項僅對於動態目標(例如特定類型的共享庫)有意義。
-fformat:使用format格式輸出。format可以選取bsd、sysv或posix,該選項在GNU的nm中有用。默認為bsd。
-g或--extern-only:僅顯示外部符號。
-n、-v或--numeric-sort:按符號對應地址的順序排序,而非按符號名的字元順序。
-p或--no-sort:按目標文件中遇到的符號順序顯示,不排序。
-P或--portability:使用POSIX.2標准輸出格式代替默認的輸出格式。等同於使用任選項-fposix。
-s或--print-armap:當列出庫中成員的符號時,包含索引。索引的內容包含:哪些模塊包含哪些名字的映射。
-r或--reverse-sort:反轉排序的順序(例如,升序變為降序)。
--size-sort:按大小排列符號順序。該大小是按照一個符號的值與它下一個符號的值進行計算的。
-tradix或--radix=radix:使用radix進制顯示符號值。radix只能為「d」表示十進制、「o」表示八進制或「x」表示十六進制。
--target=bfdname:指定一個目標代碼的格式,而非使用系統的默認格式。
-u或--undefined-only:僅顯示沒有定義的符號(那些外部符號)。
-l或--line-numbers:對每個符號,使用調試信息來試圖找到文件名和行號。對於已定義的符號,查找符號地址的行號。對於未定義符號,查找指向符號重定位入口的行號。如果可以找到行號信息,顯示在符號信息之後。
-V或--version:顯示nm的版本號。
--help:顯示nm的任選項。
ar cs libmy.a//創建一個庫
ar rs libmy.a 1.o//增加一個模塊
ar t libmy.a//顯示庫里的模塊
ar d libmy.a 1.o//刪除一個模塊
3. 如何判斷一段程序是由C 編譯程序還是由C++編譯程序編譯的
以下是在論壇中看到的兩種解釋: (1)如果是要你的代碼在編譯時發現編譯器類型,就判斷_cplusplus或_STDC_宏,通常許多編譯器還有其他編譯標志宏, #ifdef __cplusplus cout<<"c++";#else cout<<"c";#endif如果要判斷已經編譯的代碼的編譯類型,就用nm查一下輸出函數符號是否和函數名相同。(相同為c,不同為c++。詳解見下面)(2)簡單是說,由於c語言是沒有重載函數的概念的,所以c編譯器編譯的程序里,所有函數只有函數名對應的入口。而由於c++語言有重載函數 的概念,如果只有函數名對應的入口,則會出現混淆,所以c++編譯器編譯的程序,應該是函數名+參數類型列表對應到入口。 注意,因為mian函數是整個程序的入口,所以mian是不能有重載的,所以,如果一個程序只有main函數,是無法確認是c還是c++編譯器編譯的可以通過nm來查看函數名入口如一個函數int foo(int i, float j) c編譯的程序通過nm查看 foo 0x567xxxxxx (地址) c++編譯程序,通過nm查看 foo(int, float) 0x567xxxxxx 另外,如果要在c++編譯器里使用通過c編譯的目標文件,必須通知c++編譯器,我使用的函數是c風格的,不需要列出參數列表的,這樣c++編譯才能正確的連接