大家好,我是痞子衡,是正經(jīng)搞技術(shù)的痞子。今天痞子衡給大家分享的是在IAR開發(fā)環(huán)境下將整個源文件代碼重定向到任意RAM中的方法。
痞子衡舊文 《在IAR下將關(guān)鍵函數(shù)重定向到RAM中執(zhí)行的方法》 里介紹了三種關(guān)鍵函數(shù)重定向方法,不過這三種方法只是寫法形式不同,本質(zhì)上沒啥區(qū)別,都是利用 IAR 鏈接器特性將函數(shù)重定向到工程數(shù)據(jù)段(RW)所在 RAM 里。
對于 i.MXRT 這種擁有多塊地址非連續(xù)的 RAM 的芯片,其實我們也可以單獨將這些重定向函數(shù)放到一個指定的 RAM 里,不一定非得跟數(shù)據(jù)段放在同一個 RAM 里。具體實現(xiàn)也很簡單,只需要在鏈接文件里額外加一句 place in 語句處理即可,恩智浦官方 SDK 包里就是這么做的。
然而痞子衡最近在支持 i.MXRT1170 客戶過程中,不使用恩智浦 SDK 里那種自定義函數(shù)段處理的方法,而是在 IAR 鏈接文件里使用指定源文件 object 的方式將代碼重定向到 ITCM 竟然失效了,這是怎么回事?今天我們一起來看一下:
- Note 1:閱讀本文前需要對 《IAR鏈接文件(.icf)》、《IAR映射文件(.map)》 這兩種文件有所了解。Note 2:本文使用的 IAR EWARM 軟件版本是 v9.10.2。
一、回顧SDK里函數(shù)重定向做法
我們以最經(jīng)典的 SDK_2.11.0_MIMXRT1170-EVKboardsevkmimxrt1170demo_appshello_worldcm7iar 例程來看,工程 Build 選擇 flexspi_nor_debug,即代碼段放在 Flash 里(0x30000000 - ),數(shù)據(jù)段放在 DTCM 里(0x20000000 - )。
我們現(xiàn)在新建一個名為 ram_code.c 的源文件,在這個源文件里定義如下兩個 delay1/2() 函數(shù),然后將這個源文件添加進工程使用。按照 SDK 里做法,如果我們想將這兩個函數(shù)重定向,需要加 AT_QUICKACCESS_SECTION_CODE 宏來修飾,其實就是將函數(shù)放到名為 CodeQuickAccess 的自定義段里。
#define AT_QUICKACCESS_SECTION_CODE(func) func @"CodeQuickAccess"
AT_QUICKACCESS_SECTION_CODE(void delay1(void));
void delay1(void)
{
__NOP();
}
AT_QUICKACCESS_SECTION_CODE(void delay2(void));
void delay2(void)
{
__NOP();
__NOP();
}
然后工程鏈接文件 MIMXRT1176xxxxx_cm7_flexspi_nor.icf 里(僅摘錄部分),CodeQuickAccess 段單獨放在 ITCM 里(0x00000000 - ),這就是官方 SDK 里的實現(xiàn)。
define symbol m_data_start = 0x20000000;
define symbol m_data_end = 0x2003FFFF;
define symbol m_itcm_start = 0x00000000;
define symbol m_itcm_end = 0x0003FFFF;
define region DATA_region = mem:[from m_data_start to m_data_end-__size_cstack__];
define region ITCM_region = mem:[from m_itcm_start to m_itcm_end];
define block RW { first readwrite, section m_usb_dma_init_data };
define block QACCESS_CODE { section CodeQuickAccess };
initialize by copy { readwrite, section .textrw, section CodeQuickAccess };
place in DATA_region { block RW };
place in ITCM_region { block QACCESS_CODE };
編譯鏈接 hello_world_demo_cm7.ewp 工程,然后查看其映射文件(hello_world_demo_cm7.map)找到跟 delay1/2() 函數(shù)相關(guān)的內(nèi)容如下,顯然這是符合預(yù)期的。這里特別注意一下,CodeQuickAccess 的類別顯示的是 inited,表明其不是常見的 ro code,而是經(jīng)過重定向的,而且 delay1/2() 函數(shù)所在 ram_code.o 里包含了 10 個字節(jié)的 rw code。
*******************************************************************************
*** PLACEMENT SUMMARY
***
define block QACCESS_CODE { section CodeQuickAccess };
"P8": place in [from 0x0 to 0x3'ffff] { block QACCESS_CODE };
Section Kind Address Size Object
------- ---- ------- ---- ------
"P8": 0xc
QACCESS_CODE 0x0 0xc <Block>
QACCESS_CODE-1 0x0 0xa <Init block>
CodeQuickAccess inited 0x0 0xa ram_code.o [6]
- 0xc 0xc
*******************************************************************************
*** MODULE SUMMARY
***
Module ro code rw code ro data rw data
------ ------- ------- ------- -------
ram_code.o 10 10
*******************************************************************************
*** ENTRY LIST
***
Entry Address Size Type Object
---- ------- ---- ---- ------
delay1 0x1 0x4 Code Gb ram_code.o [6]
delay2 0x5 0x6 Code Gb ram_code.o [6]
如果你打開工程鏡像文件 hello_world_demo_cm7.srec 查看,這里也只有一段連續(xù)的 Flash 地址空間數(shù)據(jù),沒有 RAM 地址空間數(shù)據(jù),所以這個鏡像文件是符合獨立工具(比如 MCUBootUtility)下載以及 BootROM 啟動條件的。
二、引出源文件Object方式重定向失效問題
現(xiàn)在來看客戶遇到的問題,客戶不想在源文件里逐一修飾需要重定向的函數(shù)(即 ram_code.c 文件里 delay1/2() 函數(shù)不加 AT_QUICKACCESS_SECTION_CODE 修飾),這種情況下我們需要改動一下鏈接文件,將 object ram_code.o 放到 initialize by copy 語句和 place in ITCM_region 語句里。
initialize by copy { readwrite, section .textrw, section CodeQuickAccess, object ram_code.o };
place in ITCM_region { object ram_code.o };
這時候重新編譯鏈接工程,查看映射文件,找到跟 delay1/2() 函數(shù)相關(guān)的內(nèi)容如下,這個結(jié)果跟第一小節(jié)里結(jié)果有點區(qū)別,雖然 delay1/2() 確實鏈接在了 ITCM 里(0x00000000 - ),但是同時也增加了 0x0 - 0xb 區(qū)域的 Initializer bytes。
*******************************************************************************
*** PLACEMENT SUMMARY
***
define block QACCESS_CODE { section CodeQuickAccess };
"P8": place in [from 0x0 to 0x3'ffff] { block QACCESS_CODE };
"P9": place in [from 0x0 to 0x3'ffff] { object ram_code.o };
Section Kind Address Size Object
------- ---- ------- ---- ------
"P8-P9": 0x18
Initializer bytes const 0x0 0xc <for P8-P9-1>
P8-P9-1 0xc 0xa <Init block>
.text inited 0xc 0xa ram_code.o [6]
- 0x16 0x16
*******************************************************************************
*** MODULE SUMMARY
***
Module ro code ro data rw data
------ ------- ------- -------
ram_code.o 10 10
*******************************************************************************
*** ENTRY LIST
***
Entry Address Size Type Object
---- ------- ---- ---- ------
delay1 0xd 0x4 Code Gb ram_code.o [6]
delay2 0x11 0x6 Code Gb ram_code.o [6]
如果此時再打開工程鏡像文件 hello_world_demo_cm7.srec 查看,除了 Flash 地址空間數(shù)據(jù),還新增了 RAM 地址空間數(shù)據(jù),很顯然這個鏡像文件不符合獨立工具(比如 MCUBootUtility)下載以及 BootROM 啟動,僅能用于 IDE 中在線下載調(diào)試(即分散加載了)。
三、源文件Object方式重定向失效分析
我們再做一個實驗,按 《在IAR下將關(guān)鍵函數(shù)重定向到RAM中執(zhí)行的方法》 一文 2.3 針對源文件中全部函數(shù) 方法,在鏈接文件中僅將 object ram_code.o 放到 initialize by copy 語句里,那么 ram_code.o 中的內(nèi)容會被統(tǒng)一重定向到工程數(shù)據(jù)段 RW 所在 RAM 區(qū)域里(即 DTCM 0x20000000 -),這種情況下 delay1/2() 函數(shù)重定向是成功的。
initialize by copy { readwrite, section .textrw, section CodeQuickAccess, object ram_code.o };
//place in ITCM_region { object ram_code.o };
所以我們能夠得出結(jié)論,在不自定義函數(shù)段名的情況下,object ram_code.o 中內(nèi)容會在默認 RO、RW 段里,在做函數(shù)重定向時,IAR 鏈接器無法將對應(yīng) ram_code.o 的 Initializer bytes 從默認 RO 段里單獨提取出來拷貝到非 RW 段所在區(qū),它只能統(tǒng)一處理 RO 段 Initializer bytes 到 RW 區(qū)的拷貝。如果硬要將 object ram_code.o 重定向到非 RW 所在 RAM 區(qū),IAR 鏈接器會直接將其 Initializer bytes 也從 RO 段里抽出來,與其 RW 屬性的 .text 放在一起,這其實幾乎等效于分散加載了。
四、源文件Object方式重定向失效解決方案
分析到這里,解決方案清晰了,還是需要自定義程序段,不過既然不想單個函數(shù)加修飾,那有沒有整個文件范圍內(nèi)代碼統(tǒng)一加修飾呢?當(dāng)然是有的,這時候需要借助如下 #pragma default_function_attributes 語法,將這一對語句放置到源文件首行和末行,那么該源文件里所有函數(shù)都進入了 .myCodeSection 自定義段里:
// 作用全部函數(shù)
#pragma default_function_attributes = @ ".myCodeSection"
// 作用全部變量(如有必要)
//#pragma default_variable_attributes = @ ".myVariSection"
void delay1(void)
{
__NOP();
}
void delay2(void)
{
__NOP();
__NOP();
}
#pragma default_function_attributes =
//#pragma default_variable_attributes =
然后在工程鏈接文件 MIMXRT1176xxxxx_cm7_flexspi_nor_sdram.icf 里直接將 section .myCodeSection 放到 ITCM 里就可以了:
initialize by copy { readwrite, section .textrw, section CodeQuickAccess, section .myCodeSection };
place in ITCM_region { section .myCodeSection };
這時候再編譯鏈接工程查看映射文件,函數(shù)重定向結(jié)果就符合預(yù)期了,這個結(jié)果跟第一小節(jié)里的結(jié)果一致。
*******************************************************************************
*** PLACEMENT SUMMARY
***
"P8": place in [from 0x0 to 0x3'ffff] { block QACCESS_CODE };
"P9": place in [from 0x0 to 0x3'ffff] { section .myCodeSection };
Section Kind Address Size Object
------- ---- ------- ---- ------
"P8-P9": 0xc
P8-P9 0x0 0xc <Init block>
.myCodeSection inited 0x0 0xa ram_code.o [6]
- 0xc 0xc
*******************************************************************************
*** MODULE SUMMARY
***
Module ro code rw code ro data rw data
------ ------- ------- ------- -------
ram_code.o 10 10
*******************************************************************************
*** ENTRY LIST
***
Entry Address Size Type Object
---- ------- ---- ---- ------
delay1 0x1 0x4 Code Gb ram_code.o [6]
delay2 0x5 0x6 Code Gb ram_code.o [6]
至此,在IAR開發(fā)環(huán)境下將整個源文件代碼重定向到任意RAM中的方法痞子衡便介紹完畢了,掌聲在哪里~~~