【開發(fā)經(jīng)驗】關(guān)于ARMV6編譯器-O0優(yōu)化不能進(jìn)main的解決方案
最近使用keil 的ARMV6編譯器的開發(fā)項目的時候遇到了這樣一個問題——使用-O0優(yōu)化時候復(fù)位單片機程序直接卡死(感覺根本沒有執(zhí)行),使用除-O0優(yōu)化外的選項全都能通過。

打開仿真之后程序直接卡在了 BKPT 0xAB

一般出現(xiàn)這種問題,根據(jù)以往經(jīng)驗可能是程序中使用了標(biāo)準(zhǔn)輸入輸出函數(shù),例如?printf??格式化輸出,所以打開了編譯器提供的標(biāo)注輸入輸出的補丁,即使用printf 等函數(shù)之后函數(shù)會直接返回,而不是進(jìn)入一個斷點 BKPT 0xAB

在程序中使用printf 也能正確返回。


可以看到執(zhí)行 printf 時候直接返回了。但是問題并沒有解決,程序依然卡在 BKPT?0xAB。
那肯定不是標(biāo)準(zhǔn)輸入輸出的問題。在網(wǎng)上搜索一圈之后,百度的答案是 “換ARMV5 編譯器”。。。你猜猜看我為啥要用AC6,給你邦邦兩拳(開玩笑啦)。而谷歌的答案更是不知所云,只好繼續(xù)自己想辦法。
當(dāng)我勾選微庫之后,這個問題居然解決了。。。

當(dāng)然你可以看到,一旦勾選微庫,keil會提醒你微庫和C++不兼容。因為我編寫的是C++項目,所以堅決不能使用微庫,因此放棄了這個想法。
這時候發(fā)下堆棧中有兩個函數(shù)調(diào)用_ARM_get_argv 和 _sys_command_string?

_sys_command_string 正是斷點位置,這兩個函數(shù)一定是編譯器自動生成并鏈接的,因為我們并沒有編寫這兩個函數(shù),關(guān)于編譯器相關(guān)的東西 help一般都有解釋,于是我打開了help 搜索 _sys_command_string

搜索結(jié)果中的第三條,解釋了 在不同編譯器優(yōu)化等級的區(qū)別,其中提到了:
? ?“?如果你的main函數(shù)是不帶參數(shù)的,編譯器會應(yīng)用一些特定的優(yōu)化,針對ARMV5編譯器的所有優(yōu)化等級,而ARMV6只針對-O0之外的優(yōu)化等級”
Note的第四段話給出了解決方法

因此我們建立一個名為armv6O0fix.c的文件,添加以下代碼:

要么你定義一個_sys_command_string?函數(shù)里面什么都不干,函數(shù)原型是help搜到的。要么按照help里提的,鏈接一個空的匯編函數(shù),你寫個void?__ARM_use_no_argv(void){} 應(yīng)該也是可以的。個人建議定義一個?_sys_command_string 函數(shù),因為如果你定義了__ARM_use_no_argv而選擇了非ARMV5或ARMV6 -OO優(yōu)化以外的選項,則會和編譯器自動生成的函數(shù)發(fā)生沖突。且_asm匯編只適用于ARMV6。而?_sys_command_string可以完美應(yīng)用于ARMV5和V6編譯器所有優(yōu)化選項。
至此問題解決!