作者:paradoxfx 來(lái)源:電子產(chǎn)品世界 在我們有關(guān)DSP的論壇、博客和一些互動(dòng)活動(dòng)中,網(wǎng)友經(jīng)常會(huì )問(wèn)一些有關(guān)“編程技巧”的問(wèn)題。 關(guān)于編程技巧的定義,也沒(méi)有一個(gè)統一的標準,例如實(shí)現一個(gè)很復雜的多層嵌套的指針設計算是一種編程熟練的體現吧;又或者用C/C++的高級特性做了很復雜的功能,但是編譯器不能完全支持,例如某種內存的動(dòng)態(tài)重分配方法,這時(shí)對編譯器特性的熟悉就顯得很重要了。 接下來(lái)我們就聊一聊DSP編程技巧里面有關(guān)編譯技巧的一些問(wèn)題,具體的分類(lèi)包括編譯器的選項、代碼的優(yōu)化、庫文件的使用、代碼實(shí)現標準、實(shí)時(shí)運行環(huán)境等等;了解了這些具體的問(wèn)題,對于解決在編譯和鏈接程序的時(shí)候經(jīng)常遇到的讓人摸不著(zhù)頭腦的警告和錯誤也是很有幫助的;因為程序的語(yǔ)法錯誤很容易被編譯器發(fā)現并定位到具體的代碼中,而鏈接器輸出的那些莫名其妙的警告是很難定位的,如果理解了編譯流程中各個(gè)環(huán)節的作用所在,就有了對癥下藥的入口。編譯器主要以TI的CCS編譯器為例,目標器件為28系列,相比6000系列的,28系列的要稍微簡(jiǎn)單一些。 首先要了解一下基于CCS開(kāi)發(fā)的一個(gè)完整流程,以免“只見(jiàn)樹(shù)木,不見(jiàn)森林”: ![]() 因為很少有文檔把它們的具體漢語(yǔ)含義講清楚,所以在此我們要用通俗的語(yǔ)言描述一下各個(gè)部分: 1. 在這個(gè)流程中,與我們編程效率直接相關(guān)的就是C/C++編譯器了(如果沒(méi)有使用匯編直接編寫(xiě)的話(huà)),它的直接用途是將C/C++代碼編譯為針對DSP匯編指令集的匯編代碼。 目前的C和C++語(yǔ)言標準有好幾個(gè)版本,CCS的編譯器目前支持的版本包括: C語(yǔ)言的C89和C99版本的ISO標準(C99部分支持,主要是與C89一樣的特性):通俗的講就是我們學(xué)過(guò)的C語(yǔ)言里常用的功能都是支持的,除了一些多字節字符和一些極少數的特性等。不清楚的可以參考Kernighan和Ritchie編寫(xiě)的C語(yǔ)言書(shū)籍《The C Programming Language》第二版。 C++語(yǔ)言的2003版本的的ISO標準: 可以參考Ellis和Stroustrup編寫(xiě)的經(jīng)典書(shū)籍《The Annotated C++ Reference Manual》。同時(shí)也支持一部分的嵌入式C++特性。因為C++的特性眾多,而許多并不適用于這樣一種嵌入式的環(huán)境,所以不支持的特性相比C要多一些。 2. 匯編器的作用是將匯編語(yǔ)言代碼轉換為機器語(yǔ)言(目標文件),這里的匯編代碼包括前面由C/C++生成的匯編代碼和我們直接編寫(xiě)的匯編代碼。 3. 鏈接器是作用是把所有的庫文件、目標文件等鏈接成為一個(gè)可執行的目標文件,其中包含程序的機器代碼和數據,以及其他用來(lái)鏈接和加載該程序所需的信息(在TI DSP上是COFF格式,通俗地講就是.out二進(jìn)制文件),同時(shí)根據內存地址的分配對各目標文件進(jìn)行重定位,并解析外部參考,例如在一個(gè)源程序里引用另一個(gè)源程序中定義的變量就可以理解為外部參考,假如一個(gè)目標文件引用了一個(gè)未定義的符號symbol,則鏈接器搜索其他目標文件中定義的全局符號,找到匹配的符號修補指令。否則報告一個(gè)錯誤;所以有時(shí)候編譯所有程序完成在鏈接的時(shí)候會(huì )提示xxx symbol為定義,說(shuō)明對應的文件沒(méi)有加到工程里面。 4. 歸檔器archiver:也可以叫壓縮器,看一下我們常用的壓縮軟件winrar的全稱(chēng)winrar archiver就不難理解了。 5. 實(shí)時(shí)支持庫:包括標準C和C++的運行支持函數、編譯器公用程序函數、浮點(diǎn)運算函數和C編譯器支持的I/O函數, 6. 十六進(jìn)制轉換程序:把編譯、鏈接等步驟生成的可執行文件,轉換為十六進(jìn)制文件,例如.HEX格式,然后可以燒寫(xiě)到EEPROM、FLASH等外部存儲器之中。 7. 絕對列表器:讀取目標文件并輸出.abs文件,通過(guò)匯編.abs文件可產(chǎn)生含有絕對地址的列表文件,從而使得我們不用手工費時(shí)費力地去創(chuàng )建列表文件。這本來(lái)不就是軟件該做的事情嗎:-D 8. 交叉引用列表:與3中外部參考解析相關(guān)的,它用目標文件產(chǎn)生參照列表文件,可顯示符號及其定義,以及符號所在的源文件。 9. C/C++命名還原工具:C/C++編譯器會(huì )將程序中的變量名、函數名轉換成內部名稱(chēng),這個(gè)過(guò)程被稱(chēng)作Name Mangling,反過(guò)程被稱(chēng)作Name Demangling,即命名還原工具。內部名稱(chēng)包含了變量或函數的更多信息,例如編譯器看到?g_var@@3HA,就知道這是:int g_var。具體的還原規則一般是不開(kāi)放給我們用戶(hù)的,只要編譯器知道就行了。 10. 調試工具:例如我們電腦上裝的CCS軟件,讓我們可以用斷點(diǎn)、圖形窗口等進(jìn)行軟件的調試。 此外,并沒(méi)有明確列在前面的流程中,但是隱含在流程中,或者我們也有可能會(huì )用到的工具或者流程包括: 1. 優(yōu)化工具:在編譯時(shí)對代碼進(jìn)行優(yōu)化的工具,可以根據我們期望的優(yōu)化級別,進(jìn)行從不優(yōu)化到直至CPU寄存器級別的優(yōu)化。 2. 反編譯器:可以對目標文件進(jìn)行解碼,顯示對應的匯編語(yǔ)言。在CCS的調試模式下,我們可以打開(kāi)disassembler窗口,然后單步運行,就能看到一條條的匯編指令是如何執行的了。 3. 加載器:把可執行的二進(jìn)制文件復制到DSP的內存中,并運行啟動(dòng)程序,使得程序從程序入口處開(kāi)始運行,這個(gè)入口地址可能是地址0,也可能是帶有一個(gè)偏移量的地址,這個(gè)具體的值我們可以以后再具體討論。 4. 其它:補充一下名詞的定義,包括: 符號:在整個(gè)編譯、鏈接的過(guò)程中都會(huì )使用到符號symbol的概念,簡(jiǎn)單地理解,符號就是指一些變量、函數名字等。 庫文件:多個(gè)目標文件的壓縮包,包含了所有目標文件定義的全局符號的索引。在源程序中如果找不到某些符號的定義,鏈接器從嘗試從庫里面提取出對應的目標文件,然后鏈接到可執行文件里。 |