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