|
大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家分享的是在IAR開發(fā)環(huán)境下RT-Thread工程函數(shù)重定向失效分析。
$ _- W# V' b: p/ ]0 O痞子衡舊文 《在IAR下將關鍵函數(shù)重定向到RAM中執(zhí)行的方法》 里介紹了三種關鍵函數(shù)重定向方法,不過這三種方法只是寫法形式不同,本質上沒啥區(qū)別,都是利用 IAR 鏈接器特性將函數(shù)重定向到工程數(shù)據段(RW)所在 RAM 里。
+ \+ {, E4 X$ T5 U( @# P7 q對于 i.MXRT 這種擁有多塊地址非連續(xù)的 RAM 的芯片,其實我們也可以單獨將這些重定向函數(shù)放到一個指定的 RAM 里,不一定非得跟數(shù)據段放在同一個 RAM 里。具體實現(xiàn)也很簡單,只需要在鏈接文件里額外加一句 place in 語句處理即可,恩智浦官方 SDK 包里就是這么做的。$ t# U( [9 X! Y/ t# Y
然而痞子衡最近在移植一個 i.MXRT1170 RT-Thread 工程時發(fā)現(xiàn),在 IAR 鏈接文件里用自定義段來單獨指定重定向函數(shù)到 ITCM 竟然失效了,這是怎么回事?今天我們一起來看一下:
- C. B! a8 n- c3 l9 fNote 1:閱讀本文前需要對 《IAR鏈接文件(.icf)》、《IAR映射文件(.map)》 這兩種文件有所了解。Note 2:本文使用的 IAR EWARM 軟件版本是 v9.10.2。一、回顧SDK里函數(shù)重定向做法我們以最經典的 \SDK_2.11.0_MIMXRT1170-EVK\boards\evkmimxrt1170\demo_apps\hello_world\cm7\iar 例程來看,工程 Build 選擇 flexspi_nor_sdram_debug(僅該 build 預編譯宏里有 XIP_BOOT_HEADER_DCD_ENABLE=1),即代碼段放在 Flash 里(0x30000000 - ),數(shù)據段放在 SDRAM 里(0x80000000 - )。: Y. q8 u8 u: W( G) B& H
在時鐘初始化函數(shù) BOARD_BootClockRUN() 里會調用如下 UpdateSemcClock() 函數(shù),這個函數(shù)需要重定向到 RAM 里執(zhí)行,在代碼里先將它放到自定義 CodeQuickAccess 段里。7 D; Y; h/ r! X: Q
#define AT_QUICKACCESS_SECTION_CODE(func) func @"CodeQuickAccess"
& G5 I3 y% a) D- [! W#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
" W/ O4 G8 A! B% _6 S#if defined(XIP_BOOT_HEADER_DCD_ENABLE) && (XIP_BOOT_HEADER_DCD_ENABLE == 1), f4 ^* `! w( q m3 C
AT_QUICKACCESS_SECTION_CODE(void UpdateSemcClock(void));
# \7 Z/ U) E. E7 x4 Hvoid UpdateSemcClock(void)
% s% U. |+ b+ Q1 a) h. C# F{
( M; r9 i5 G6 _3 c7 E' D9 w! N SEMC->IPCMD = 0xA55A000D;
B/ Q2 W" C2 l0 p while ((SEMC->INTR & 0x3) == 0);2 b0 O0 \7 _- }1 y3 b
SEMC->INTR = 0x3;0 p" E: \: z% \" \
SEMC->DCCR = 0x0B;* [; R- }& K8 d7 r+ J9 l
CCM->CLOCK_ROOT[kCLOCK_Root_Semc].CONTROL = 0x602;; t0 u9 P6 R: \3 N, ?
}
* A/ K: B% c: W6 H) L#endif
- s( H E- q6 A0 d$ n. V#endif S: M; C2 Y* e4 r! u" W
然后在工程鏈接文件 MIMXRT1176xxxxx_cm7_flexspi_nor_sdram.icf 里(僅摘錄部分),再將 CodeQuickAccess 段單獨放在 ITCM 里(0x00000000 - ),這就是官方 SDK 里的做法。
+ t+ e3 |# r* k; [define symbol m_data3_start = 0x80000000;' u X* ]5 L+ F
define symbol m_data3_end = 0x82FFFFFF;
! y9 h/ E3 |8 O& U" j5 x; j+ ddefine symbol m_qacode_start = 0x00000000;9 e5 P5 t P Y5 Z! f& A y
define symbol m_qacode_end = 0x0003FFFF;
/ a: e$ D' \' J! p P, U Udefine region DATA3_region = mem:[from m_data3_start to m_data3_end-__size_cstack__];! y* H. o" p0 k6 t3 e8 ?7 Q" j
define region QACODE_region = mem:[from m_qacode_start to m_qacode_end];, }+ Y) Z4 Y) c" D/ u( M/ ?- ?
define block RW { first readwrite, section m_usb_dma_init_data };
) W( E- J- Q7 h0 ^$ G& F2 _1 o9 tdefine block QACCESS_CODE { section CodeQuickAccess };
/ Q+ g0 H$ t% K2 l* u" Winitialize by copy { readwrite, section .textrw, section CodeQuickAccess };
6 a; b$ D9 N# M. S! S% ?: M8 iplace in DATA3_region { block RW };9 w K4 G% Q7 x( N: c
place in QACODE_region { block QACCESS_CODE };! f/ o* i4 B/ J ~. t$ m+ H! h7 l
編譯鏈接 hello_world_demo_cm7.ewp 工程,然后查看其映射文件(hello_world_demo_cm7.map)找到跟 UpdateSemcClock() 函數(shù)相關的內容如下,顯然這是符合預期的。這里特別注意一下,CodeQuickAccess 的類別顯示的是 inited,表明其不是常見的 ro code,而是經過重定向的,而且 UpdateSemcClock() 函數(shù)所在 clock_config.o 里包含了 60個字節(jié)的 rw code。6 Y8 m8 }3 _. j5 P
*******************************************************************************% d* |7 p% c" Z- z5 r9 D% ?
*** PLACEMENT SUMMARY# p" U' F N' C$ f t. s
***/ ~ Q* f! d @: n; G+ I
define block QACCESS_CODE { section CodeQuickAccess };
; v( x8 u' g% y/ \- V"P7": place in [from 0x0 to 0x3'ffff] { block QACCESS_CODE };. ^: C* v) }5 l1 b6 }$ u
Section Kind Address Size Object" I0 v; P& r: P. t* [) P* f2 [
------- ---- ------- ---- ------
9 O$ P$ T. |, J1 j3 B3 U"P7": 0x3c. v: p1 y2 j; F- }" H& U
QACCESS_CODE 0x0 0x3c [B]8 Z& Q8 Z) V; ?0 D: E( ]
QACCESS_CODE-1 0x0 0x3c [I]
" t2 u5 \0 Q) l* R CodeQuickAccess inited 0x0 0x3c clock_config.o [1]$ ]8 A. _; K" e# Q2 T
- 0x3c 0x3c
' p1 B) p d5 V0 |" @3 d) q*******************************************************************************
1 f- A1 r3 ~! `: v2 E/ ?' F' H*** MODULE SUMMARY
9 l4 @- K( [6 q***
t) M6 ~, y+ ^+ ^2 ` Module ro code rw code ro data rw data4 t5 {& ^& V9 n1 {( E
------ ------- ------- ------- -------8 ~7 E7 E# O, ?6 @* M6 d! s
clock_config.o 2'644 60 844
$ |2 A( S' p: Z*******************************************************************************# l( U" K- ^' V8 T/ @+ q
*** ENTRY LIST* A3 ?" z1 m' `
***
0 t6 Z" q& b8 H* Y9 O/ H! C Entry Address Size Type Object: n$ V e8 x/ p
---- ------- ---- ---- ------
* f2 C$ `- _7 c$ U4 Q* B2 p7 \ UpdateSemcClock 0x1 0x3c Code Gb clock_config.o [1]
% x* q% ~0 U9 y# y5 X" _二、引出RT-Thread下函數(shù)重定向失效問題現(xiàn)在來看 RT-Thread 工程,也是一個簡單的 hello world(具體工程略去不表),其中 i.MXRT1170 芯片 BSP 部分直接來自于官方 SDK,鏈接文件也與 SDK 里一致,但是編譯鏈接工程后查看其映射文件,發(fā)現(xiàn)跟 UpdateSemcClock() 函數(shù)相關的內容如下,CodeQuickAccess 的類別顯示的是 ro code, UpdateSemcClock() 函數(shù)所在 clock_config.o 里干脆連 rw code 都沒有。顯然函數(shù)重定向失效了,鏈接文件里 initialize by copy { section CodeQuickAccess }; 語句沒起作用,這顯然就是一個分散鏈接而已。
6 Z! B" g: x" P5 K7 M******************************************************************************** ?9 g/ G( b" V, Y. F3 d
*** PLACEMENT SUMMARY* p" ^4 v3 R ?+ W5 ]& a
***6 w* y+ ^3 f/ L7 t& X
define block QACCESS_CODE { section CodeQuickAccess }; C Q$ l1 F8 W; }
"P7": place in [from 0x0 to 0x3'ffff] { block QACCESS_CODE };
9 K$ @: j' F0 \6 |3 Y: w P" b Section Kind Address Size Object
3 l1 r2 _8 k2 i) A: P. O ------- ---- ------- ---- ------: }8 J2 o f2 B' K# y
"P7": 0x3c4 n. g6 u% S9 V
QACCESS_CODE 0x0 0x3c [B]
# [/ ?/ L4 ?+ l g$ T, [" J CodeQuickAccess ro code 0x0 0x3c clock_config.o [4]3 S' q$ m' D! S7 N; a! ~' t' W' H
- 0x3c 0x3c- E) Y: l, ~: p" c; V2 H u
*******************************************************************************5 c: U1 y) U9 V3 F! j0 {2 Z" I0 u- S
*** MODULE SUMMARY
. u5 N9 x4 w* M* B, V) I8 K***
' f% t5 z% ] `3 `. r Module ro code ro data rw data# K. I8 [+ x* z
------ ------- ------- -------
/ L, N. S `9 ? clock_config.o 2'768 784
5 W" k, F$ Z- o$ g*******************************************************************************
" Y7 ^) I, _& t# d*** ENTRY LIST6 V/ ]: C( B% K3 ]6 ^2 d9 y. s
***
+ g0 U- D3 L4 H0 g9 i Entry Address Size Type Object0 m$ J8 U- t/ s/ `+ ?8 ^( n m
---- ------- ---- ---- ------5 v {- `4 G" [
UpdateSemcClock 0x1 0x3c Code Gb clock_config.o [4]
4 D' R* R& H6 R' D# B3 M三、RT-Thread下函數(shù)重定向失效分析第一節(jié)里 SDK 裸機環(huán)境下函數(shù)重定向做法不會失效,RT-Thread 環(huán)境下同樣的做法就失效了,難道 IAR 對 RTOS 支持不友好?但是痞子衡在 \SDK_2.11.0_MIMXRT1170-EVK\boards\evkmimxrt1170\rtos_examples\freertos_hello 下做了相同實驗,F(xiàn)reeRTOS 下這種函數(shù)重定向方式也是沒有問題的(FreeRTOS 內核啟動是在 main() 里),所以這個問題主要跟 RT-Thread 內核代碼結構設計有關。( j- Q7 s* M- z/ H3 d+ p
經過裸機工程、RT-Thread 工程、FreeRTOS 工程三者對比,痞子衡找到了問題所在。RT-Thread 內核啟動是在 /src/components.c 文件中的 __low_level_init() 函數(shù)里,而這個 __low_level_init() 函數(shù)本應是 IAR 入口函數(shù) __iar_program_start() 中的一部分(IAR 系統(tǒng)庫里有一個內置 PUBWEAK 版本),但是 RT-Thread 重實現(xiàn)了這個 __low_level_init() 函數(shù),很不幸的是 IAR 鏈接器對于自定義段的函數(shù)重定向認定與原內置 __low_level_init() 函數(shù)設計有某種內在關聯(lián)。
% n) V' @2 H, ]RT-Thread 代碼:https://gitee.com/rtthread/rt-thread/blob/gitee_master/src/components.c |
|