2013-07-25 57 views
3

我正在嘗試獲取內核函數的邊界(例如系統調用)。現在,如果我理解正確,我可以通過閱讀/proc/kallsymsSystem.map得到感興趣的函數的起始地址,但我不知道如何獲得此函數的結束地址。在運行時獲取Linux內核函數的結束地址

正如您所知,/proc/kallsyms允許我們查看Linux內核的符號表,因此我們可以看到所有導出符號的起始地址。我們可以使用下一個函數的起始地址來計算前一個函數的結束地址嗎?如果我們不能這樣做,你能否以另一種方式給我建議?

+0

爲什麼你需要知道函數的「結束地址」? –

+1

我需要知道它,因爲我想在運行時執行「函數內聯」。之後,我可以構建控制流圖,其中包含感興趣的功能的基本塊及其所有被調用者。 – user2571676

回答

1

通常,可執行文件僅存儲函數的起始地址,因爲它只是調用該函數所需的全部內容。你將不得不推斷最終地址,而不是簡單地查看它。

您可以嘗試查找後續函數的起始地址,但這並不總是有效。想象一下以下內容:

void func_a() { 
    // do something 
} 

static void helper_function() { 
    // do something else 
} 

void func_b() { 
    // ... 
    helper_function(); 
    // ... 
} 

你可以得到的func_afunc_b,但helper_function地址不會出現,因爲沒有什麼需要鏈接到它。如果您試圖使用func_b作爲func_a的末尾(假設編譯代碼中的順序等價於源代碼中的順序,但不能保證),那麼最終會意外地包含您不需要的代碼包括 - 並且在將其他函數內聯到func_b時可能找不到需要查找的代碼。

那麼,我們如何找到這些信息呢?那麼,如果你仔細想想 - 確實存在的信息 - func_a中的所有路徑最終都會終止(在循環中,返回語句,尾部調用等),可能在helper_function開始之前。

您需要解析出func_a的代碼並構建其中所有可能代碼路徑的映射。當然,無論如何你都需要這樣做,以將其他功能嵌入其中 - 所以不應該太難以簡單地不關心該函數的結束地址。

最後一個注意事項:在這個例子中,如果找到helper_function以便知道將它內聯,將會遇到問題,因爲符號不會顯示在kallsyms中。這裏的解決方案是,您可以跟蹤單個函數中的call指令,以確定您不知道的其他隱藏函數。

TL; DR:您只能通過解析編譯後的代碼來找到結束地址。無論如何你必須解析這個,所以只需要做一次。

相關問題