|
大家好,我是痞子衡,是正經(jīng)搞技術(shù)的痞子。今天痞子衡給大家分享的是在IAR開發(fā)環(huán)境下RT-Thread工程函數(shù)重定向失效分析。
3 _/ }6 G$ q0 M i痞子衡舊文 《在IAR下將關(guān)鍵函數(shù)重定向到RAM中執(zhí)行的方法》 里介紹了三種關(guān)鍵函數(shù)重定向方法,不過這三種方法只是寫法形式不同,本質(zhì)上沒啥區(qū)別,都是利用 IAR 鏈接器特性將函數(shù)重定向到工程數(shù)據(jù)段(RW)所在 RAM 里。
' y# J0 J* X0 P6 ~* ]$ r- J) |對于 i.MXRT 這種擁有多塊地址非連續(xù)的 RAM 的芯片,其實(shí)我們也可以單獨(dú)將這些重定向函數(shù)放到一個指定的 RAM 里,不一定非得跟數(shù)據(jù)段放在同一個 RAM 里。具體實(shí)現(xiàn)也很簡單,只需要在鏈接文件里額外加一句 place in 語句處理即可,恩智浦官方 SDK 包里就是這么做的。8 Q+ b9 g, q+ U b
然而痞子衡最近在移植一個 i.MXRT1170 RT-Thread 工程時發(fā)現(xiàn),在 IAR 鏈接文件里用自定義段來單獨(dú)指定重定向函數(shù)到 ITCM 竟然失效了,這是怎么回事?今天我們一起來看一下:& h( Q) b# W9 J9 }2 u+ P9 N5 }
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 - )。
" Q1 p" K1 a: M' o在時鐘初始化函數(shù) BOARD_BootClockRUN() 里會調(diào)用如下 UpdateSemcClock() 函數(shù),這個函數(shù)需要重定向到 RAM 里執(zhí)行,在代碼里先將它放到自定義 CodeQuickAccess 段里。
; J) f' r8 E5 I" O G#define AT_QUICKACCESS_SECTION_CODE(func) func @"CodeQuickAccess", z6 T9 y" F( R# l6 m$ f1 n
#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
3 J$ Q& s; }" \$ h& a1 g#if defined(XIP_BOOT_HEADER_DCD_ENABLE) && (XIP_BOOT_HEADER_DCD_ENABLE == 1)( w( T3 I3 w* o/ B' r1 z
AT_QUICKACCESS_SECTION_CODE(void UpdateSemcClock(void));
" y' {2 h' _( N3 Qvoid UpdateSemcClock(void)% P4 R0 L& z/ U' e! e4 f- a
{
# E8 n7 O# n5 s+ N+ b SEMC->IPCMD = 0xA55A000D;/ r. M4 \1 C0 b' f; E& l
while ((SEMC->INTR & 0x3) == 0);
6 s8 a! P$ M, i' x SEMC->INTR = 0x3;' s) M' g/ y- A ~$ w/ ~. e# T
SEMC->DCCR = 0x0B;
! a/ W% H/ ~ A! H1 x5 `. A CCM->CLOCK_ROOT[kCLOCK_Root_Semc].CONTROL = 0x602;
2 j: n0 e3 |6 X/ T3 Z3 o5 ? K8 [* X}
. m/ [ d" N( p, K. I#endif' J: M6 ?, G8 h
#endif d: m1 B' u* F9 I) a/ x1 Q5 W, p; K
然后在工程鏈接文件 MIMXRT1176xxxxx_cm7_flexspi_nor_sdram.icf 里(僅摘錄部分),再將 CodeQuickAccess 段單獨(dú)放在 ITCM 里(0x00000000 - ),這就是官方 SDK 里的做法。& `- r: g+ l k2 @" x
define symbol m_data3_start = 0x80000000;
' s7 {0 M& x& c7 N4 w% s: zdefine symbol m_data3_end = 0x82FFFFFF;
' T$ }8 ~* l0 Wdefine symbol m_qacode_start = 0x00000000;% U1 C* g m- L
define symbol m_qacode_end = 0x0003FFFF;
: ?! o6 @5 {& k* ?9 odefine region DATA3_region = mem:[from m_data3_start to m_data3_end-__size_cstack__];
: m+ @! U: q! Jdefine region QACODE_region = mem:[from m_qacode_start to m_qacode_end];
7 ^3 d( P6 v: Z0 e5 ?define block RW { first readwrite, section m_usb_dma_init_data };
8 u* y0 `( }% o0 g! M1 v) }& ndefine block QACCESS_CODE { section CodeQuickAccess };; ]$ B) D1 @3 c' O: R3 V: `
initialize by copy { readwrite, section .textrw, section CodeQuickAccess };- \, y/ n1 Z$ E
place in DATA3_region { block RW };( H' ?$ P9 f8 l( j, I; P" q
place in QACODE_region { block QACCESS_CODE };
2 H2 i" Y2 }% `* s編譯鏈接 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。6 N% q; u& M1 l j( p* s. [; O
*******************************************************************************
1 H: K. I+ j# G# @( n+ _5 I*** PLACEMENT SUMMARY* W4 R/ V+ Y- d# L! a+ k
***8 [: x. b. _1 B5 I) R
define block QACCESS_CODE { section CodeQuickAccess };* `5 h3 P+ o1 t5 y
"P7": place in [from 0x0 to 0x3'ffff] { block QACCESS_CODE };# v- q% r- v* Q
Section Kind Address Size Object
) @* G/ S$ C4 E g; P5 n4 h b ------- ---- ------- ---- ------; K3 ]+ w9 y3 d. d1 f
"P7": 0x3c1 P1 A' h. }0 X0 R
QACCESS_CODE 0x0 0x3c [B]
$ d' v2 e/ W! C6 G QACCESS_CODE-1 0x0 0x3c [I]- h& R$ {& y; n' j& ?) f% h
CodeQuickAccess inited 0x0 0x3c clock_config.o [1]
+ r/ H1 }4 ~( F1 I% p - 0x3c 0x3c4 f* x l! F$ y ^$ Q3 _
*******************************************************************************. r3 @6 C9 l$ h# j6 z4 D
*** MODULE SUMMARY7 b- _, b; `8 s) z* N% v) a% B
***
1 A/ U+ j8 ?3 {8 v& A+ p Module ro code rw code ro data rw data
! M% S R8 d3 S6 l ------ ------- ------- ------- -------# c" v" E3 w* m8 X* _; O
clock_config.o 2'644 60 844
# ~8 n+ T9 h0 ~' ^8 U*******************************************************************************8 I( X: s7 @/ `$ I6 e9 W5 i2 x* ?9 D
*** ENTRY LIST
6 ^$ }# I- G) _5 O( L1 q% Q' F# e***. L' p ]6 D4 Z' B% R% {
Entry Address Size Type Object" b \ \/ T: O
---- ------- ---- ---- ------
3 {. y2 e- \, ^ UpdateSemcClock 0x1 0x3c Code Gb clock_config.o [1]2 v+ U% X. R8 G3 e& H
二、引出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 }; 語句沒起作用,這顯然就是一個分散鏈接而已。
; S3 s0 v5 i7 y: T2 @* a*******************************************************************************
9 D! Q) t1 v8 R G2 _0 D*** PLACEMENT SUMMARY9 [. P t) S2 ^* {! |+ C5 J
***
- q. G$ F. V+ Tdefine block QACCESS_CODE { section CodeQuickAccess };
- D& K- \" C" n"P7": place in [from 0x0 to 0x3'ffff] { block QACCESS_CODE };
8 W% m0 ?" D9 ]# a( s0 i6 g6 { Section Kind Address Size Object& f5 Q# x9 x' G& ]; |* U# C( g
------- ---- ------- ---- ------
' G2 d2 J6 |( a- t0 e"P7": 0x3c
9 ?! x Y' S; d3 B6 `7 u1 b5 V QACCESS_CODE 0x0 0x3c [B]
( t/ ^$ J V" e# N E5 s* Z CodeQuickAccess ro code 0x0 0x3c clock_config.o [4]3 `; T9 H7 h. F: A, O* U# T
- 0x3c 0x3c
$ E. |+ y7 ^9 M1 C' s*******************************************************************************
! T0 e" U ~7 b6 {( U8 `*** MODULE SUMMARY
R! T4 v1 E' I9 G* d***. r) o* y5 V# T, Q) w
Module ro code ro data rw data
. ~; Y6 n& [* a ------ ------- ------- -------/ Y6 w6 h6 v7 K4 w. o$ \
clock_config.o 2'768 784- k" X% u1 p* X H& J# q7 E
*******************************************************************************
+ f. k" f) w' m9 c9 m% N*** ENTRY LIST i( e" j4 p4 |; R6 H, h
***
1 ^, `$ u. ] j9 G Entry Address Size Type Object
$ Z1 h4 s5 x4 L! w) t( r+ F/ h ---- ------- ---- ---- ------ I7 `8 V, S" I) M* p
UpdateSemcClock 0x1 0x3c Code Gb clock_config.o [4]% D+ G- ~3 O: k2 p+ v
三、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è)計(jì)有關(guān)。/ ]7 g s* R; z
經(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è)計(jì)有某種內(nèi)在關(guān)聯(lián)。9 I8 o- a& i' Q2 e- |" L/ _
RT-Thread 代碼:https://gitee.com/rtthread/rt-thread/blob/gitee_master/src/components.c |
|