DSP編程技巧之34---答疑解惑哪家強之(9)
答疑解惑哪家強?當屬我們EEPW最強。。。接下來(lái)繼續我們的答疑解惑系列。
本文引用地址:http://dyxdggzs.com/article/267884.htm58. 為什么一個(gè)看起來(lái)很簡(jiǎn)單的程序,鏈接的時(shí)候卻要花費很長(cháng)的時(shí)間?
導致這種現象的最主要的原因是類(lèi)型合并(type merging)。那什么是類(lèi)型合并呢?舉個(gè)簡(jiǎn)單的例子,在頭文件types.h中定義了結構sss,且所有的.c中中都引用了這個(gè)types.h。因此在編譯之后,描述sss的調試類(lèi)型信息被包含到每個(gè)目標文件之中(除非使用了--symdebug:none來(lái)禁用調試信息),因此在鏈接的時(shí)候,鏈接器會(huì )發(fā)現有很多個(gè)sss類(lèi)型的副本;默認情況下,鏈接器使用類(lèi)型合并把這么多sss類(lèi)型合并為一個(gè),從而使得最終輸出的.out文件中只有一個(gè)sss類(lèi)型,而不是很多個(gè)重復的副本,達到減小代碼尺寸的目的,并且使得CCS在加載.out文件時(shí)也會(huì )花費更少的時(shí)間。然后,類(lèi)型合并這個(gè)過(guò)程中需要大量的計算,因此導致了鏈接看起來(lái)需要花費很長(cháng)的時(shí)間。
解決的方法有兩個(gè):
1. 禁用類(lèi)型合并:使用鏈接器的-b選項(含義請參考http://dyxdggzs.com/article/249328.htm)。這樣做的結果是鏈接的時(shí)間變短,但是.out文件變大,需要更長(cháng)的時(shí)間來(lái)加載;如果在這個(gè)例子中sss的副本非常多,有可能需要很差的時(shí)間來(lái)加載.out文件。
2. 使用--symdebug:none選項來(lái)完全禁止把調試信息寫(xiě)入.out文件。這樣做既可以減小鏈接時(shí)間,又可以減小.out的尺寸和縮短加載時(shí)間,但后果是代碼的調試功能被大大削弱了。
59. 如何使用一個(gè).cmd文件在含有不同的內部存儲空間的芯片上來(lái)實(shí)現段的優(yōu)先級?
假設有下面的狀況:
器件1有64kb快速的內部存儲,而器件2有128kb?,F在我們有4個(gè)關(guān)鍵的代碼段:
.text:_a : 20kb
.text:_b : 30kb
.text:_c : 20kb
.text:_d : 10kb
其中段a的運算重要性最高,段b的次之,以此類(lèi)推。
給片內的快速存儲器命名為IRAM,而片外的慢速存儲器命名為SDRAM。假設在器件1上,我們必須把.text:_a和.text:_b保存在IRAM中以保證運行速度,而.text:_c和.text:_d則既可以保存在IRAM,也可以保存在SDRAM中。在器件2中,因為片上存儲顯著(zhù)增大,可以把abcd四個(gè)段都保存在SDRAM中。此時(shí)我們可以使用下面的方式,使用同一個(gè).cmd文件來(lái)完成段的分配:
這一段語(yǔ)句的作用有兩個(gè):
(1) 在分配存儲空間時(shí),按照順序來(lái)確保配段的優(yōu)先級。在.cmd文件中,如果需要保證段的優(yōu)先級,則必須使用GROUP這個(gè)指令;如果不使用則段之間不會(huì )有優(yōu)先級的關(guān)系,此時(shí)鏈接器會(huì )有效把長(cháng)度最大的那個(gè)段優(yōu)先分配空間,以最大程度地減少存儲空間中的空隙。
(2) 自動(dòng)在不相鄰的存儲空間IRAM和SDRAM中劃分輸出的段。兩個(gè)大于號“>>”也是鏈接器的內部指令,它用來(lái)表明GROUP中的段可以被劃分到不同的存儲空間里。例如,當鏈接器在器件1上,發(fā)現在分配完.text:_a和.text:_b到IRAM中之后,發(fā)現.text:_c有20kb,IRAM的空間已經(jīng)不足以存放它時(shí),它會(huì )跳過(guò)把text:_c分配到IRAM上,而是把text:_c分配到SDRAM中;接下來(lái)鏈接器會(huì )繼續嘗試把text:_d給分配到IRAM中(如果text:_d的長(cháng)度足夠小的話(huà))。而在器件2上,編譯器會(huì )發(fā)現空間足夠存放abcd四個(gè)段的時(shí)候,就把它們四個(gè)一起保存到IRAM中了。
如果我們使用下面的兩種方式,結果會(huì )是什么樣的呢?
使用這個(gè)方法仍然可以做到段的分割,即上面的第二條,然而它們之間空間分配的優(yōu)先級沒(méi)有辦法保證,很有可能使得程序的性能受到影響。
使用這個(gè)方法仍然可以做到段的優(yōu)先級,即上面的第一條,然而在器件1上這些段將無(wú)法全部保存到IRAM中,最終導致鏈接器的錯誤。。
60. 為什么需要開(kāi)啟鏈接器–w選項?
-w的含義是:在未定義的輸出段被創(chuàng )建時(shí)產(chǎn)生警告信息。因此,如果我們在程序中創(chuàng )建了段,例如:
但是在cmd文件中沒(méi)有明確段的類(lèi)型(例如.text、.bss等),則鏈接器將有可能任意地給我們自定義的段分配一個(gè)地址控制,這將導致嚴重的運行時(shí)錯誤。例如,鏈接器有可能任意地把我們自定義的段給分配為FLASH這個(gè)段類(lèi)型,但是實(shí)際上它們并不在Flash中運行,結果導致代碼完全不執行。
使用-w選項將使得鏈接器必須提示我們有關(guān)段未定義的信息,從而避免上述問(wèn)題的發(fā)生。
61. 鏈接器地址映射文件中的trampolines代表什么含義?
在鏈接之后,打開(kāi)生成的.map文件,可以查看地址映射信息,如下圖所示。
其中的TRAMPOLINES在英語(yǔ)里是“蹦床”的有意思,在這里的含義則是代表非直接跳轉的向量。它的含義與蹦床運動(dòng)是一樣的,代碼執行到trampoline之后會(huì )立刻跳轉出,或者回彈。當跳轉指令無(wú)法到達目的地時(shí),鏈接器會(huì )自動(dòng)產(chǎn)生trampoline, 然后我們就可以看到上圖所示的那些信息了,它們的含義是:
callee:函數被調用。
addr:callee的地址。
tramp:鏈接器自動(dòng)為trampoline所產(chǎn)生的名字。
addr:trampoline在存儲器中的地址。
call addr:從trampoline產(chǎn)生的調用所使用的地址列表。
call info:包含最初調用的目標文件和輸入段。如果目標文件保存在某個(gè)庫中,則會(huì )把庫文件的名字也顯示出來(lái)。
62. 在C編譯器中使用內聯(lián)的匯編指令的情況下,為何代碼的實(shí)時(shí)運行出錯了?
在C代碼中,我們可以使用asm()指令來(lái)插入匯編代碼。如果插入的這段匯編代碼修改了C代碼所使用的運行環(huán)境中的寄存器,則會(huì )破壞C代碼的數據,導致運行時(shí)出錯。所有在C代碼中使用內聯(lián)的匯編代碼時(shí)務(wù)必小心,不要破壞了程序的完整性。
評論