開發嵌入式軟體通常是比較麻煩的事,一些常用的工具往往無法使用,在開發pc軟體時簡單的任務,此時變得很複雜。今天就遇到了這樣一件事,折騰了幾個小時,僅僅是為知道call stack。
我編譯了乙個程式放到pda(arm9+linux+uclibc)上面執行,出現了乙個assert,並顯示了檔名和行號,原來是呼叫了乙個沒有實現的函式,我很想知道是誰呼叫了它,這看似簡單的問題卻讓我很頭疼,如果有gdb,那好辦-用bt命令就可以搞定,如果用的libc,那也好辦-用backtrace函式就可以搞定,問題是兩者都沒有。
想來想去只有自己寫乙個backtrace,要實現這個功能並不難,如果我們知道呼叫堆疊的格式,就可以很容易取出上層呼叫者的指令位址,有了這些上層呼叫者的指令位址,我們可以通過map檔案找到指令位址對應的源檔名和行號。
下面簡要介紹一下實現原理:
要獲得呼叫者的位址,有必要介紹一下堆疊的格式:
+---------------------------+ (高位址)
+_引數1__________+
+---------------------------+
+_引數2__________+
+---------------------------+ 引數的順序依賴於呼叫方式
+_引數.__________+
+---------------------------+
+_引數n__________+
+---------------------------+
+_eip____________+ 返回本次呼叫後,下一條指令的位址
+----------------------------+
+_ebp____________+ 這裡儲存的呼叫者的ebp
+----------------------------+
(ebp 指向這裡:相當於呼叫者和被呼叫者的分界線)
+----------------------------+
+_臨時變數1_______+
+----------------------------+
+_臨時變數2_______+
+----------------------------+
+_臨時變數.________+
+----------------------------+
+----------------------------+
+_臨時變數n_______+
+----------------------------+(低位址)
由於優化、呼叫方式、編譯器的不同,上述布局部可能有所不同,但一般來說,第乙個區域性變數前是呼叫者的ebp,ebp前是返回後下一條指令的位址。
知道了這個結構,要獲得上層呼叫的者指令位址就容易了,我們可以用如下**模擬glibc提供的backtrace的功能:
int backtrace (void **buffer, int size)
return size;}附:
通過addr2line可以找到位址對應的檔名和行號,不用手動去查map檔案了。
誰在CALL我 callstack的實現原理
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!開發嵌入式軟體通常是比較麻煩的事,一些常用的工具往往無法使用,在開發pc軟體時簡單的任務,此時變得很複雜。今天就遇到了這樣一件事,折騰了幾個小時,僅僅是為知道call stack。我編譯了乙個程式放到pda arm9 linux uclibc 上面...
誰在CALL我 callstack的實現原理
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!開發嵌入式軟體通常是比較麻煩的事,一些常用的工具往往無法使用,在開發pc軟體時簡單的任務,此時變得很複雜。今天就遇到了這樣一件事,折騰了幾個小時,僅僅是為知道call stack。我編譯了乙個程式放到pda arm9 linux uclibc 上面...
我所理解的call和apply
一 先來看看示例 這兩個方法的用途都在特定的作用域中呼叫函式,實際上等於設定函式體內this物件的值。例一 123 4567 891011 1213 1415 function box num1,num2 function sum num1,num2 alert sum 10,10 function...