readelf 用法與範例

本篇 ShengYu 介紹 Linux readelf 指令用法,並附上 Linux readelf 範例。

Linux readelf 指令用來顯示 elf 檔案格式裡的資訊,常用於顯示 symbols、headers、sections、segments,這在分析編譯器如何從原始碼生成二進制檔案時非常實用。

Linux readelf 有一些跟 objdump 指令相似的功能,但 readelf 能顯示更多細節。

readelf 顯示符號表 symbols

這邊示範 readelf 顯示符號表 symbols,

1
readelf -Ws <library>

-s
–syms
–symbols
顯示符號表(如果有的話)。
Displays the entries in symbol table section of the file, if it has one.

-W
–wide 寬行輸出。
Don’t break output lines to fit into 80 columns.

readelf 搭配 c++filt 解析 c++ 符號

用 c++filt 把 symbol name 轉換 demangle 成看得懂的 symbol name.

1
readelf -Ws <library> | c++filt

例如用 readelf 查看 libzmq.so 可以發現像 _ZNSt7__cxx1119basic_ostringstreamIcSt11char_traitsIcESaIcEED1Ev 這一串實在很難短時間內看出是什麼,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ readelf -Ws `gcc -print-file-name=libzmq.so.5`
# 或者 readelf -Ws /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libzmq.so.5

Symbol table '.dynsym' contains 198 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 000000000000bb90 0 SECTION LOCAL DEFAULT 9
2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __errno_location@GLIBC_2.2.5 (2)
3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND bind@GLIBC_2.2.5 (3)
4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZSt29_Rb_tree_insert_and_rebalancebPSt18_Rb_tree_node_baseS0_RS_@GLIBCXX_3.4 (4)
5: 0000000000000000 0 OBJECT GLOBAL DEFAULT UND _ZTVSt9basic_iosIcSt11char_traitsIcEE@GLIBCXX_3.4 (4)
6: 0000000000000000 0 FUNC GLOBAL DEFAULT UND randombytes_close
7: 0000000000000000 0 FUNC GLOBAL DEFAULT UND if_nametoindex@GLIBC_2.2.5 (3)
8: 0000000000000000 0 FUNC GLOBAL DEFAULT UND isxdigit@GLIBC_2.2.5 (3)
9: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZNSt7__cxx1119basic_ostringstreamIcSt11char_traitsIcESaIcEED1Ev@GLIBCXX_3.4.21 (5)
#...略

這時可以用 c++filt 工具轉換成看得懂的 symbol name,

1
2
$ echo _ZNSt7__cxx1119basic_ostringstreamIcSt11char_traitsIcESaIcEED1Ev | c++filt
std::__cxx11::basic_ostringstream<char, std::char_traits<char>, std::allocator<char> >::~basic_ostringstream()

下次用 readelf 查看 libzmq.so 時後面接續 c++filt,這樣就輕鬆看了~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ readelf -Ws `gcc -print-file-name=libzmq.so.5` | c++filt

Symbol table '.dynsym' contains 198 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 000000000000bb90 0 SECTION LOCAL DEFAULT 9
2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __errno_location@GLIBC_2.2.5 (2)
3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND bind@GLIBC_2.2.5 (3)
4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND std::_Rb_tree_insert_and_rebalance(bool, std::_Rb_tree_node_base*, std::_Rb_tree_node_base*, std::_Rb_tree_node_base&)@GLIBCXX_3.4 (4)
5: 0000000000000000 0 OBJECT GLOBAL DEFAULT UND vtable for std::basic_ios<char, std::char_traits<char> >@GLIBCXX_3.4 (4)
6: 0000000000000000 0 FUNC GLOBAL DEFAULT UND randombytes_close
7: 0000000000000000 0 FUNC GLOBAL DEFAULT UND if_nametoindex@GLIBC_2.2.5 (3)
8: 0000000000000000 0 FUNC GLOBAL DEFAULT UND isxdigit@GLIBC_2.2.5 (3)
9: 0000000000000000 0 FUNC GLOBAL DEFAULT UND std::__cxx11::basic_ostringstream<char, std::char_traits<char>, std::allocator<char> >::~basic_ostringstream()@GLIBCXX_3.4.21 (5)
#...略

readelf 查看依賴的函式庫

有時候需要瞭解某個執行檔或共享函式庫執行時所依賴的函式庫是哪些,就可以用 readelf 或者 ldd 來查看,

1
readelf -d <executable binary|library> | grep NEEDED

例如查看 gdb 執行檔的所依賴的函式庫是哪些,這些 Shared library 顯示 NEEDED 表示執行時需要,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ readelf -d `which gdb` # 或者 readelf -d /usr/bin/gdb

Dynamic section at offset 0x629d68 contains 36 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libreadline.so.6]
0x0000000000000001 (NEEDED) Shared library: [libz.so.1]
0x0000000000000001 (NEEDED) Shared library: [libdl.so.2]
0x0000000000000001 (NEEDED) Shared library: [libncurses.so.5]
0x0000000000000001 (NEEDED) Shared library: [libtinfo.so.5]
0x0000000000000001 (NEEDED) Shared library: [libm.so.6]
0x0000000000000001 (NEEDED) Shared library: [libpython3.5m.so.1.0]
0x0000000000000001 (NEEDED) Shared library: [libpthread.so.0]
0x0000000000000001 (NEEDED) Shared library: [libexpat.so.1]
0x0000000000000001 (NEEDED) Shared library: [liblzma.so.5]
0x0000000000000001 (NEEDED) Shared library: [libbabeltrace.so.1]
0x0000000000000001 (NEEDED) Shared library: [libbabeltrace-ctf.so.1]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000000c (INIT) 0x45a8d8
0x000000000000000d (FINI) 0x79ea6c
#...略

例如查看 libpthread.so 函式庫的所依賴的函式庫是哪些,這些 Shared library 顯示 NEEDED 表示執行時需要,

1
2
3
4
5
6
7
8
9
10
11
$ readelf -d `gcc -print-file-name=libpthread.so.0`
# 或者 readelf -d /lib/x86_64-linux-gnu/libpthread.so.0

Dynamic section at offset 0x17d50 contains 31 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x0000000000000001 (NEEDED) Shared library: [ld-linux-x86-64.so.2]
0x000000000000000e (SONAME) Library soname: [libpthread.so.0]
0x000000000000000c (INIT) 0x5580
0x000000000000000d (FINI) 0x12ad4
#...略

以上就是 readelf 用法與範例的介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

參考
https://man7.org/linux/man-pages/man1/readelf.1.html
https://linux.die.net/man/1/readelf
readelf命令_Linux readelf 命令用法详解:用于显示elf格式文件的信息
https://man.linuxde.net/readelf

其它相關文章推薦
Linux 常用指令教學懶人包
objdump 用法與範例
nm 用法與範例
Linux ldd 查看執行檔執行時需要哪些 library