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