Re: [問題] Linux - Alignmet trap

看板C_and_CPP作者 (小風)時間14年前 (2009/12/05 21:21), 編輯推噓7(701)
留言8則, 8人參與, 最新討論串4/4 (看更多)
※ 引述《eleghost (徵求12/5五月天DNA門票!!)》之銘言: : 請教一下PC的意思, PC是"CPU下一步要執行的工作,便是PC內容所指的位置" : 那我用 nm 這個指令將執行檔(binary code)的變數與function的位址列出 : 然後在對應到PC的值, 這樣為什麼不能解釋為說 "當CPU正要執行此函式時, : 而產生了 Alignment trap?", 謝謝! PC (Program Counter) 的意思和你所描述的意義是符合的, 但是在 debug 時, 望著 PC 的值, 很多時候, 卻不能告訴你問題發生的地方. 為什麼呢? 請耐心往下看. 先稍微介紹一下程式執行時的 memory layout. +---------+ .text: 此區域用來存放每一行程式碼所編譯後產生的 PC → | .text | machine instruction, PC 會在這個區域內, +---------+ 指向下一個要執行之 instruction 的位址. | .data | .data: 全域變數 +---------+ .bss: 在編譯時未給初值的全域變數. (例: int a;) | .bss | heap: malloc或new時配置出的記憶體, 會一直向下 +---------+ 遞增. | heap | stack:堆疊, SP(Stack Pointer) 在此區域活動. 其 +---------+ 頂端為 stack segment 的底部, 配置時向上 | ↓ | 延伸, 比如說, 配置了 8 bytes 的 stack 時, | unused | SP 的值會減 8. | ↑ | +---------+ SP → | stack | +---------+ ARM 的 PC 暫存器, 和 x86 的 EIP (Instruction Pointer) 是一樣的功能, 主要是 用來指向要執行的 instruction 位置, 因此, 大都會在 .text 這個區域裡活動. 接下來, 我們來看一下, 當一個函式被呼叫時, PC (Program Counter) 做了什 麼事? 以最簡單的例子說明, 00 #include <stdio.h> 01 02 void func1() { 03 printf("I am function 1\n"); 04 } 05 06 void func2() { 07 printf("I am function 2\n"); 08 func1(); 09 } 10 11 int main() { 12 func2(); 13 return 0; 14 } a. 在 12 行, func2() 被呼叫時, 參數(此例沒有傳入參數) 和 return address(即 .text 裡 13 行被編譯後的 instruction 位址) 堆入堆疊. b. 接著, 把 PC 指向 func2() 所在的位址, 並執行 07 行. c. PC 執行到 08 行, 準備呼叫 func1() d. return address (09 行) 堆入堆疊後, PC 指向 func1() 每一個 function call 發生時, 就會產生一個新的 stack frame (或稱為 call stack), 而每個 stack frame 的位址叫做 frame pointer (簡稱 FP). FP 也會被存在 stack frame 裡, 例如上例這樣呼叫後, 會產生以下的 stack frame, libc main() func2() func1() +----------+ +----------+ +----------+ FP <----+ FP <-------+ FP <-------+ FP | +----------+ +----------+ +----------+ | ret addr | | ret addr | | ret addr | +----------+ +----------+ +----------+ | .... | | .... | | .... | | .... | | .... | | .... | 在 x86 上, FP 會存在 EBP 這個暫存器裡. 而 FP 總是指向上一個 stack frame 的 開頭. 待 func1() 返回時, PC 會存入最上圖最右邊的 ret addr (這個位址其實是 func2() 呼叫 func1() 之前所預存, 程式碼第 09 行的位址), 於是 func1 的 stack frame 接著就被釋放, 再來 func2() 也返回了, PC 指向其預存的 ret addr (14 行的位址), 釋放 func2 的 stack frame, 以此類推. 我們的程式, 雖然用 C/C++ 寫成, 但是 C/C++ 的 library 也有很多底層函式, 一個 printf() 後面, 也有很多函式呼叫, 並且產生上述的 stack frame, 然而, 當 kernel 告訴你一個問題發生時的 PC 值時, PC 雖然停在有問題的地方, 但是那個地方, 你 並不一定擁用 debug symbol. 因此, 在利用 addr2line 解析時, 經常無法從那個位 址取得 function name. 反而, 要用 Frame Pointer 上推數層後, 才能找出真正有問 題的地方. 舉個例子來說, 有一個程式呼叫了很多 memcpy, 其中一處發生了 Segmentation Fault. 而 PC 指向 memcpy() 裡的一個地方, 從 PC 的值來判斷時, 或許你有辦法知道問題大 概是出在 memcpy(), 但是卻無法得知是誰, 在哪裡, 用什麼參數呼叫了 memcpy(). 顯 然的, memcpy() 裡寫的 code 也沒有問題, 問題可能出現在呼叫 memcpy 時, 給了不 正確的參數. 這也就是為什麼 PC 常常無法告訴你問題發生的確切位置. 要用 backtrace 來追蹤 stack frame 的內容. -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 118.171.76.172 ※ 編輯: phterry 來自: 118.171.76.172 (12/05 21:23) ※ 編輯: phterry 來自: 118.171.76.172 (12/05 21:30)

12/05 21:58, , 1F
用力推~~~~~~~~~~~~
12/05 21:58, 1F

12/06 01:10, , 2F
12/06 01:10, 2F

12/06 14:01, , 3F
推~~~ 辛苦了
12/06 14:01, 3F

12/06 23:00, , 4F
光看到畫圖就要推了
12/06 23:00, 4F

12/06 23:01, , 5F
推詳細解說!!
12/06 23:01, 5F

12/06 23:19, , 6F
很詳細
12/06 23:19, 6F

12/07 08:37, , 7F
太深了, 要印出來看了!! 大推!!
12/07 08:37, 7F

12/08 23:01, , 8F
真是上了一課 !!
12/08 23:01, 8F
文章代碼(AID): #1B6bv23x (C_and_CPP)
文章代碼(AID): #1B6bv23x (C_and_CPP)