ARM(S3C2440 )下解決的非法指令問題(Illegal instruction)

最近在學習和做項目的時候需要搭建s3c2440的環境,遇到了一些問題(非法指令)和大家分享一下修正錯誤的過程。

一、我先介紹一下我們的實驗環境:
內核版本:kernel-2.6.27-android_ok
編繹器:arm-2010q1-202-arm-none-linux-gnueabi
硬件:(S3C2440) 支持armv4t 指令,
busybox版本:busybox-1.17.0

我們這次實驗的kernel相對來說版本不算老,編譯可就是非常新的了。
他支持ARMV7,就是cortex-A8,A9系列的。
而我們的硬件s3c2440 只有armv4t的指令集。

二、問題的出現:
我們用新的編譯器編譯出來的uboot,kernel均能正常執行。
當我們用它來編譯busybox,並且生成靜態busybox的時候,有時候執行正常,
有時候執行就不正常。不正常的時候出現如下提示:
Illegal instruction
這個錯誤表明我們的程序執行了不正確的指令。
一般這種情況是因爲我們編譯起編譯出了較高版本的ARM指令造成的。

三、排錯
排錯1:讓編譯器編譯出支持s3c2440 的armv4t,在網絡上查詢得知增加 “-march=armv4t”選項即可。

於是在busybox make menuconfig 中編譯選項中加入了上述參數,見下圖



增加 -march=armv4t



殘酷的事實驗證後,結果發現還是不行。

這是爲什麼,我們該怎麼做?有兩個問題困擾着我:
1.出現的非法指令是在哪,是什麼指令?
2.所加入的參數到底有沒有起作用?

排錯二:
現來尋找上述第一個問題的答案,
由於在交叉編譯過程中產生了非法指令,故在執行過程中會產生異常,我們進入到內核的非法指令異常去看看。
於是到內核 (arch/arm/kernel/traps.c) 中找到相關的異常處理函數(do_undefinstr)  
其中部分代碼爲:
#ifdef CONFIG_DEBUG_USER    
    if (user_debug & UDBG_UNDEFINED)
   {       
       printk(KERN_INFO "%s (%d): undefined instruction: pc=%p\n",    current->comm,   
                task_pid_nr(current), pc);       
       dump_instr(regs);    
   }
#endif

通過上面的代碼我們如果
CONFIG_DEBUG_USER 定義了,並且user_debug設置了參數,應該可以看到系統打印是哪個程序產生了異常。
通過kernel的.config文件發現 CONFIG_DEBUG_USER已經定義了。
user_debug是一個命令行參數。

好了我們可以通過uboot打開:
打開的方法爲在U-boot bootargs 添加 user_debug=1;
(egs: setenv bootargs console=ttySAC0,115200 user_debug=1   saveenv    );

在LINUX再次執行程序,發現在原先的出現“指令錯誤”的上方多出了兩條具體的錯誤信息。


打印出非法指令信息

以上圖片中,是執行mdev(mdev,是busybox的子程序)時出錯。 pc=000ca8b4,是指mdev的ca8b4處有個非法指令。


接下來從busybox中找出次指令:
進入busybox目錄 ,輸入命令(arm-none-linux-gnueabi-objdump -D busybox > bu.S 意思爲將生的目標文件的彙編代碼dump 到 bu.S 文件中) ,
打開bu.S(命令:vim bu.S) 文件,根據出現“指令錯誤”上面兩條具體指令錯誤位置信息可以找到非法指令指置,我們查到該位置爲clz指令:
在ARM官方網上息查詢得知clz指令相關信息:(http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0204ic/Cihjgjed.html

clz 指令體系結構:
此 ARM 指令可用於 ARMv5 及更高版本。
此 32 位 Thumb 指令可用於 ARMv6T2 及更高版本。
此指令無 16 位 Thumb 版本。

我們最終找到出現非法指令的位置,以及是什麼指令。

好,接下來,我們需要第二步,回到busybox本身:

我們想把編譯過程中的參數給打印出來,通過查看busybox中的Makefile,得知由quiet_決定,我們在編譯busybox時加入選項參數V=1(egs: make V=1);

通過編譯過程所打印的信息知所加的選項參數在編譯的時候起了作用,但在鏈接生成靜態庫的時候並沒有起到作用。

雖然知道在make menuconfig 加了相關參數(-march=armv4t),編譯器並沒有去執行這條語句,可能的原因是:我們所加的參數的格式不正確,或其它原因等)。於是我們就想找一種能解決此問題的方法。下面給出一種針對上述問題的解決的方案:
爲了以防萬一,我們手動將編譯鏈接的地方都增加了 (-march=armv4t )

我們可在busybox 中的Makefile.flags 中找到靜態鏈接的位置以及編譯的位置:
將:
ifeq ($(CONFIG_STATIC),y)CFLAGS_busybox += -static
endif修改爲:
ifeq ($(CONFIG_STATIC),y)CFLAGS_busybox += -static -march=armv4t
endif

將:
CPPFLAGS += $(call cc-option,-std=gnu99,)
修改爲:CPPFLAGS += $(call cc-option,-std=gnu99 -march=armv4t,)

再進行編譯就生成了我們所需指令版本的目標文件了。

相關軟件下載地址:交叉編譯器:arm-2010q1-202-arm-none-linux-gnueabi下載地址:
http://www.codesourcery.com/sgpp/lite/arm/portal/release1293   具體爲Recommended Packagesbusybox-1.17.0下載地址:http://www.busybox.net/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章