轉自:https://www.jianshu.com/p/d9489aba95a9
一、前言
本文是主要用於講述 ELF查看工具 ,包括 readelf 、nm 等工具。除了講述他們的使用方法和功效之外,也有可能會記錄在程序文件分析中的經驗心得,不定期更新。
二、正文
可用於查看分析 ELF文件 的工具如下所示:
工具 | 功能說明 |
---|---|
strings | 輸出 ELF文件 中的所有字符串 |
strip | 刪除 ELF文件 中一些無用的信息 |
nm | 顯示目標文件中的所有符號 |
size | 顯示目標文件中的 section 大小及目標文件大小 |
readelf | 顯示 ELF 文件中的內容,主要的 ELF分析工具 |
objdump | 顯示目標文件的匯編信息,主要用於反匯編 |
ar | 將目標文件鏈接為靜態庫 |
addr2line | 將地址轉換為文件、行號 |
2.1 nm
2.1.1 使用格式
nm 的使用格式為 nm [-options] [files],當沒有輸入文件時,默認使用當前目錄下的 a.out 文件作為輸入。
我們說一下幾個常用的選項;
nm的用法很簡單,以下幾個關鍵字比較常用:
- -A:列出符號名的時候並顯示來自於文件來源,一般用於查看 多個文件(比如庫文件) 的符號時比較有用
- -a:列出所有符號,該選線會將 調試符號 也列出來。默認狀態下 不顯示 調試符號。
- -l:列出符號在源代碼中對應的行號,對於 未定義符號 顯示為空
- -n:根據符號的地址來排序,默認按符號名的字母順序進行排序的
- -u:只列出 未定義符號
- --defined-only:只列出 已定義符號
- -f:指定輸出格式,可以使用 nm -f sysv 查看變量所在的節區
- -r:按順序打印出符號
2.1.2 輸出
下面是一個 nm 查看一個測試程序的符號,我們簡單看一下輸出:

其輸出一共有 3 列,分別如下:
- 第一列:符號 起始地址
- 第二列:符號 類型
- 第三列:符號 名稱
2.1.3 符號類型
我們重點看一下符號類型,如下表所示:
符號類型 | 含義 |
---|---|
A | 該符號的值是絕對的,在以后的鏈接過程中,不允許進行改變。該符號類型常常出現在中斷向量表中,比如用符號來表示各個中斷向量函數在中斷向量表中的位置 |
B | 該符號出現在 BSS段 中,同時也位於 bss section。其值表示該符號在 BSS段 中的 偏移。一般而言,BSS段 分配於RAM中 |
D | 該符號位於 data段 中,同時也位於 *data section |
N | 該符號是一個 調試符號 |
R | 該符號位於 只讀數據區,比如由 const 修飾的變量或者字符串常量等 |
S | 該符號位於 非初始化數據區,一般也位於 rodata section |
T | 該符號位於 代碼段 的 text section |
U | 該符號在當前文件中是未定義的,即該符號的定義在別的文件 |
2.2 size
使用方法為: size file_name ,如圖所示

