【軟體開發底層知識修煉】六 Binutils輔助工具之- addr2line與strip工具

楊柳_發表於2019-02-26

學習交流加

  • 個人qq: 1126137994
  • 個人微信: liu1126137994
  • 學習交流資源分享qq群: 962535112

上一篇文章我們學習了gcc編譯器的相關內容。點選檢視上一篇文章:gcc編譯器。本篇文章接著上一篇文章,學習GNU為GCC提供的輔助開發工具集Binutils。Binutils工具集,主要是用於在程式碼除錯的時候,定位bug的一些手段。我們主要學習以下幾個工具的使用:

在這裡插入圖片描述

本篇文章先學習使用addr2line與strip工具。

1、addr2line工具

首先我們要知道,gcc編譯程式的時候,加上-g選項,表示在目標檔案中生成除錯資訊。幾乎所有除錯輔助工具,都依賴於程式的除錯資訊。

addr2line工具。顧名思義,可以將地址轉換為行號。它常用於分析定位記憶體訪問錯誤的問題。以實際例子為例:

test.c程式

#include <stdio.h>

int g_global = 0;
int g_test = 1;

extern int* g_pointer;
extern void func();

int main(int argc, char *argv[])
{
    printf("&g_global = %p\n", &g_global);
    printf("&g_test = %p\n", &g_test);
    printf("&g_pointer = %p\n", &g_pointer);
    printf("g_pointer = %p\n", g_pointer);
    printf("&func = %p\n", &func);
    printf("&main = %p\n", &main);
    
    func();
	
    return 0;
}
複製程式碼

func.c程式

#include <stdio.h>

int* g_pointer;

void func()
{
	*g_pointer = (int)"D.T.Software";

    return;
}
複製程式碼

我們在linux下編譯以下程式(注意我使用gcc-4.4.5版本編譯沒有警告顯示。但是使用較高版本的gcc編譯器,可能會有警告。這裡我們忽略警告):

  • gcc -g func.c test.c -o lyy

執行程式

  • ./lyy

顯示結果為:

在這裡插入圖片描述

其實結果也在意料之中。我們分析程式很容易知道,func函式中 *g_pointer = (int)"D.T.Software"; 這句話,使得在0地址賦值了。因為int* g_pointer;只是定義了g_pointer卻沒有賦值,那麼g_pointer實際上一開始是指向0地址,後面又對它進行賦值。相當於對0地址進行操作。

但是我們知道0地址,是不能被操作的。所以會產生段錯誤。這個程式很短,問題我們很容易發現。但是如果這個歌程式有一千行,一萬行的話,那麼問題就很難定位到。此時addr2line工具就能夠上場。

下面來說明如何使用addr2line工具。

  1. 首先開啟core dump選項。使用命令ulimit -c unlimited。開啟這個選項後,在執行可執行程式的時候,會將程式崩潰前最後一刻的記憶體狀態資訊,轉儲(儲存)到一個core檔案。這個檔案叫做核心轉儲檔案。我們可以通過讀取該檔案,獲取一些用於除錯的資訊。

    在這裡插入圖片描述

  2. 開啟core dump選項後,再次執行可執行程式,來生成core檔案。

在這裡插入圖片描述

我們可以看到,段錯誤後面顯示核心已轉儲。此時檢視當前目錄的話,就可以看到core檔案。

在這裡插入圖片描述

  1. 讀取core檔案,獲取IP暫存器的值(IP暫存器存的是當前CPU所要執行指令的值,程式崩潰前最後一刻的IP暫存器的值,就是崩潰的指令地址)。使用dmesg core 命令讀取core檔案的內容,顯示內容最後部分如下:

在這裡插入圖片描述

可以看到,最後一刻IP暫存器的值為0x080483d1.出問題的程式碼就在這個地址處。但是我們無法知道這個地址處到底是個啥。但是可以利用addr2line工具,將這個地址轉換為程式碼中對應的行號。

  1. 使用addr2line定位對應的程式碼行。使用命令:addr2line 0x080483d1 -f -e lyy

在這裡插入圖片描述

很明顯,已經找打原因,是func.c程式的第7行。當從兩萬行大程式碼中找到這個錯誤,也是很激動的!!!

2、strip工具

實際上,addr2line能夠正常工作,必須依賴於程式的除錯資訊。而我們在編譯程式的時候,也確實讓程式生成了除錯資訊。如上編譯的時候帶的-g選項。

當可執行程式裡面帶有大量的除錯資訊,會導致可執行程式,非常的大。如果在大型的軟體中,軟體在釋出之前,肯定是要將這些除錯資訊去掉,好讓釋出出去的程式佔用記憶體空間更小,不然程式太大,對使用者來說也是非常不友好的。

其實這就是所謂的release版本的程式。在釋出之前,還需要除錯的程式,我們稱為debug版本程式。

那麼如何剔除除錯資訊?使用strip工具!如下圖是release版本的程式大小為9074:

在這裡插入圖片描述

使用strip將除錯資訊剔除後大小為5512:

在這裡插入圖片描述

結果顯而易見!!!

還有其他工具,放在下一篇文章學習!!!

3、總結

  • addr2line用於將程式碼地址轉換為對應的行號。常用於定位記憶體訪問錯誤的問題
  • 理解core dump選項。
  • strip可以剔除目標程式中的除錯資訊,從而可以減小目的碼的大小,提升目標程式的執行效率。
  • 學會使用上述兩個工具。

相關文章