跟我學c++中級篇——Linux下的庫相關工具和命令

2021-03-02 太平洋工作室

一、相關工具集

在Linux的實際開發中,與庫相關的命令工具有很多,這些工具在前面也介紹了一部分,現在做一個相對全面的介紹,掌握了這些命令工具,會在實際開發中大大減少解決問題的思路,提高開發的效率。在查找和定位問題時,起到事半功倍的效果。

二、查看和分析工具

1、file
這個命令可以用來查看幾乎所有類型的文件的詳細信息

file [ -bchikLnNprsvz ] [ -f namefile ] [ -F separator ] [ -m magicfiles ] file ...
-b
只顯示執行結果,不顯示文件名
-c
這個是顯示執行過程,在Linux命令中基本差不多
-f
顯示文件中文件名的文件類型
-F
指定分隔符號替換輸出文件名後的默認的「:」分隔符。
-i
輸出mime類型的字符串
-L
顯示相關軟連結對應文件的文件類型
-z
嘗試顯示壓縮文件的內容

看一下執行效果:

machine:~/dlltest$ file -b testdll.cpp
C source, ASCII text
machine:~/dlltest$ file  testdll.cpp
testdll.cpp: C source, ASCII text
machine:~/dlltest$ file -c testdll.cpp
cont    offset  type    opcode  mask    value   desc
machine:~/dlltest$ file -f testdll.cpp
#include <iostream>:                      cannot open `#include <iostream>' (No such file or directory)
:                                         cannot open `' (No such file or directory)
int Compare(int a,int b);:                cannot open `int Compare(int a,int b);' (No such file or directory)
:                                         cannot open `' (No such file or directory)
int main():                               cannot open `int main()' (No such file or directory)
{:                                        cannot open `{' (No such file or directory)
        int a = 100;:                             cannot open `\011int a = 100;' (No such file or directory)
        int b = 200;:                             cannot open `\011int b = 200;' (No such file or directory)
:                                         cannot open `' (No such file or directory)
        int max = Compare(a,b);:                  cannot open `\011int max = Compare(a,b);' (No such file or directory)
        std::cout<<"max is :"<< max<< std::endl;: cannot open `\011std::cout<<"max is :"<< max<< std::endl;' (No such file or directory)
:                                         cannot open `' (No such file or directory)
        return 0;:                                cannot open `\011return 0;' (No such file or directory)
}:                                        cannot open `}' (No such file or directory)

2、size
可以用來查看輸入文件的段大小和總大小:

size [parms] [file]
參數:
size [-A|-B|--format=compatibility]  控制輸出格式
            [--help]
            [-d|-o|-x|--radix=number]  輸出的數據進位
            [--common]         列印common symbols大小
            [-t|--totals]      列出所有文件的總大小
            [--target=bfdname] [-V|--version]
            [objfile...]

默認是以十進位顯示數據的。看一下執行命令:

machine:~/dlltest$ size dtest
   text    data     bss     dec     hex filename
   2483     704     280    3467     d8b dtest
machine:~/dlltest$ size -x dtest
   text    data     bss     dec     hex filename
  0x9b3   0x2c0   0x118    3467     d8b dtest

machine:~/dlltest$ size dc dtest
     text    data     bss     dec     hex filename
     3323     712     280    4315    10db dc
     2483     704     280    3467     d8b dtest

3、strings
這個命令用來在二進位文件中查找可列印的字符串:

strings [ -a ] [ - ] [ -o ] [ -t Format ] [ -n Number ] [ -Number ]  [file ... ]
-a --all:掃描整個文件
-f –print-file-name:顯示文件名
-n –bytes=[number]:找到並輸出終止符
- :設置顯示字節數,默認4個
-t --radix={o,d,x} :輸出字符的位置,基於八進位,十進位或者十六進位
-o :八進位 等於--radix=o
-T --target= :指定目標文件格式

最常用的是如果庫的版本不對,會報編譯錯誤缺少XXX函數,那麼就可以用這個命令來試一下目前庫是否版本低

machine:/usr/local/lib64$ strings libstdc++.so |grep GLIBCXX*
GLIBCXX_3.4
GLIBCXX_3.4.1
GLIBCXX_3.4.2
GLIBCXX_3.4.3
GLIBCXX_3.4.4
GLIBCXX_3.4.5
GLIBCXX_3.4.6
GLIBCXX_3.4.7
GLIBCXX_3.4.8
GLIBCXX_3.4.9
GLIBCXX_3.4.10
GLIBCXX_3.4.11
GLIBCXX_3.4.12
GLIBCXX_3.4.13
GLIBCXX_3.4.14
GLIBCXX_3.4.15
GLIBCXX_3.4.16
GLIBCXX_3.4.17
GLIBCXX_3.4.18
GLIBCXX_3.4.19
GLIBCXX_3.4.20
GLIBCXX_3.4.21
GLIBCXX_3.4.22
GLIBCXX_3.4.23
GLIBCXX_3.4.24
GLIBCXX_3.4.25
GLIBCXX_3.4.26

4、ldd  
這個命令是用來查看文件依賴的,如果缺少庫,可以用他來看:

ldd [option] [parms]
參數:
--version:顯示版本
-v:顯示詳細信息
-u:顯示未應用用直接依賴
-d:執行重定位並顯示不存在的依賴
-r:執行數據對象和函數的重定位,並顯示不存在的依賴

執行一下:

machine:~/dlltest$ ldd dtest
        linux-vdso.so.1 (0x00007ffdb39f7000)
        libdisplay.so => not found
        libcompare.so => not found
        libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fea0eb7d000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fea0e7df000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fea0e5c7000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fea0e1d6000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fea0ef0b000)

不過ldd命令無法識別通過動態加載的動態庫,最重要的是,這個命令可能會引起安全問題,因為一些版本的ldd可能會嘗試執行程序來獲得依賴信息,這就給病毒木馬提供了機會,所以可以使用以下的兩個命令來替換:

machine:~/dlltest$ objdump -p dtest|grep NEEDED
  NEEDED               libdisplay.so
  NEEDED               libcompare.so
  NEEDED               libstdc++.so.6
  NEEDED               libm.so.6
  NEEDED               libgcc_s.so.1
  NEEDED               libc.so.6

  machine:~/dlltest$ readelf -d dtest|grep NEEDED
   0x0000000000000001 (NEEDED)             共享庫:[libdisplay.so]
   0x0000000000000001 (NEEDED)             共享庫:[libcompare.so]
   0x0000000000000001 (NEEDED)             共享庫:[libstdc++.so.6]
   0x0000000000000001 (NEEDED)             共享庫:[libm.so.6]
   0x0000000000000001 (NEEDED)             共享庫:[libgcc_s.so.1]
   0x0000000000000001 (NEEDED)             共享庫:[libc.so.6]

5、nm
顯示目標文件的符號表:

nm [option] [parms]
-A:顯示文件名
-D:顯示動態符號
-g:只顯示外部符號
-r:逆序顯示符號表

執行一下命令:

machine:~/dlltest$ nm -g  libcompare.so
0000000000201038 B __bss_start
                 U __cxa_atexit@@GLIBC_2.2.5
                 w __cxa_finalize@@GLIBC_2.2.5
                 U Display
0000000000201038 D _edata
0000000000201040 B _end
00000000000007d8 T _fini
                 w __gmon_start__
0000000000000620 T _init
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
0000000000000745 T _Z7Compareii
                 U _ZNSt8ios_base4InitC1Ev@@GLIBCXX_3.4
                 U _ZNSt8ios_base4InitD1Ev@@GLIBCXX_3.4

6、objdump    
這個命令非常強大,強大到可以在WIN和LINUX上同時使用。它不但支持ELF,更是支持幾十種其它格式的文件,提供了大量的針對二進位文件的分析信息。
其下命令最後都要跟目標文件地址和名稱。
objdump -f:獲得頭信息
objdump -h:列出所有節
objdump -t(T) :列出所有符號(動態符號)
objdump -p:列查看動態節
objdump -R:查看重定位
objdump -s -j(節名稱):查看節的數據
objdump -d -M intel:以intel方式查看彙編,前提是編譯期提供了-g選項。

前邊講過這個,不再舉例

7、readelf
這個命令只能看ELF文件。主要的用法有以下幾個:
其下命令最後都要跟目標文件地址和名稱。
readelf -h :用於獲取目標頭文件信息,比如上面的頭就是用這個命令得到的。
readelf -S:是大寫的S,是獲得節的信息
readelf --symbols:用於得到文件內的符號。注意這裡是兩個-
readelf --dyn-syms:列出動態符號
readelf -d:只看動態節信息
readelf -r:查看重定位信息
readelf -x:查看指定節的信息
其它更多的可以用man命令或者查找相關資料。看一下執行查看指定節的命令。

三、部署工具

1、chrpath
這個工具可以改變rpath的路徑,也就是可以修改依賴庫的路徑,好東西啊。

chrpath [-v|-d|-c|-r <path>] <program> [<program> ...]
參數:
   -v|--version                顯示版本號
   -d|--delete                 刪除當前rpath/runpath設置
   -c|--convert                覆蓋上述設置
   -r <path>|--replace <path>  用給定的路徑覆蓋上述路徑
   -l|--list                   顯示上述路徑

看一下執行情況:

machine:~/dlltest$ ldd dtest
        libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f8996e19000)

machine:~/dlltest$ chrpath -r "/usr/local/lib/" dtest
machine:~/dlltest$ ldd dtest
        libstdc++.so.6 => /usr/local/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f8996e19000)

如果沒有這個命令,需要安裝一下。
2、patchelf
這個功能和上面的類似也是修改runpath的路徑。

patchelf --set-rpath [one or more paths] [executable]

執行命令:

machine:~/dlltest$ patchelf  --set-rpath /usr/local/lib/ dtest
machine:~/dlltest$ readelf -d dtest

Dynamic section at offset 0x270 contains 31 entries:
  標記        類型                         名稱/值
 0x000000000000001d (RUNPATH)            Library runpath: [/usr/local/lib/]
 0x0000000000000001 (NEEDED)             共享庫:[libdisplay.so]
 0x0000000000000001 (NEEDED)             共享庫:[libcompare.so]
 0x0000000000000001 (NEEDED)             共享庫:[libstdc++.so.6]

3、ldconfig
這個命令的重要性在於,如果在/etc/ld.so.conf中包含的目錄中修改了依賴庫文件,可以使用這個命令將其更新到/etc/ld.so.cache文件中,從而使路徑生效。但是這個命令需要root權限。

四、運行分析工具

1、strace
追蹤進程調用

strace [option] [file]
參數:
-tt 在每行輸出的前面,顯示毫秒級別的時間
-T 顯示每次系統調用所花費的時間
-v 對於某些相關調用,把完整的環境變量,文件stat結構等打出來。
-f 跟蹤目標進程,以及目標進程創建的所有子進程
-e 控制要跟蹤的事件和跟蹤行為,比如指定要跟蹤的系統調用名稱
-o 把strace的輸出單獨寫到指定的文件
-s 當系統調用的某個參數是字符串時,最多輸出指定長度的內容,默認是32個字節
-p 指定要跟蹤的進程pid, 要同時跟蹤多個pid, 重複多次-p選項即可。

執行一下:

machine:~/dlltest$ strace -tt  ./dtest   -o 1.log

18:20:27.732059 writev(2, [{iov_base="./dtest", iov_len=7}, {iov_base=": ", iov_len=2}, {iov_base="error while loading shared libra"..., iov_len=36}, {iov_base=": ", iov_len=2}, {iov_base="libdisplay.so", iov_len=13}, {iov_base=": ", iov_len=2}, {iov_base="cannot open shared object file", iov_len=30}, {iov_base=": ", iov_len=2}, {iov_base="No such file or directory", iov_len=25}, {iov_base="\n", iov_len=1}], 10./dtest: error while loading shared libraries: libdisplay.so: cannot open shared object file: No such file or directory
) = 120
18:20:27.732185 exit_group(127)         = ?
18:20:27.732317 +++ exited with 127 +++

//如果跟蹤某個進程可以:
strace -tt -T -v -f -e trace=file -o ./data.log -s 1024 -p 9879
跟蹤某個執行文件啟動調用:
strace -tt -T -f -e trace=file -o ./data.log -s 1024 ./exefilename

2、addr2line
這個可以通過崩潰的地址來回退到指定文件的位置,不過前提是要加上調試符號 -g.

addr2line [-b bfdname|--target=bfdname] [-C|--demangle[=style]] [-e filename|--exe=filename] [-f|--functions] [-s|--basename] [-i|--inlines] [-j|--section=name] [-H|--help] [-V|--version] [addr addr ...]
參數:
-b
指定目標文件的目標代碼格式為bfdname。
-C
將低級符號名稱解碼(demangle)為用戶級名稱。去除c++改名機制產生的代碼。
-e
指定應為其轉換地址的可執行文件的名稱。默認文件是a.out。
-f
顯示函數名以及文件和行號信息。
-s
只顯示每個文件名而不顯示相關路徑

-i
如果地址屬於內聯函數,則列印全部代碼
-j
讀取相對於指定節而不是絕對地址的偏移量。

假如taddr.cpp第6行做一個除0的動作,編譯後執行,崩潰轉儲,使用gdb exe core得到地址就可以使用如下命令來操作:

machine:~/dlltest$ addr2line -C -f -e taddr 0x00000000004007c7
main
/dlltest/taddr.cpp:6

3、gdb
這個工具實在是太強大,請移步專門的分析篇章。

五、實例

使用上面的命令,看一個個體的例子的分析過程(例子使用前面創建的dtest):
1、確定文件類型

machine:~/dlltest$ file dtest
dtest: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, not stripped
machine:~/dlltest$ readelf -h dtest |grep 類型
  類型:                              EXEC (可執行文件)

2、確定可執行文件入口

machine:~/dlltest$ objdump -f dtest|grep 起始
起始地址 0x0000000000400850
machine:~/dlltest$ readelf -h dtest |grep 入口
  入口點地址:               0x400850

3、列出符號表

machine:~/dlltest$ readelf --dyn-syms dtest  動態連結符號

Symbol table '.dynsym' contains 17 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND _Z7Compareii
     2: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __cxa_atexit@GLIBC_2.2.5 (3)
     3: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND _ZStlsISt11char_traitsIcE@GLIBCXX_3.4 (2)
     4: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND _ZNSolsEPFRSoS_E@GLIBCXX_3.4 (2)
     5: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND _ZNSt8ios_base4InitC1Ev@GLIBCXX_3.4 (2)
     6: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND _ZNSolsEi@GLIBCXX_3.4 (2)
     7: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.2.5 (3)
     8: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
     9: 0000000000601068     0 NOTYPE  GLOBAL DEFAULT   23 _edata
    10: 0000000000601198     0 NOTYPE  GLOBAL DEFAULT   24 _end
    11: 00000000004007d0     0 FUNC    GLOBAL DEFAULT  UND _ZSt4endlIcSt11char_trait@GLIBCXX_3.4 (2)
    12: 00000000004007a8     0 FUNC    GLOBAL DEFAULT   12 _init
    13: 0000000000601068     0 NOTYPE  GLOBAL DEFAULT   24 __bss_start
    14: 0000000000400a54     0 FUNC    GLOBAL DEFAULT   15 _fini
    15: 0000000000601080   272 OBJECT  GLOBAL DEFAULT   24 _ZSt4cout@GLIBCXX_3.4 (2)
    16: 0000000000400840     0 FUNC    GLOBAL DEFAULT  UND _ZNSt8ios_base4InitD1Ev@GLIBCXX_3.4 (2)
    machine:~/dlltest$ objdump -t dtest  獲取外部可見符號

    dtest:     文件格式 elf64-x86-64

    SYMBOL TABLE:
    00000000003ff888 l    d  .interp        0000000000000000              .interp
    00000000003ff8a8 l    d  .note.ABI-tag  0000000000000000              .note.ABI-tag
    00000000003ff830 l    d  .hash  0000000000000000              .hash
    00000000003ff7e8 l    d  .gnu.hash      0000000000000000              .gnu.hash
    00000000003ff650 l    d  .dynsym        0000000000000000              .dynsym
    00000000003ff4b0 l    d  .dynstr        0000000000000000              .dynstr
    000000000040063e l    d  .gnu.version   0000000000000000              .gnu.version
    0000000000400660 l    d  .gnu.version_r 0000000000000000              .gnu.version_r
    00000000004006a0 l    d  .rela.dyn      0000000000000000              .rela.dyn
    00000000004006e8 l    d  .rela.plt      0000000000000000              .rela.plt
    00000000004007a8 l    d  .init  0000000000000000              .init
    00000000004007c0 l    d  .plt   0000000000000000              .plt
    0000000000400850 l    d  .text  0000000000000000              .text
    0000000000400a54 l    d  .fini  0000000000000000              .fini
    0000000000400a60 l    d  .rodata        0000000000000000              .rodata
    0000000000400a70 l    d  .eh_frame_hdr  0000000000000000              .eh_frame_hdr
    0000000000400ac0 l    d  .eh_frame      0000000000000000              .eh_frame
    0000000000600da8 l    d  .init_array    0000000000000000              .init_array
    0000000000600db8 l    d  .fini_array    0000000000000000              .fini_array
    00000000003ff270 l    d  .dynamic       0000000000000000              .dynamic
    0000000000600ff0 l    d  .got   0000000000000000              .got
    0000000000601000 l    d  .got.plt       0000000000000000              .got.plt
    0000000000601058 l    d  .data  0000000000000000              .data
    0000000000601080 l    d  .bss   0000000000000000              .bss
    0000000000000000 l    d  .comment       0000000000000000              .comment
    0000000000000000 l    df *ABS*  0000000000000000              crtstuff.c
    0000000000400890 l     F .text  0000000000000000              deregister_tm_clones
    00000000004008c0 l     F .text  0000000000000000              register_tm_clones
    0000000000400900 l     F .text  0000000000000000              __do_global_dtors_aux
    0000000000601190 l     O .bss   0000000000000001              completed.7409
    0000000000600db8 l     O .fini_array    0000000000000000              __do_global_dtors_aux_fini_array_entry
    0000000000400930 l     F .text  0000000000000000              frame_dummy
    0000000000600da8 l     O .init_array    0000000000000000              __frame_dummy_init_array_entry
    0000000000000000 l    df *ABS*  0000000000000000              testdll.cpp
    0000000000400a64 l     O .rodata        0000000000000001              _ZStL19piecewise_construct
    0000000000601191 l     O .bss   0000000000000001              _ZStL8__ioinit
    000000000040098d l     F .text  000000000000003e              _Z41__static_initialization_and_destruction_0ii
    00000000004009cb l     F .text  0000000000000015              _GLOBAL__sub_I_main
    0000000000000000 l    df *ABS*  0000000000000000              crtstuff.c
    0000000000400bfc l     O .eh_frame      0000000000000000              __FRAME_END__
    0000000000000000 l    df *ABS*  0000000000000000
    0000000000400a70 l       .eh_frame_hdr  0000000000000000              __GNU_EH_FRAME_HDR
    0000000000600dc0 l     O .dynamic       0000000000000000              _DYNAMIC
    0000000000600db8 l       .init_array    0000000000000000              __init_array_end
    0000000000600da8 l       .init_array    0000000000000000              __init_array_start
    0000000000601000 l     O .got.plt       0000000000000000              _GLOBAL_OFFSET_TABLE_
    0000000000601068 g       .data  0000000000000000              _edata
    0000000000601058  w      .data  0000000000000000              data_start
    0000000000400a60 g     O .rodata        0000000000000004              _IO_stdin_used
    0000000000400932 g     F .text  000000000000005b              main
    00000000004007d0       F *UND*  0000000000000000              _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@@GLIBCXX_3.4
    0000000000601060 g     O .data  0000000000000000              .hidden __dso_handle
    0000000000400a54 g     F .fini  0000000000000000              _fini
    0000000000400880 g     F .text  0000000000000002              .hidden _dl_relocate_static_pie
    0000000000000000       F *UND*  0000000000000000              _Z7Compareii
    0000000000000000       F *UND*  0000000000000000              __cxa_atexit@@GLIBC_2.2.5
    0000000000400850 g     F .text  000000000000002b              _start
    0000000000000000       F *UND*  0000000000000000              _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@@GLIBCXX_3.4
    0000000000000000       F *UND*  0000000000000000              _ZNSolsEPFRSoS_E@@GLIBCXX_3.4
    00000000004007a8 g     F .init  0000000000000000              _init
    0000000000601068 g     O .data  0000000000000000              .hidden __TMC_END__
    0000000000601080 g     O .bss   0000000000000110              _ZSt4cout@@GLIBCXX_3.4
    0000000000601058 g       .data  0000000000000000              __data_start
    0000000000601198 g       .bss   0000000000000000              _end
    0000000000601068 g       .bss   0000000000000000              __bss_start
    0000000000000000       F *UND*  0000000000000000              _ZNSt8ios_base4InitC1Ev@@GLIBCXX_3.4
    00000000004009e0 g     F .text  0000000000000065              __libc_csu_init
    0000000000000000       F *UND*  0000000000000000              _ZNSolsEi@@GLIBCXX_3.4
    0000000000400a50 g     F .text  0000000000000002              __libc_csu_fini
    0000000000000000       F *UND*  0000000000000000              __libc_start_main@@GLIBC_2.2.5
    0000000000000000  w      *UND*  0000000000000000              __gmon_start__
    0000000000400840       F *UND*  0000000000000000              _ZNSt8ios_base4InitD1Ev@@GLIBCXX_3.4

4、查看節的信息

machine:~/dlltest$ readelf -s dtest

Symbol table '.dynsym' contains 17 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND _Z7Compareii
     2: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __cxa_atexit@GLIBC_2.2.5 (3)
     3: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND _ZStlsISt11char_traitsIcE@GLIBCXX_3.4 (2)
     4: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND _ZNSolsEPFRSoS_E@GLIBCXX_3.4 (2)
     5: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND _ZNSt8ios_base4InitC1Ev@GLIBCXX_3.4 (2)
     6: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND _ZNSolsEi@GLIBCXX_3.4 (2)
     7: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.2.5 (3)
     8: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
     9: 0000000000601068     0 NOTYPE  GLOBAL DEFAULT   23 _edata
    10: 0000000000601198     0 NOTYPE  GLOBAL DEFAULT   24 _end
    11: 00000000004007d0     0 FUNC    GLOBAL DEFAULT  UND _ZSt4endlIcSt11char_trait@GLIBCXX_3.4 (2)
    12: 00000000004007a8     0 FUNC    GLOBAL DEFAULT   12 _init
    13: 0000000000601068     0 NOTYPE  GLOBAL DEFAULT   24 __bss_start
    14: 0000000000400a54     0 FUNC    GLOBAL DEFAULT   15 _fini
    15: 0000000000601080   272 OBJECT  GLOBAL DEFAULT   24 _ZSt4cout@GLIBCXX_3.4 (2)
    16: 0000000000400840     0 FUNC    GLOBAL DEFAULT  UND _ZNSt8ios_base4InitD1Ev@GLIBCXX_3.4 (2)

Symbol table '.symtab' contains 73 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 00000000003ff888     0 SECTION LOCAL  DEFAULT    6
     2: 00000000003ff8a8     0 SECTION LOCAL  DEFAULT    7
     3: 00000000003ff830     0 SECTION LOCAL  DEFAULT    5

5、查看段的信息

machine:~/dlltest$ objdump -p dtest

dtest:     文件格式 elf64-x86-64

程序頭:
    PHDR off    0x0000000000000040 vaddr 0x00000000003ff040 paddr 0x00000000003ff040 align 2**3
         filesz 0x0000000000000230 memsz 0x0000000000000230 flags r--
   STACK off    0x0000000000001000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**4
         filesz 0x0000000000000000 memsz 0x0000000000000000 flags rw-
    LOAD off    0x0000000000000000 vaddr 0x00000000003ff000 paddr 0x00000000003ff000 align 2**12
         filesz 0x0000000000001000 memsz 0x0000000000001000 flags rw-
 DYNAMIC off    0x0000000000000270 vaddr 0x00000000003ff270 paddr 0x00000000003ff270 align 2**3
         filesz 0x0000000000000240 memsz 0x0000000000000240 flags rw-
  INTERP off    0x0000000000000888 vaddr 0x00000000003ff888 paddr 0x00000000003ff888 align 2**0
         filesz 0x000000000000001c memsz 0x000000000000001c flags r--
    LOAD off    0x0000000000001000 vaddr 0x0000000000400000 paddr 0x0000000000400000 align 2**12
         filesz 0x0000000000000c00 memsz 0x0000000000000c00 flags r-x
    NOTE off    0x0000000000001254 vaddr 0x0000000000400254 paddr 0x0000000000400254 align 2**2
         filesz 0x0000000000000020 memsz 0x0000000000000020 flags r--
EH_FRAME off    0x0000000000001a70 vaddr 0x0000000000400a70 paddr 0x0000000000400a70 align 2**2
         filesz 0x000000000000004c memsz 0x000000000000004c flags r--
    LOAD off    0x0000000000001da8 vaddr 0x0000000000600da8 paddr 0x0000000000600da8 align 2**12
         filesz 0x00000000000002c0 memsz 0x00000000000003f0 flags rw-
   RELRO off    0x0000000000001da8 vaddr 0x0000000000600da8 paddr 0x0000000000600da8 align 2**0
         filesz 0x0000000000000258 memsz 0x0000000000000258 flags r--

動態節:
  RUNPATH              /usr/local/lib/
  NEEDED               libdisplay.so
  NEEDED               libcompare.so
  NEEDED               libstdc++.so.6
  NEEDED               libm.so.6
  NEEDED               libgcc_s.so.1
  NEEDED               libc.so.6
  INIT                 0x00000000004007a8
  FINI                 0x0000000000400a54
  INIT_ARRAY           0x0000000000600da8
  INIT_ARRAYSZ         0x0000000000000010
  FINI_ARRAY           0x0000000000600db8
  FINI_ARRAYSZ         0x0000000000000008
  HASH                 0x00000000003ff830
  GNU_HASH             0x00000000003ff7e8
  STRTAB               0x00000000003ff4b0
  SYMTAB               0x00000000003ff650
  STRSZ                0x000000000000019d
  SYMENT               0x0000000000000018
  DEBUG                0x0000000000000000
  PLTGOT               0x0000000000601000
  PLTRELSZ             0x00000000000000c0
  PLTREL               0x0000000000000007
  JMPREL               0x00000000004006e8
  RELA                 0x00000000004006a0
  RELASZ               0x0000000000000048
  RELAENT              0x0000000000000018
  VERNEED              0x0000000000400660
  VERNEEDNUM           0x0000000000000002
  VERSYM               0x000000000040063e

版本引用:
  required from libc.so.6:
    0x09691a75 0x00 03 GLIBC_2.2.5
  required from libstdc++.so.6:
    0x08922974 0x00 02 GLIBCXX_3.4

6、反彙編

machine:~/dlltest$ objdump -d -M intel dtest

dtest:     文件格式 elf64-x86-64


Disassembly of section .init:

00000000004007a8 <_init>:
  4007a8:       48 83 ec 08             sub    rsp,0x8
  4007ac:       48 8b 05 45 08 20 00    mov    rax,QWORD PTR [rip+0x200845]        # 600ff8 <__gmon_start__>
  4007b3:       48 85 c0                test   rax,rax
  4007b6:       74 02                   je     4007ba <_init+0x12>
  4007b8:       ff d0                   call   rax
  4007ba:       48 83 c4 08             add    rsp,0x8
  4007be:       c3                      ret

Disassembly of section .plt:

00000000004007c0 <.plt>:
  4007c0:       ff 35 42 08 20 00       push   QWORD PTR [rip+0x200842]        # 601008 <_GLOBAL_OFFSET_TABLE_+0x8>
  4007c6:       ff 25 44 08 20 00       jmp    QWORD PTR [rip+0x200844]        # 601010 <_GLOBAL_OFFSET_TABLE_+0x10>
  4007cc:       0f 1f 40 00             nop    DWORD PTR [rax+0x0]

00000000004007d0 <_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@plt>:
  4007d0:       ff 25 42 08 20 00       jmp    QWORD PTR [rip+0x200842]        # 601018 <_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GLIBCXX_3.4>
  4007d6:       68 00 00 00 00          push   0x0
  4007db:       e9 e0 ff ff ff          jmp    4007c0 <.plt>

00000000004007e0 <_Z7Compareii@plt>:
  4007e0:       ff 25 3a 08 20 00       jmp    QWORD PTR [rip+0x20083a]        # 601020 <_Z7Compareii>
  4007e6:       68 01 00 00 00          push   0x1
  4007eb:       e9 d0 ff ff ff          jmp    4007c0 <.plt>

00000000004007f0 <__cxa_atexit@plt>:
  4007f0:       ff 25 32 08 20 00       jmp    QWORD PTR [rip+0x200832]        # 601028 <__cxa_atexit@GLIBC_2.2.5>
  4007f6:       68 02 00 00 00          push   0x2
  4007fb:       e9 c0 ff ff ff          jmp    4007c0 <.plt>

0000000000400800 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>:
  400800:       ff 25 2a 08 20 00       jmp    QWORD PTR [rip+0x20082a]        # 601030 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@GLIBCXX_3.4>
  400806:       68 03 00 00 00          push   0x3
  40080b:       e9 b0 ff ff ff          jmp    4007c0 <.plt>

0000000000400810 <_ZNSolsEPFRSoS_E@plt>:
  400810:       ff 25 22 08 20 00       jmp    QWORD PTR [rip+0x200822]        # 601038 <_ZNSolsEPFRSoS_E@GLIBCXX_3.4>
  400816:       68 04 00 00 00          push   0x4
  40081b:       e9 a0 ff ff ff          jmp    4007c0 <.plt>

7 、判斷是否Debug

machine:~/dlltest$ readelf --debug-dump=line taddr
.debug_line 節的調試內容轉儲:

  偏移:                       0x0
  長度:                      1061
  DWARF 版本:                2
  導言長度:        993
  最小指令長度:              1
  「is_stmt」的初始值:       1
  行基數:                      -5
  行範圍:                      14
  操作碼基數:                  13

 操作碼:
  Opcode 1 has 0 args
  Opcode 2 has 1 arg
  Opcode 3 has 1 arg
  Opcode 4 has 1 arg
  Opcode 5 has 1 arg
  Opcode 6 has 0 args
  Opcode 7 has 0 args
  Opcode 8 has 0 args
  Opcode 9 has 1 arg
  Opcode 10 has 0 args
  Opcode 11 has 0 args
  Opcode 12 has 1 arg

 目錄表 (偏移 0x1b):
  1     /usr/local/include/c++/9.1.0
  2     /usr/local/include/c++/9.1.0/bits
  3     /usr/local/include/c++/9.1.0/x86_64-pc-linux-gnu/bits
  4     /usr/local/include/c++/9.1.0/debug
  5     /usr/local/include/c++/9.1.0/ext
  6     /usr/local/lib/gcc/x86_64-pc-linux-gnu/9.1.0/include
  7     /usr/include/x86_64-linux-gnu/bits/types
  8     /usr/include/x86_64-linux-gnu/bits
  9     /usr/include

 文件名表 (偏移 0x163):
  條目  目錄    時間    大小    名稱
  1     0       0       0       taddr.cpp
  2     1       0       0       iostream

8 、查看應用依賴項

machine:~/dlltest$ ldd dtest
        linux-vdso.so.1 (0x00007ffd18f90000)
        libdisplay.so => not found
        libcompare.so => not found
        libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f8941397000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f8940ff9000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f8940de1000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f89409f0000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f8941725000)

或者特定的加載庫

machine:~/dlltest$ ldconfig -p|grep display
//此處沒有找到

9、使用strace追蹤加載的動態庫
這個已經介紹並運行了實例,此處不再贅述。
10、lsof顯示當前打開的文件

//顯示某個進程使用的文件
# lsof -c MeetingServer
COMMAND    PID USER   FD      TYPE DEVICE SIZE/OFF    NODE NAME
MeetingSe 9032 root  cwd       DIR  253,1     4096 1186984 /root/projects/MeetingServer/build
MeetingSe 9032 root  rtd       DIR  253,1     4096       2 /
MeetingSe 9032 root  txt       REG  253,1  2446712 1187072 /root/projects/MeetingServer/build/MeetingServer
MeetingSe 9032 root  mem       REG  253,1  2151672  265443 /usr/lib64/libc-2.17.so
MeetingSe 9032 root  mem       REG  253,1   141968  265470 /usr/lib64/libpthread-2.17.so
MeetingSe 9032 root  mem       REG  253,1    88720  266411 /usr/lib64/libgcc_s-4.8.5-20150702.so.1
MeetingSe 9032 root  mem       REG  253,1  1137024  265452 /usr/lib64/libm-2.17.so
MeetingSe 9032 root  mem       REG  253,1   995840  266421 /usr/lib64/libstdc++.so.6.0.19
MeetingSe 9032 root  mem       REG  253,1   163400  265153 /usr/lib64/ld-2.17.so
MeetingSe 9032 root    0w      CHR    1,3      0t0    1028 /dev/null
MeetingSe 9032 root    1w      REG  253,1  1285955 1187006 /root/projects/MeetingServer/build/1.log
MeetingSe 9032 root    2w      REG  253,1  1285955 1187006 /root/projects/MeetingServer/build/1.log
MeetingSe 9032 root    3u     IPv4 222350      0t0     TCP *:38888 (LISTEN)
MeetingSe 9032 root    4u  a_inode   0,10        0    6487 [eventpoll]
MeetingSe 9032 root    5u  a_inode   0,10        0    6487 [timerfd]
[root@iZj6c8dmrj7zr49bx5dnooZ ~]# lsof -c -p 9032
lsof: missing -c option value
lsof 4.87
 latest revision: ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/
 latest FAQ: ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/FAQ
 latest man page: ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/lsof_man
 usage: [-?abhKlnNoOPRtUvVX] [+|-c c] [+|-d s] [+D D] [+|-f[gG]] [+|-e s]
 [-F [f]] [-g [s]] [-i [i]] [+|-L [l]] [+m [m]] [+|-M] [-o [o]] [-p s]
[+|-r [t]] [-s [p:s]] [-S [t]] [-T [t]] [-u s] [+|-w] [-x [fl]] [--] [names]
Use the ``-h'' option to get more help information.
[root@iZj6c8dmrj7zr49bx5dnooZ ~]# lsof  -p 9032
COMMAND    PID USER   FD      TYPE DEVICE SIZE/OFF    NODE NAME
MeetingSe 9032 root  cwd       DIR  253,1     4096 1186984 /root/projects/MeetingServer/build
MeetingSe 9032 root  rtd       DIR  253,1     4096       2 /
MeetingSe 9032 root  txt       REG  253,1  2446712 1187072 /root/projects/MeetingServer/build/MeetingServer
MeetingSe 9032 root  mem       REG  253,1  2151672  265443 /usr/lib64/libc-2.17.so
MeetingSe 9032 root  mem       REG  253,1   141968  265470 /usr/lib64/libpthread-2.17.so
MeetingSe 9032 root  mem       REG  253,1    88720  266411 /usr/lib64/libgcc_s-4.8.5-20150702.so.1
MeetingSe 9032 root  mem       REG  253,1  1137024  265452 /usr/lib64/libm-2.17.so
MeetingSe 9032 root  mem       REG  253,1   995840  266421 /usr/lib64/libstdc++.so.6.0.19
MeetingSe 9032 root  mem       REG  253,1   163400  265153 /usr/lib64/ld-2.17.so
MeetingSe 9032 root    0w      CHR    1,3      0t0    1028 /dev/null
MeetingSe 9032 root    1w      REG  253,1  1285955 1187006 /root/projects/MeetingServer/build/1.log
MeetingSe 9032 root    2w      REG  253,1  1285955 1187006 /root/projects/MeetingServer/build/1.log
MeetingSe 9032 root    3u     IPv4 222350      0t0     TCP *:38888 (LISTEN)
MeetingSe 9032 root    4u  a_inode   0,10        0    6487 [eventpoll]
MeetingSe 9032 root    5u  a_inode   0,10        0    6487 [timerfd]

lsof還可以恢復刪除的文件,這裡不介紹。此命令非常強大,可以查詢相關資料。

六、總結

基本到這裡,對庫的學習和使用就基本告一段落了,整個過程使用的工程簡單明了,只要掌握了這些基本的方法,就可以進行複雜的開發,因為所謂複雜,並不是庫使用本身的複雜,而是業務邏輯的複雜,導出一個函數和導出一百個函數,沒有什麼區別。同樣,使用一個動態庫和使用一百個動態庫同樣沒有區別,如果說非要有區別,就是要認真考慮庫的設計和導出的ABI兼容問題,考慮一個不同的庫之間的調用如果解耦和儘量設計使用單向調用的原則。
假使真的沒有辦法,遇到了非常複雜的循環調用,動態庫和靜態庫來回調用,深入數層甚至上十層,只要掌握了分析工具和命令,一點點的琢磨,終究還是能夠解決問題的。
一定要學會的是編程的思想和設計的原則,一定會把複雜的邏輯抽象成一個簡單的模型,這樣,對於解決看上去非常複雜的問題有著重要的幫助。而這,就需要同學們仔細反覆的深入學習和實踐了。

相關焦點

  • 跟我學C++中級篇——STL的學習
    一、c++標準庫C++的標準庫主要包含兩大類,首先是包含C的標準庫的,當然,為了適應c++對一些C庫進行了少許的修改和增加。最重要的當然是面向對象的c++庫;而c++庫又可以分成兩大類,即面向對象的c++庫和標準模板庫,也就是題目中的STL。
  • 跟我學C++中級篇——STL中的字符串
    STL為了解決這個問題,提供了std::string這個數據結構,其實它就是一個類,不過其提供了常見的對字符串的操作符的重載,實現在實際工程中經常遇到的字符串的長度計算,拼接和裁剪以及和C類型字符串的轉換。它不算是STL的容器,它只是一個類。
  • C++伺服器開發完整學習路線(含免費學習資料下載地址)
    我寫這篇文章的目的就是為了幫助更多想入行或者想轉行做c++伺服器的新人避免走更多的彎路,最終能夠順利的掌握相關知識找到心儀的工作。一. 基礎階段  c/c++程式語言linux基礎數據結構與算法設計模式腳本語言(可選)二.
  • python3使用ctypes在windows中訪問C和C++動態連結庫函數示例
    python3使用ctypes在windows中訪問C和C++動態連結庫函數示例這是我們的第一個示例,我們儘量簡單,不傳參,不返回,不訪問其他的動態連結庫一 測試環境介紹和準備測試環境:作業系統:windows10Python版本:3.7.0VS版本:vs2015社區版(免費)相關工具下載:VS版本vs2015社區版(免費
  • 文件和目錄屬性相關 Linux 命令詳解,收藏~
    ,深入了解linux文件目錄結構的標準和每個目錄的詳細功能,對於我們用好linux系統只管重要,下面我們就開始了解一下linux目錄結構的相關知識。當在使用Linux的時候,如果您通過ls –l / 就會發現,在/下包涵很多的目錄,比如etc、usr、var、bin ... ... 等目錄,而在這些目錄中,我們進去看看,發現也有很多的目錄或文件。
  • Linux GCC常用命令
    從程式設計師的角度看,函數庫實際上就是一些頭文件(.h)和庫文件(so、或lib、dll)的集合。\。雖然Linux下的大多數函數都默認將頭文件放到/usr/include/目錄下,而庫文件則放到/usr/lib/目錄下;Windows所使用的庫文件主要放在Visual Stido的目錄下的include和lib,以及系統文件夾下。
  • C++機器學習庫介紹
    介紹我喜歡使用C++。C++是我學習過的第一種程式語言,我喜歡在機器學習中使用它。我在之前寫過關於構建機器學習模型的文章。我收到了一個回復,問我C++有沒有機器學習的庫?這是個公平的問題。像Python和R這樣的語言有大量的包和庫來滿足不同的機器學習任務。
  • 每天一個 Linux 命令(23):Linux 目錄結構
    ,深入了解linux文件目錄結構的標準和每個目錄的詳細功能,對於我們用好linux系統只管重要,下面我們就開始了解一下linux目錄結構的相關知識。當在使用Linux的時候,如果您通過ls –l / 就會發現,在/下包涵很多的目錄,比如etc、usr、var、bin … … 等目錄,而在這些目錄中,我們進去看看,發現也有很多的目錄或文件。
  • Linux下使用tar命令
    範例:範例一:將整個 /etc 目錄下的文件全部打包成為 /tmp/etc.tar[root@linux ~][root@linux ~][root@linux ~]特別注意:在參數範例四:在 /tmp 底下,我只想要將 /tmp/etc.tar.gz 內的 etc/passwd 解開而已[root@linux ~][root@linux tmp]我可以透過 tar -ztvf 來查閱 tarfile 內的文件名稱,如果只要一個文件,就可以透過這個方式來下達,注意, etc.tar.gz 內的根目錄
  • linux下configure命令詳細介紹
    Linux環境下的軟體安裝,並不是一件容易的事情;如果通過原始碼編譯後在安裝,當然事情就更為複雜一些;現在安裝各種軟體的教程都非常普遍;但萬變不離其中,對基礎知識的紮實掌握,安裝各種軟體的問題就迎刃而解了。Configure腳本配置工具就是基礎之一,它是autoconf的工具的基本應用。
  • 摸魚也要有技巧 3個linux命令行工具讓你假裝很忙
    我們遇到的大多數情況都需要我們對試圖解決的問題進行大量思考,與利益相關者進行良好的溝通,進行一些研究以及組織信息,然後還有佔工作量很少的快速打字。但這並不意味著我們不想和電影中的黑客一樣。有時,我們只是想讓自己看起來「有效率」。旁註:我當然是開玩笑的。如果你真的需要被評估看起來有多忙,那麼你們公司存在很嚴重的文化問題。
  • Linux常用命令:Linux more命令使用方法
    more功能類似 cat ,cat命令是整個文件的內容從上到下顯示在屏幕上。 more會以一頁一頁的顯示方便使用者逐頁閱讀,而最基本的指令就是按空白鍵(space)就往下一頁顯示,按 b 鍵就會往回(back)一頁顯示,而且還有搜尋字串的功能 。more命令從前向後讀取文件,因此在啟動時就加載整個文件。
  • C++機器學習庫介紹 | 文末送書
    C++是我學習過的第一種程式語言,我喜歡在機器學習中使用它。我在之前寫過關於構建機器學習模型的文章,我收到了一個回復,問我C++有沒有機器學習的庫?這是個很好的問題。像Python和R這樣的語言有大量的包和庫來滿足不同的機器學習任務,那麼C++有沒有這樣的產品呢?是的!在本文中,我將重點介紹兩個這樣的C++庫,我們也將看到它們都是可以運行。
  • ​跟我學C++中級篇——STL的容器vector
    二、源碼std:vector的源碼很容易找到,其實你看它代碼也不複雜,之所以看上去眼花繚亂的原因不是因為他複雜,而是為了兼容和安全性搞了好多新功能和方法,再加上一些模板本身的技巧。這些都可以暫時忽略過去,重點看重點的相關的函數方法的實現。向量的構造函數其實就是兩部分模板類型名稱和分配器,而分配器一般使用默認的分析器類型,這個回頭再分配器中再詳細分析。
  • gcc、arm-linux-gcc和arm-elf-gcc的關係?
    GCC 中的一般工具通常都是通過在命令行上調用命令(如 gcc)來執行的。在使用交叉編譯的情況下,這些工具將根據它編譯的目標而命名。例如,要使用交叉工具鏈為 ARM 機器編譯簡單的 Hello World 程序,你可以運行如下所示的命令:使用如下命令編譯並測試這個代碼:arm-linux-gcc -o hello hello.c。
  • Linux 命令匯總
    文件壓縮及解壓縮命令(4 個)tar打包壓縮。oldboyunzip解壓文件。gzipgzip 壓縮工具。zip壓縮工具。信息顯示命令(11 個)uname顯示作業系統相關信息的命令。wget命令行下載文件。ping測試主機之間網絡的連通性。route顯示和設置 linux 系統的路由表。ifconfig查看、配置、啟用或禁用網絡接口的命令。ifup啟動網卡。ifdown關閉網卡。
  • Linux mkdir 命令的初學者教程 | Linux 中國
    在這篇教程中,我將使用一些易於理解的例子來講解這個工具的基本用法。在開始之前,值得一提的是,這篇教程中的所有例子都已經在 Ubuntu 16.04 LTS 中測試過。Linux mkdir 命令正如上面所提到的,用戶可以使用 mkdir 命令來創建目錄。它的語法如下:mkdir [OPTION]... DIRECTORY...
  • 每天學一個 Linux 命令(34):wc
    命令簡介wc 命令用來統計文件中的行數、單詞數或字節數,然後將結果輸出在終端上。我們可以使用 wc 命令來計算文件的Byte數、字數或是列數。test.txt[root@centos7 ~]# wc -m test.txt 140 test.txt[root@centos7 ~]# wc -l test.txt 6 test.txt[root@centos7 ~]# wc -c test.txt 140 test.txt統計當前目錄下的所有文件行數及總計行數
  • 性能工具之linux常見日誌統計分析命令
    引言在上文中性能工具之linux三劍客awk、grep、sed詳解,我們已經詳細介紹 linux
  • 用linux命令瀏覽網頁:用Wget命令來瀏覽網頁
    用linux命令瀏覽網頁:用Wget命令來瀏覽網頁 以下是在liux模式下用linux命令瀏覽網頁的方法,可以用linux命令:lynx,links瀏覽web,linux命令:lftp,wget,curl等上傳/下載軟體。