其輸出含義如下:
- text:表示文件中指令的大小
- data:表示文件有初值的全局變量和靜態變量的大小
- bss:表示文件中未賦初值或初值為 0 的全局變量和靜態變量的大小
- dec:text + data + bss
- hex:dec 的 16 進制表示
2.3 readelf
readelf 的 使用方法為:readelf [-options] [files]。下面列舉幾個我們常用的選項:
- -h:查看 ELF文件頭,其輸出含義如下:
輸出字段 | 含義 |
---|---|
Magic | 該行給出了ELF文件的一些標識信息 |
Entry point address | 程序入口的 虛擬地址。如果目標文件沒有程序入口,可以為 0。在程序加載完成后,loader 會將程序指針轉移到該地址。 |
Start of program headers | 表明 程序頭部表(program header) 在 ELF文件 中的位置。 |
Start of section headers | 表明 節區頭部表(section header) 在 ELF文件 中的位置。 |
Size of this heade | 表明 ELF文件頭 的大小。 |
Size of program headers | 表明 程序頭部表 中每行的大小為 32 個字節。 |
Number of program headers | 表明在 程序頭部表 的行數,也就意味着程序的段數。 |
Size of section headers | 表明 節區頭部表 每行的大小 |
Number of section headers | 表明在 節區頭部表 中的行數,也就意味着程序中節數 |
-
-S:查看 節(section) 信息,其輸出字段為:
- Type:節區類型,其含義如下:
段類型 含義 NULL 此值標志節區頭部是非活動的,沒有對應的節區。此節區頭部中的其他 成員取值無意義 PROGBITS 此節區包含程序定義的信息,其格式和含義都由程序來解釋,代碼節區 和 數據節區 都是這種類型 SYMTAB 此節區包含 符號表。符號表中每一個符號是值都是一個 數字,該數字是對應符號的符號名在 字符串表 中的下標 STRTAB 此節區包含 字符串表,目標文件可能包含多個字符串表節區 RELA 此節區包含 重定位表項。目標文件可能擁有多個重定位節區 HASH 此節區包含 符號哈希表。所有參與動態鏈接的目標都必須包含一個 符號哈希表 DYNAMIC 此節區包含 動態鏈接的信息 NOTE 此節區包含以某種方式來標記文件的信息 NOBITS 這種類型的節區不占用文件中的空間,其他方面和 SHT_PROGBITS 相似,如 bss段 DYNSYM 動態鏈接符號表,它可能包含很多對動態鏈接而言不必要的符號 INIT_ARRAY 在 main函數 之前運行的函數指針數組 FINI_ARRAY 在退出 main函數 之后,運行的函數指針數組 - Addr:如果節區將出現在進程的內存映像中,此成員給出節區的第一個字節應處的位置。 否則此字段為 0
- Off:表示該節內容在距離 文件起始 的偏移地址。
- Size:表示該節在文件中的 大小
- ES:某些節區中包含 固定大小 的項目,如 符號表。對於這類節區,此成員給出每個表項的 長度字節數 。 如果節區中並不包含固定長度表項的表格,此成員取值為 0
- Flag: 表示該節的內存分配屬性,A(分配內存) , X(可執行) , W(可寫)
- Lk: 此成員給出節區頭部表 索引鏈接
- AL: 某些節區帶有 地址對齊約束
-
-l:查看 段(segment) 信息及 節與段之間的映射關系,其輸出字段為:
- Type:段類型,其含義如下:
段類型 含義 PHDR 此段給出了程序頭部表自身的 大小 和 位置,同時包括 在文件 和 在內存 中的信息 INTERP 該段給出一個 NULL結尾的字符串。該字符串將被當作解釋器調用。對於 ELF文件 來講,該段指定了啟動進程的 Loader LOAD 該段是一個可加載的段,段的大小由 FileSiz 和 MemSiz 描述。文件中的字節被映射到內存段開始處 DYNAMIC 該段給出動態鏈接信息 NOTE 此段給出附加信息的位置和大小 - Offset:該段在距離文件開頭的 偏移地址
- VirtAddr:此成員給出段的第一個字節將被放到內存中的 虛擬地址
- PhysAddr:此成員僅用於與物理地址相關的系統中
- FileSiz:此成員給出段在 文件映像 中所占的 字節數
- MemSiz:此成員給出段在 內存映像 中占用的 字節數
- Flg:該段的屬性,R(可讀),E(可執行),W(可寫)
- Align:表示該段的要求 字節對齊 屬性
注意,MemSize 可能與 FileSize 不等,主要是因為 .bss段 只占據 內存空間,不占據 文件空間。
- -r:查看 重定位節區信息
- -s:查看 符號表
- -d:讀取 .dynamic段,該段包含 可執行文件所依賴的庫
2.3 addr2line
addr2line的 使用方法為:addr2line[-options] [files]。下面列舉幾個我們常用的選項:
- -e:指定 可執行文件,在 執行文件 需要在編譯時加入 -g 選項來加入調試信息
2.4 objdump
- -h:打印 ELF文件 中所有 section頭,輸出字段如下:
- Idx Name:section 名
- Size:大小
- File off:在文件中的偏移
- -r:查看目標文件的 靜態 重定位表:
- OFFSET:重定位入口偏移
- TYPE:重定位入口類型
- VALUE:重定位入口的符號
- -R:查看共享對象的 動態 重定位表:
2.4 objcopy
objcopy 可以將 非ELF文件 編譯為 section,使其能夠直接鏈接到 可執行文件 中。
其使用方法為 objcopy [-optoins] input output
常用選項如下:
- -I:輸入文件格式
- O:輸出文件格式
- -B:設置輸出文件的體系架構,比如i386
作者:wipping的技術小棧
鏈接:https://www.jianshu.com/p/d9489aba95a9
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。