前言##
前幾天,主管找我問關(guān)于定義變量起始地址對齊方式的問題鸵隧。下面介紹一下問題:上位機(jī)生成了一個(gè)參數(shù)數(shù)組 char para[36541] = {...} ;數(shù)組比較大绸罗,已經(jīng)內(nèi)建好了結(jié)構(gòu)體,只要按照指針指到頭部地址即可正常讀取出來豆瘫,但是由于處理器讀取int 或者 float 數(shù)據(jù)類型比較要求數(shù)據(jù)地址是四字節(jié)對齊的珊蟀,而我們這個(gè)數(shù)組存放在內(nèi)存中是以兩個(gè)字節(jié)對齊的,這就導(dǎo)致了CPU無法讀取數(shù)據(jù)并死機(jī)在了讀取float數(shù)據(jù)類型處外驱;
主管提出育灸,能否直接指定該數(shù)組的存在于內(nèi)存中的起始地址?我一想昵宇,確實(shí)是磅崭,只要頭地址對了那就啥問題也沒有了。
主管又補(bǔ)充了一句瓦哎,他測試過了 #pragma pack(4) 這種編譯命令砸喻,實(shí)際效果是沒效果柔逼,于是我上網(wǎng)查了下,這個(gè)命令確實(shí)是數(shù)據(jù)對齊的命令割岛,但是只是對于結(jié)構(gòu)體內(nèi)部愉适。對于數(shù)組頭地址,我開始覺得有點(diǎn)挑戰(zhàn)了癣漆;
而且方法要簡單维咸,不要影響程序的運(yùn)行效率問題;
問題嘗試
今天在處理上次開會中提到的內(nèi)存分配的問題扑媚,改著改著忽然就靈光一閃腰湾,覺得這個(gè)問題應(yīng)該是可以解決的:
我拿出了自己使用的比較利索的C語言工具->IAR workbench for ARM; 測試平臺當(dāng)然還是最熟悉的Kinetis 系列的 K66 啦疆股!
先定義以下變量:測試看看存放于內(nèi)存中的位置费坊,代碼如下:
char aa[2] = {1,2}旬痹;
查看地址的方式有兩個(gè):
- 通過IAR編譯器生成的MAP文件進(jìn)行查找
- 就是通過IAR DEBUG工具中的 watch工具進(jìn)行查看
而我這種偷懶王必須采用第二種方式啊附井,多么直觀,哈哈哈哈两残;
如下是我通過IAR Debug watch中查看到的相關(guān)信息:
Expression | Value | Location | Type |
---|---|---|---|
aa | <<a>array>"??" | 0x1FFF0070 | char[2] |
bb | <<a>array>"??" | 0x1FFF0072 | char[2] |
可以看出上面aa存放地址是 0x1FFF0070 而bb的地址存放在0x1FFF0072地址上永毅,bb的起始地址是一個(gè)2字節(jié)對齊的地址,并非四地址對齊的地址人弓。
明確目標(biāo)沼死,向前進(jìn)發(fā)
準(zhǔn)備修改bb的首地址到一個(gè)四字節(jié)對齊的地址上,或者八字節(jié)對齊的地址上
目標(biāo)明確過后就是嘗試了崔赌,我首先嘗試了下主管說過的
#pragma pack(x) ;
這類編譯命令意蛀,不出意外,一點(diǎn)影響都沒有健芭;
直到今天县钥,一個(gè)偶然中想到了是否可以使用IAR 鏈接時(shí)候使用的ICF文件(鏈接文件)進(jìn)行處理;
好慈迈,說做就做:開始嘗試若贮,寫了一個(gè)簡單的鏈接代碼測試一下:
//define block to place test value
define symbol m_data_start = 0x1FFF0000;
define symbol m_data_end = 0x1FFFFFFF;
define memory mem with size = 4G;
define region test_region = mem:[from m_data_start to m_data_end];
define block test_block with alignment = 4 {section .test};
place in test_region {block test_block};
這里定義了一下鏈接文件(*.icf)將 .test這個(gè)段放在了0x00000410 ~ 0x1FFFFFFF這個(gè)區(qū)段中以四字節(jié)對齊的地址上;
然后回去在變量定義中修改成如下代碼:
char aa[2] = {1,2};
#pragma location = ".test"
char bb[2] = {3,4};
這里意思是數(shù)組aa依然按照編譯器缺省規(guī)則編譯痒留,而數(shù)組bb則存放到 .test段中谴麦;
究竟是否成功呢?打開IAR Debug watch:驚喜啊狭瞎,真的是跋敢啤:
以下是4字節(jié)對齊aa、bb首地址
Expression | Value | Location | Type |
---|---|---|---|
aa | <<a>array>"??" | 0x1FFF0070 | char[2] |
bb | <<a>array>"??" | 0x1FFF04A8 | char[2] |
好家伙熊锭,真的是成了四字節(jié)對齊的地址了(0x1FFF04A8 % 4 == 0)弧轧;為了確保是這個(gè)樣子雪侥,多實(shí)驗(yàn)幾下看看,看看是不是對的精绎,于是將鏈接中關(guān)于對齊部分代碼修改如下:
define block test_block with alignment = 8 {section .test};
再使用IAR debug watch查看一下地址:
以下是8字節(jié)對齊的aa速缨、bb首地址
Expression | Value | Location | Type |
---|---|---|---|
aa | <<a>array>"??" | 0x1FFF0070 | char[2] |
bb | <<a>array>"??" | 0x1FFF04A8 | char[2] |
地址竟然和上面一樣,使用計(jì)算器計(jì)算一下發(fā)現(xiàn)(0x1FFF04A8 % 8 == 0)代乃,確定是8字節(jié)對齊的旬牲。
我心里還是有點(diǎn)疑慮,看看16搁吓、32字節(jié)對齊會有啥樣子原茅?
以下是16字節(jié)對齊的aa、bb首地址
Expression | Value | Location | Type |
---|---|---|---|
aa | <<a>array>"??" | 0x1FFF0070 | char[2] |
bb | <<a>array>"??" | 0x1FFF04B0 | char[2] |
新地址計(jì)算一下(0x1FFF04B0 % 16 == 0 )
以下是32字節(jié)對齊的aa堕仔、bb首地址
Expression | Value | Location | Type |
---|---|---|---|
aa | <<a>array>"??" | 0x1FFF0070 | char[2] |
bb | <<a>array>"??" | 0x1FFF04C0 | char[2] |
新地址計(jì)算一下(0x1FFF04C0 % 32 == 0 )
結(jié)論
通過這一系列的嘗試擂橘。發(fā)現(xiàn)ICF文件(鏈接文件)中的塊alignment關(guān)鍵字可以使塊的首地址按照2^x(2,4,8,16,32...)方式對齊;而我們定義這一個(gè)塊就存放一個(gè)變量摩骨,那么這個(gè)變量的首地址的對齊方式就是一個(gè)可控的值通贞。
展望
由于項(xiàng)目中使用的參數(shù)文件是上位機(jī)生成的一個(gè)數(shù)組,按道理這個(gè)參數(shù)是不需要被被修改的恼五,本著提高CPU的效率考慮(CPU復(fù)位時(shí)候程序初始化需要搬運(yùn).data段到RAM中)昌罩,我們可以定義到該變量到CODE中成為一個(gè)常量表,可以提高系統(tǒng)啟動(dòng)的速率灾馒;
以下為改進(jìn)的icf文件關(guān)鍵代碼:
//define block to place test value
define symbol m_text_start = 0x00000410;
define symbol m_text_end = 0x001FFFFF;
define memory mem with size = 4G;
define region test_region = mem:[from m_text_start to m_text_end];
define block test_block with alignment = 4 {section .test};
place in test_region {block test_block};
以下為改進(jìn)了的測試數(shù)組定義
char aa[2] = {1,2};
#pragma location = ".test"
const char bb[2] = {3,4};
以下是通過IAR Debug Watch 所觀察到的變量數(shù)據(jù):
Expression | Value | Location | Type |
---|---|---|---|
aa | <<a>array>"??" | 0x1FFF0070 | char[2] |
bb | <<a>array>"??" | 0x00013748 | char[2] |
可以發(fā)現(xiàn)該地址存在于flash空間中茎用,仍然是一個(gè)4字節(jié)對齊的地址,成功睬罗,哈哈哈哈绘搞,這次任務(wù)完成;
寄語
樓主文筆特別差傅物,很多時(shí)候表詞不達(dá)意,或者用詞錯(cuò)誤琉预,亦或者對于東西理解不深入等等董饰。但是希望我的分享能夠解決你的實(shí)際問題。也希望你閱讀過程中發(fā)現(xiàn)對文章的技術(shù)或者其他方法有懷疑的提出反饋圆米,一起討論學(xué)習(xí)卒暂,一起進(jìn)步。謝謝閱讀娄帖。