|
返無 |
在開發 uefi os loader 時, 遇到了一個詭異問題, crt0_x86_64_efi.S _start 會 call _relocate() 做 relocation, 這時候只要在 gcc 8/5 用 -O0 就會發生錯誤, 我用上了 gdb + qemu 在執行時期追組合語言, 查閱 stack/register, 終於讓我找到為什麼?
問題出在 crt0_x86_64_efi.S L29, 只要呼叫了 _relocate 之後, crt0_x86_64_efi.S L31, L32 pop 回來的值不會是之前 push 的, 我一直搞不懂為什麼, 起先還以為是爆 stack, 不過看起來不是, rsp 在 _relocate 之前之後, 會回到原來的值。
後來簡化到 _relocate 是空的也會發生, 真是奇怪了, 最後查看反組譯之後的組合語言, 終於理解了。-O0 會
生成 (我不太喜歡這辭, 詞語不太順口) 輸出 list 1 的組合語言; -Os, -O1 就不會。list 1 L1, L2 %rcx, %rdx 的值直接填在 stack, 這個位址剛好是 crt0_x86_64_efi.S L23, L24 push 進去的值, 所以就 pop 不回原來的值, 而 %rdx 是 system table, 所以只要用到 system table 的程式碼, 一律掛掉。後來用了 list 2 的方法, push/pop 4 次, 避開這樣的問題, 如此一來 -O0 也可以正常執行。
這問題其實蠻棘手的, 如果一開始就可以看到反組譯的結果, 那就很順利, 可惜運氣不再這邊, 花了許多時間, 才找到這問題。期間也讓我對於 gdb + qemu 的除錯方式更加理解, 讓我得到 ice 等級的除錯利器。
沒有留言:
張貼留言
使用 google 的 reCAPTCHA 驗證碼, 總算可以輕鬆留言了。
我實在受不了 spam 了, 又不想讓大家的眼睛花掉, 只好放棄匿名留言。這是沒辦法中的辦法了。留言的朋友需要有 google 帳號。