真誇張:最後是 這一篇 王聰 先生的blog : __umoddi3()的問題 有比較清楚的說明: (copy 一下,以免消失.. 對不起)busybox -- qemu boot with preload kernel -- ref jserv's tutorial -- build kernel fail -- workaround on CFLAG -- GCC 4.3 problem -- GCC 4.3 optimize functions -- example test code
繞了好大一圈,已經離 busybox 很遠了..
以下 copy 自 王聰 先生的 blog 文章:
===========================================================
在編譯內核時有人遇到下面這個問題: kernel/built-in.o: In function `getnstimeofday': (.text+0xb6ae): undefined reference to `__umoddi3' kernel/built-in.o: In function `getnstimeofday': (.text+0xb6ce): undefined reference to `__udivdi3' 這個問題可以在用戶空間重現,不過不是很容易,我實驗了一下,在i386上,並不是所有的64位整數操作都會被轉化成 調用__umoddi3,gcc bugzilla上有演示程序,如下: PLAIN TEXT C: 1.#define NSEC_PER_SEC 1000000000UL 2.int rmg(void); 3. 4.int main(void) 5.{ 6. /* int sec; */ 7. return rmg(); 8.} 9. 10.int rmg(void) 11.{ 12. static unsigned long long nsec = 0; 13. static int sec = 0; 14. while (sec <1 ) { 15. nsec++; 16. while (__builtin_expect(nsec>= NSEC_PER_SEC, 0)) { 17. nsec -= NSEC_PER_SEC; 18. ++sec; 19. } 20. } 21. return sec; 22.} 這樣編譯它:% gcc -nostdlib -O2 -o umoddi3 umoddi3.c,就會得到: /tmp/ccycM684.o: In function `rmg': umoddi3.c:(.text+0x87): undefined reference to `__udivdi3' collect2: ld returned 1 exit status 問題重現了。這裡的問題是,對於nsec來說,內層的循環其實等價於求模運算,gcc在優化時發現了這一點,而且硬件 本身也不支持對64位整數直接進行算術運算,所以gcc會把這一步優化成調用內部函數__udivdi3()和 __umoddi3(),這兩個函數在libgcc中(見gcc源代碼 gcc/libgcc2.c),libgcc默認和libc一樣是要被加載 的,但如果我們加了-nostdlib(Linux內核是更好的例子),這個問題就會出現了。 知道原因了,怎麼解決?網上有兩種方法,一種是像這個補丁那樣,在循環中插入下面這條內聯彙編: asm("" : "+r"(ns)); 這句是告訴gcc把ns這個變量放到寄存器中,並且既有讀操作也有寫操作,所以後面再用它時必須重新讀取,這樣就消 除了上面的優化。 另一種解決方法是添加新的編譯選項:-fno-tree-scev-cprop,這個選項似乎沒有文檔,至少我沒找到。說說它的 大體意思。scev 應該是SCalar EVolutions,什麼意思不知道。:( cprop應該是Copy PROPagation,這個應 該很容易理解,就是賦值的傳播,比如: i = 10; a = i; b = i; 其實就是: a = 10; b = 10; 可見,編譯優化是門大學問,寫個編譯器絲毫不比寫個內核容易。:-P============王聰先生的文章copy到此==============
沒有留言:
張貼留言