|
大家好,我是痞子衡,是正經(jīng)搞技術(shù)的痞子。今天痞子衡給大家分享的是在IAR開(kāi)發(fā)環(huán)境下RT-Thread工程函數(shù)重定向失效分析。
0 {; j, ^0 A1 g痞子衡舊文 《在IAR下將關(guān)鍵函數(shù)重定向到RAM中執(zhí)行的方法》 里介紹了三種關(guān)鍵函數(shù)重定向方法,不過(guò)這三種方法只是寫法形式不同,本質(zhì)上沒(méi)啥區(qū)別,都是利用 IAR 鏈接器特性將函數(shù)重定向到工程數(shù)據(jù)段(RW)所在 RAM 里。
3 K2 {' B" ~; ]* Q8 i# K對(duì)于 i.MXRT 這種擁有多塊地址非連續(xù)的 RAM 的芯片,其實(shí)我們也可以單獨(dú)將這些重定向函數(shù)放到一個(gè)指定的 RAM 里,不一定非得跟數(shù)據(jù)段放在同一個(gè) RAM 里。具體實(shí)現(xiàn)也很簡(jiǎn)單,只需要在鏈接文件里額外加一句 place in 語(yǔ)句處理即可,恩智浦官方 SDK 包里就是這么做的。
, a w, U* Q- R然而痞子衡最近在移植一個(gè) i.MXRT1170 RT-Thread 工程時(shí)發(fā)現(xiàn),在 IAR 鏈接文件里用自定義段來(lái)單獨(dú)指定重定向函數(shù)到 ITCM 竟然失效了,這是怎么回事?今天我們一起來(lái)看一下:
' f; d9 B5 D. t l$ oNote 1:閱讀本文前需要對(duì) 《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 例程來(lái)看,工程 Build 選擇 flexspi_nor_sdram_debug(僅該 build 預(yù)編譯宏里有 XIP_BOOT_HEADER_DCD_ENABLE=1),即代碼段放在 Flash 里(0x30000000 - ),數(shù)據(jù)段放在 SDRAM 里(0x80000000 - )。+ F; {9 D; y* C: X4 A" H1 ?3 h4 h, i1 {& ^
在時(shí)鐘初始化函數(shù) BOARD_BootClockRUN() 里會(huì)調(diào)用如下 UpdateSemcClock() 函數(shù),這個(gè)函數(shù)需要重定向到 RAM 里執(zhí)行,在代碼里先將它放到自定義 CodeQuickAccess 段里。
# W8 ~) I: U' Y3 h#define AT_QUICKACCESS_SECTION_CODE(func) func @"CodeQuickAccess"
3 o/ Z( o7 P( y1 @7 K5 ?#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)/ Y; c; V+ _* a) J3 p
#if defined(XIP_BOOT_HEADER_DCD_ENABLE) && (XIP_BOOT_HEADER_DCD_ENABLE == 1)0 J, a3 L6 o& }% y
AT_QUICKACCESS_SECTION_CODE(void UpdateSemcClock(void));% _2 l! {8 s$ Y& c# ^
void UpdateSemcClock(void)1 k2 g0 k% b' t
{( b5 x' s2 T7 I( E6 K, m
SEMC->IPCMD = 0xA55A000D;
1 j9 h D% O( ~) O while ((SEMC->INTR & 0x3) == 0);
4 t' S! v0 ?5 }6 f8 \$ x* w SEMC->INTR = 0x3;7 q) L1 b/ N! m$ `- `
SEMC->DCCR = 0x0B;
% ?( y$ y0 G+ {6 n" q$ V" i* p E. c CCM->CLOCK_ROOT[kCLOCK_Root_Semc].CONTROL = 0x602;* p) q1 {5 a$ y
}
; L, r6 E. _. d; F#endif5 w9 l2 b. N7 P$ V+ q8 `
#endif
( Y; o4 q* }1 d! M- S0 S1 \3 X然后在工程鏈接文件 MIMXRT1176xxxxx_cm7_flexspi_nor_sdram.icf 里(僅摘錄部分),再將 CodeQuickAccess 段單獨(dú)放在 ITCM 里(0x00000000 - ),這就是官方 SDK 里的做法。
2 A, F) ^$ e8 {define symbol m_data3_start = 0x80000000;( I& K4 b+ _- ]/ I/ Y
define symbol m_data3_end = 0x82FFFFFF;- F3 F0 P+ G% {$ R
define symbol m_qacode_start = 0x00000000;5 X2 I- t3 |1 _
define symbol m_qacode_end = 0x0003FFFF;8 W" d# `5 O9 H5 a
define region DATA3_region = mem:[from m_data3_start to m_data3_end-__size_cstack__];
& o: S( ~0 y! t8 ^% D4 Odefine region QACODE_region = mem:[from m_qacode_start to m_qacode_end];
8 x# w& I1 E1 K: [+ Edefine block RW { first readwrite, section m_usb_dma_init_data };
$ o- x8 g2 ?& n& ?define block QACCESS_CODE { section CodeQuickAccess };& b1 i. ~7 h/ C4 [0 y, k; Q, S
initialize by copy { readwrite, section .textrw, section CodeQuickAccess };
' h( {0 M9 z9 p# qplace in DATA3_region { block RW };" \* F# Y* w$ N) Z: j2 W
place in QACODE_region { block QACCESS_CODE };
, W/ \$ ?( U' V+ O2 Y/ V編譯鏈接 hello_world_demo_cm7.ewp 工程,然后查看其映射文件(hello_world_demo_cm7.map)找到跟 UpdateSemcClock() 函數(shù)相關(guān)的內(nèi)容如下,顯然這是符合預(yù)期的。這里特別注意一下,CodeQuickAccess 的類別顯示的是 inited,表明其不是常見(jiàn)的 ro code,而是經(jīng)過(guò)重定向的,而且 UpdateSemcClock() 函數(shù)所在 clock_config.o 里包含了 60個(gè)字節(jié)的 rw code。" q2 \" b" c6 r+ o" ~2 T$ T7 ?9 ]
*******************************************************************************4 g$ J% @& U l# f- O' b1 L
*** PLACEMENT SUMMARY# V; z. P; q# d; S% Z) N+ @
***3 d+ T# s8 v- z6 e( Z' d" k
define block QACCESS_CODE { section CodeQuickAccess }; v! \8 W' K4 H% V
"P7": place in [from 0x0 to 0x3'ffff] { block QACCESS_CODE };
) z+ W' W* [ Y0 r Section Kind Address Size Object
2 h6 K, @3 l5 t8 h( g ------- ---- ------- ---- ------ Z! z. j6 u* M* k
"P7": 0x3c
$ F d& K% Q5 W1 c QACCESS_CODE 0x0 0x3c [B]
* z5 e" P) T) m QACCESS_CODE-1 0x0 0x3c [I]
5 Y% p$ N7 B9 d% d8 D6 f& l CodeQuickAccess inited 0x0 0x3c clock_config.o [1]' s" D6 `; p: b3 ~4 V
- 0x3c 0x3c; M1 f, h2 ?2 M5 E& h9 h/ Y, m
*******************************************************************************
9 f+ o, ]. a; V: |/ a! |' W2 T*** MODULE SUMMARY
( y' G' C! l* a9 D! A***
2 I3 ]: p4 Q! ^5 @3 p8 R: D Module ro code rw code ro data rw data6 ]& P5 k- z m# P3 W5 Z9 Z
------ ------- ------- ------- -------4 W4 Y7 |8 T3 ~2 i! [/ E- i
clock_config.o 2'644 60 844
; K* w; z- s8 e; c! O*******************************************************************************7 y8 |: S9 k2 V: w8 O3 b3 f0 O5 f
*** ENTRY LIST. Y8 p8 |5 ]. @' v: d
***$ X k1 q' G! N, p
Entry Address Size Type Object
' @% S# ]' v; ] ---- ------- ---- ---- ------
8 r* h) U$ j! i& P* _+ T+ @ UpdateSemcClock 0x1 0x3c Code Gb clock_config.o [1]
6 n* i1 b1 [: c( K ?7 J5 a" o二、引出RT-Thread下函數(shù)重定向失效問(wèn)題現(xiàn)在來(lái)看 RT-Thread 工程,也是一個(gè)簡(jiǎn)單的 hello world(具體工程略去不表),其中 i.MXRT1170 芯片 BSP 部分直接來(lái)自于官方 SDK,鏈接文件也與 SDK 里一致,但是編譯鏈接工程后查看其映射文件,發(fā)現(xiàn)跟 UpdateSemcClock() 函數(shù)相關(guān)的內(nèi)容如下,CodeQuickAccess 的類別顯示的是 ro code, UpdateSemcClock() 函數(shù)所在 clock_config.o 里干脆連 rw code 都沒(méi)有。顯然函數(shù)重定向失效了,鏈接文件里 initialize by copy { section CodeQuickAccess }; 語(yǔ)句沒(méi)起作用,這顯然就是一個(gè)分散鏈接而已。
; L: B: s2 R. D. |) v. D4 d1 W*******************************************************************************8 _. k4 o+ b1 I: z" d2 C* C& r6 g
*** PLACEMENT SUMMARY
I) R$ b( j# {: B# Z2 v; y***
; L0 Q4 e$ a) X# T8 i+ udefine block QACCESS_CODE { section CodeQuickAccess };- {" v; l s. @6 B( _* M% ?7 \9 i
"P7": place in [from 0x0 to 0x3'ffff] { block QACCESS_CODE };2 @0 L8 A ^3 `9 Z" O, U
Section Kind Address Size Object
4 _3 h2 A2 f8 |2 u7 Y8 ^- k ------- ---- ------- ---- ------. l) A" }" g k, y/ }0 P/ V
"P7": 0x3c
* n( {' O. `) b$ O: w, j/ b QACCESS_CODE 0x0 0x3c [B]
) O1 w6 b2 F9 Z" ?: w CodeQuickAccess ro code 0x0 0x3c clock_config.o [4], c" S- K1 q7 S; w8 R5 q
- 0x3c 0x3c7 C! h o o8 F k+ S& p
*******************************************************************************; @% ^2 p8 p7 b
*** MODULE SUMMARY1 e* M% P; x% B @( R
***4 y& e" b6 r( _9 s) D/ w
Module ro code ro data rw data
% j0 `' X& Y# x- _; V* C. G ------ ------- ------- -------
# g k1 [- U" X6 [. N/ I clock_config.o 2'768 7849 K) c) Z2 ]; F% E
*******************************************************************************% K4 q. L3 X- l4 \
*** ENTRY LIST6 j3 @0 }6 a/ [) j2 g- }
***
* w7 x% K1 H, [0 P" y- z Entry Address Size Type Object
5 o _1 m2 o z: j5 a$ z ---- ------- ---- ---- ------' v$ w) N; s+ h
UpdateSemcClock 0x1 0x3c Code Gb clock_config.o [4]
3 x! F: }* Z! W" t+ U$ [8 N# T三、RT-Thread下函數(shù)重定向失效分析第一節(jié)里 SDK 裸機(jī)環(huán)境下函數(shù)重定向做法不會(huì)失效,RT-Thread 環(huán)境下同樣的做法就失效了,難道 IAR 對(duì) RTOS 支持不友好?但是痞子衡在 \SDK_2.11.0_MIMXRT1170-EVK\boards\evkmimxrt1170\rtos_examples\freertos_hello 下做了相同實(shí)驗(yàn),F(xiàn)reeRTOS 下這種函數(shù)重定向方式也是沒(méi)有問(wèn)題的(FreeRTOS 內(nèi)核啟動(dòng)是在 main() 里),所以這個(gè)問(wèn)題主要跟 RT-Thread 內(nèi)核代碼結(jié)構(gòu)設(shè)計(jì)有關(guān)。
: C* @+ X2 _7 [ k經(jīng)過(guò)裸機(jī)工程、RT-Thread 工程、FreeRTOS 工程三者對(duì)比,痞子衡找到了問(wèn)題所在。RT-Thread 內(nèi)核啟動(dòng)是在 /src/components.c 文件中的 __low_level_init() 函數(shù)里,而這個(gè) __low_level_init() 函數(shù)本應(yīng)是 IAR 入口函數(shù) __iar_program_start() 中的一部分(IAR 系統(tǒng)庫(kù)里有一個(gè)內(nèi)置 PUBWEAK 版本),但是 RT-Thread 重實(shí)現(xiàn)了這個(gè) __low_level_init() 函數(shù),很不幸的是 IAR 鏈接器對(duì)于自定義段的函數(shù)重定向認(rèn)定與原內(nèi)置 __low_level_init() 函數(shù)設(shè)計(jì)有某種內(nèi)在關(guān)聯(lián)。. Z) z3 t% B5 R; G; R5 b
RT-Thread 代碼:https://gitee.com/rtthread/rt-thread/blob/gitee_master/src/components.c |
|