|
大家好,我是痞子衡,是正經(jīng)搞技術(shù)的痞子。今天痞子衡給大家分享的是在IAR開發(fā)環(huán)境下RT-Thread工程函數(shù)重定向失效分析。
2 b7 ~+ e9 ]/ b, [$ Q# a* {痞子衡舊文 《在IAR下將關(guān)鍵函數(shù)重定向到RAM中執(zhí)行的方法》 里介紹了三種關(guān)鍵函數(shù)重定向方法,不過這三種方法只是寫法形式不同,本質(zhì)上沒啥區(qū)別,都是利用 IAR 鏈接器特性將函數(shù)重定向到工程數(shù)據(jù)段(RW)所在 RAM 里。! j" H9 b' s r Y5 y- f) x+ a
對于 i.MXRT 這種擁有多塊地址非連續(xù)的 RAM 的芯片,其實(shí)我們也可以單獨(dú)將這些重定向函數(shù)放到一個指定的 RAM 里,不一定非得跟數(shù)據(jù)段放在同一個 RAM 里。具體實(shí)現(xiàn)也很簡單,只需要在鏈接文件里額外加一句 place in 語句處理即可,恩智浦官方 SDK 包里就是這么做的。
+ ^, E- ` @8 a/ u4 |然而痞子衡最近在移植一個 i.MXRT1170 RT-Thread 工程時發(fā)現(xiàn),在 IAR 鏈接文件里用自定義段來單獨(dú)指定重定向函數(shù)到 ITCM 竟然失效了,這是怎么回事?今天我們一起來看一下:& U3 V" b8 I k' H3 A$ |, h4 e
Note 1:閱讀本文前需要對 《IAR鏈接文件(.icf)》、《IAR映射文件(.map)》 這兩種文件有所了解。Note 2:本文使用的 IAR EWARM 軟件版本是 v9.10.2。一、回顧SDK里函數(shù)重定向做法我們以最經(jīng)典的 \SDK_2.11.0_MIMXRT1170-EVK\boards\evkmimxrt1170\demo_apps\hello_world\cm7\iar 例程來看,工程 Build 選擇 flexspi_nor_sdram_debug(僅該 build 預(yù)編譯宏里有 XIP_BOOT_HEADER_DCD_ENABLE=1),即代碼段放在 Flash 里(0x30000000 - ),數(shù)據(jù)段放在 SDRAM 里(0x80000000 - )。1 x$ ]; ]3 q- B6 ^+ A
在時鐘初始化函數(shù) BOARD_BootClockRUN() 里會調(diào)用如下 UpdateSemcClock() 函數(shù),這個函數(shù)需要重定向到 RAM 里執(zhí)行,在代碼里先將它放到自定義 CodeQuickAccess 段里。
% {3 P# s$ }0 t' B#define AT_QUICKACCESS_SECTION_CODE(func) func @"CodeQuickAccess"
. t& b" y+ k) a# n#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
; F+ z/ t1 a3 L" {0 v" c2 x+ H#if defined(XIP_BOOT_HEADER_DCD_ENABLE) && (XIP_BOOT_HEADER_DCD_ENABLE == 1)& j8 v# j; W7 b: v( a
AT_QUICKACCESS_SECTION_CODE(void UpdateSemcClock(void));% f) j( p$ Z. f" q; J
void UpdateSemcClock(void)
% C! {" [/ Q2 n, i; t4 N{
& N7 V, A e3 ]# F SEMC->IPCMD = 0xA55A000D;4 R [4 P- G, F& ^ G; |( F
while ((SEMC->INTR & 0x3) == 0);" `8 O* g( t3 @7 m& @
SEMC->INTR = 0x3;
/ g- @: J/ }+ M# X0 F! ? SEMC->DCCR = 0x0B;- ]8 ]' d0 Z% h. w: q" g
CCM->CLOCK_ROOT[kCLOCK_Root_Semc].CONTROL = 0x602;/ F/ K" e, J {2 C* y* l' m d. y
}
* U( ^! `( V# M3 y#endif- P. x1 G7 P t* ?
#endif
+ c$ Z, E, t, o' Z+ C然后在工程鏈接文件 MIMXRT1176xxxxx_cm7_flexspi_nor_sdram.icf 里(僅摘錄部分),再將 CodeQuickAccess 段單獨(dú)放在 ITCM 里(0x00000000 - ),這就是官方 SDK 里的做法。# j# ], ~2 g0 |& I! D$ g- p& Q9 t
define symbol m_data3_start = 0x80000000;
$ K- l' \6 {: {) {1 Idefine symbol m_data3_end = 0x82FFFFFF;" M$ r4 p% [- n6 f/ d' q
define symbol m_qacode_start = 0x00000000;/ ~+ m9 y0 E, |+ m; u3 @
define symbol m_qacode_end = 0x0003FFFF;
, l9 P. t6 k3 k A& C2 f- l! e. pdefine region DATA3_region = mem:[from m_data3_start to m_data3_end-__size_cstack__];: }; C, P/ D& s; G
define region QACODE_region = mem:[from m_qacode_start to m_qacode_end];
U' c# l# ?$ idefine block RW { first readwrite, section m_usb_dma_init_data };; O9 r& Y0 x' T, j i" ~; J2 {
define block QACCESS_CODE { section CodeQuickAccess };6 y4 a6 K) v- S q7 g
initialize by copy { readwrite, section .textrw, section CodeQuickAccess };' K: ~& i6 s( ^# j. r$ z
place in DATA3_region { block RW };
% e) Y8 s, Z* g$ Tplace in QACODE_region { block QACCESS_CODE };
% R c, P# O: s, Z9 u/ b編譯鏈接 hello_world_demo_cm7.ewp 工程,然后查看其映射文件(hello_world_demo_cm7.map)找到跟 UpdateSemcClock() 函數(shù)相關(guān)的內(nèi)容如下,顯然這是符合預(yù)期的。這里特別注意一下,CodeQuickAccess 的類別顯示的是 inited,表明其不是常見的 ro code,而是經(jīng)過重定向的,而且 UpdateSemcClock() 函數(shù)所在 clock_config.o 里包含了 60個字節(jié)的 rw code。0 L4 G, {) n `& p) T" P
*******************************************************************************% S% X/ q/ u; q; i- y$ Q6 O( y
*** PLACEMENT SUMMARY2 \7 f* L! t/ a; s$ \3 `$ J
***
- J( P) u {- M- Cdefine block QACCESS_CODE { section CodeQuickAccess };
+ ?/ o+ l( E1 I/ u6 `; H0 O"P7": place in [from 0x0 to 0x3'ffff] { block QACCESS_CODE };1 U" i3 \9 p6 O$ K/ ]( B$ f
Section Kind Address Size Object6 C) g }: ]. V" m) ^ ^
------- ---- ------- ---- ------# g S) k* a' [4 U6 N0 e. E
"P7": 0x3c
) y' O B6 _; k8 s. M9 n QACCESS_CODE 0x0 0x3c [B]9 F% c, x8 p) W( @1 J% L$ L3 g
QACCESS_CODE-1 0x0 0x3c [I]
; Z3 r& m7 U. ?. P CodeQuickAccess inited 0x0 0x3c clock_config.o [1]5 y9 _; d" J" R9 @ ?. Z
- 0x3c 0x3c
- {' s1 S* f* P. z% F*******************************************************************************
& k" n1 W" e; l( w3 k*** MODULE SUMMARY
7 ]1 }- W0 x5 F! {7 v***
9 F& R7 f6 p, _0 |; Q$ _9 a Module ro code rw code ro data rw data
; F# a* @; V# D1 G, c9 Z+ p9 m ------ ------- ------- ------- -------2 h( m6 O; g1 I# k
clock_config.o 2'644 60 844' q" A9 G2 z& y/ Y6 ^8 Q
*******************************************************************************
B8 p( E- G: C* t, n# A*** ENTRY LIST
& p6 D2 H6 @$ }1 a1 p) Y6 g% V***; o) ^! c2 D$ V' E/ f) M
Entry Address Size Type Object
( T( B' W g% O9 Q- T ---- ------- ---- ---- ------* A( _* J1 e0 X9 U$ F
UpdateSemcClock 0x1 0x3c Code Gb clock_config.o [1]4 W9 E3 v( @: r
二、引出RT-Thread下函數(shù)重定向失效問題現(xiàn)在來看 RT-Thread 工程,也是一個簡單的 hello world(具體工程略去不表),其中 i.MXRT1170 芯片 BSP 部分直接來自于官方 SDK,鏈接文件也與 SDK 里一致,但是編譯鏈接工程后查看其映射文件,發(fā)現(xiàn)跟 UpdateSemcClock() 函數(shù)相關(guān)的內(nèi)容如下,CodeQuickAccess 的類別顯示的是 ro code, UpdateSemcClock() 函數(shù)所在 clock_config.o 里干脆連 rw code 都沒有。顯然函數(shù)重定向失效了,鏈接文件里 initialize by copy { section CodeQuickAccess }; 語句沒起作用,這顯然就是一個分散鏈接而已。
( U# {6 c ^' g3 H- a# \* y* j******************************************************************************** U/ P; z! T1 N9 ]" a& B
*** PLACEMENT SUMMARY9 K* |* ]8 E( |7 X0 J
***
6 W: b$ A4 F% d5 T& U2 ydefine block QACCESS_CODE { section CodeQuickAccess };9 o$ e/ K% M: D. _% {
"P7": place in [from 0x0 to 0x3'ffff] { block QACCESS_CODE };+ R0 V- n- X) Z
Section Kind Address Size Object; g7 z- }' e% \
------- ---- ------- ---- ------
# |2 [3 b5 o) m! y) K" r5 ~! i" B"P7": 0x3c1 |- k8 u& f/ U9 [: |
QACCESS_CODE 0x0 0x3c [B]) H) b3 I1 ~6 M( o) m3 d2 V6 @1 t4 }
CodeQuickAccess ro code 0x0 0x3c clock_config.o [4]5 ?9 B: G. X, w
- 0x3c 0x3c+ m3 @9 a* r: x
*******************************************************************************7 c3 ^: ` ]" g4 T
*** MODULE SUMMARY% I# Q5 E1 a Z9 X; H. [) n5 Z d
***5 W0 ?: v# d& Y4 O) L) `) G
Module ro code ro data rw data
2 S0 L+ x) v# G5 L/ ]# m ------ ------- ------- -------/ G& c [0 M; L4 L
clock_config.o 2'768 784
4 U; m: Y' a7 _- S: T; v*******************************************************************************
( d+ M( c, D! j. u ^+ p*** ENTRY LIST1 ^ P0 _/ R8 c* S0 ^& T8 y) p! V! t
***
( ~' W1 h( E0 `6 m, B1 J Entry Address Size Type Object
/ z. f) v- h" b& ~* m ---- ------- ---- ---- ------
5 j6 p9 D& F4 G( l& q6 D UpdateSemcClock 0x1 0x3c Code Gb clock_config.o [4]
: d% T7 Y* F. W: ~ B三、RT-Thread下函數(shù)重定向失效分析第一節(jié)里 SDK 裸機(jī)環(huán)境下函數(shù)重定向做法不會失效,RT-Thread 環(huán)境下同樣的做法就失效了,難道 IAR 對 RTOS 支持不友好?但是痞子衡在 \SDK_2.11.0_MIMXRT1170-EVK\boards\evkmimxrt1170\rtos_examples\freertos_hello 下做了相同實(shí)驗(yàn),F(xiàn)reeRTOS 下這種函數(shù)重定向方式也是沒有問題的(FreeRTOS 內(nèi)核啟動是在 main() 里),所以這個問題主要跟 RT-Thread 內(nèi)核代碼結(jié)構(gòu)設(shè)計有關(guān)。' Y7 x/ C7 ], _5 E6 m# @7 w
經(jīng)過裸機(jī)工程、RT-Thread 工程、FreeRTOS 工程三者對比,痞子衡找到了問題所在。RT-Thread 內(nèi)核啟動是在 /src/components.c 文件中的 __low_level_init() 函數(shù)里,而這個 __low_level_init() 函數(shù)本應(yīng)是 IAR 入口函數(shù) __iar_program_start() 中的一部分(IAR 系統(tǒng)庫里有一個內(nèi)置 PUBWEAK 版本),但是 RT-Thread 重實(shí)現(xiàn)了這個 __low_level_init() 函數(shù),很不幸的是 IAR 鏈接器對于自定義段的函數(shù)重定向認(rèn)定與原內(nèi)置 __low_level_init() 函數(shù)設(shè)計有某種內(nèi)在關(guān)聯(lián)。9 i5 y) I2 ]! _
RT-Thread 代碼:https://gitee.com/rtthread/rt-thread/blob/gitee_master/src/components.c |
|