|
大家好,我是痞子衡,是正經(jīng)搞技術的痞子。今天痞子衡給大家分享的是在IAR開發(fā)環(huán)境下RT-Thread工程函數(shù)重定向失效分析。
8 _$ ]& T- }9 z7 q* o& \痞子衡舊文 《在IAR下將關鍵函數(shù)重定向到RAM中執(zhí)行的方法》 里介紹了三種關鍵函數(shù)重定向方法,不過這三種方法只是寫法形式不同,本質(zhì)上沒啥區(qū)別,都是利用 IAR 鏈接器特性將函數(shù)重定向到工程數(shù)據(jù)段(RW)所在 RAM 里。
: a; l0 |% ~9 s$ _- a6 W" J; f對于 i.MXRT 這種擁有多塊地址非連續(xù)的 RAM 的芯片,其實我們也可以單獨將這些重定向函數(shù)放到一個指定的 RAM 里,不一定非得跟數(shù)據(jù)段放在同一個 RAM 里。具體實現(xiàn)也很簡單,只需要在鏈接文件里額外加一句 place in 語句處理即可,恩智浦官方 SDK 包里就是這么做的。: o0 W% r6 B# O" u9 @! O7 D: @
然而痞子衡最近在移植一個 i.MXRT1170 RT-Thread 工程時發(fā)現(xiàn),在 IAR 鏈接文件里用自定義段來單獨指定重定向函數(shù)到 ITCM 竟然失效了,這是怎么回事?今天我們一起來看一下:
/ k' A* O6 l: S. oNote 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 預編譯宏里有 XIP_BOOT_HEADER_DCD_ENABLE=1),即代碼段放在 Flash 里(0x30000000 - ),數(shù)據(jù)段放在 SDRAM 里(0x80000000 - )。
4 e# h& W4 {9 ?0 _在時鐘初始化函數(shù) BOARD_BootClockRUN() 里會調(diào)用如下 UpdateSemcClock() 函數(shù),這個函數(shù)需要重定向到 RAM 里執(zhí)行,在代碼里先將它放到自定義 CodeQuickAccess 段里。
/ y* V( T* C( |2 W#define AT_QUICKACCESS_SECTION_CODE(func) func @"CodeQuickAccess"
+ p8 e+ ^4 S$ Y8 R3 |% e#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
]& e- n4 e$ J. I6 d/ V#if defined(XIP_BOOT_HEADER_DCD_ENABLE) && (XIP_BOOT_HEADER_DCD_ENABLE == 1)
2 ]% K1 o' J& jAT_QUICKACCESS_SECTION_CODE(void UpdateSemcClock(void));1 `% m6 B0 o* m7 R, N/ D0 Z9 Q$ D
void UpdateSemcClock(void)
+ k) j: j% Q5 t9 J8 R% ^4 b9 b{4 f# A7 E5 j( u: f7 P8 z
SEMC->IPCMD = 0xA55A000D;
. ?- _0 L8 s* N' n, N0 _ while ((SEMC->INTR & 0x3) == 0);* j1 J! b7 e6 X6 m2 ?+ c
SEMC->INTR = 0x3;3 B! H d N9 F, u
SEMC->DCCR = 0x0B;# @* N- s) {+ Z6 p v
CCM->CLOCK_ROOT[kCLOCK_Root_Semc].CONTROL = 0x602;1 \$ b' _7 x4 r3 @7 [' {+ |
}2 B0 I7 [& q# J1 a2 {2 f
#endif7 s3 C) Y1 W! B, L7 k
#endif! @; l7 j/ I; e! |/ z2 {3 `
然后在工程鏈接文件 MIMXRT1176xxxxx_cm7_flexspi_nor_sdram.icf 里(僅摘錄部分),再將 CodeQuickAccess 段單獨放在 ITCM 里(0x00000000 - ),這就是官方 SDK 里的做法。
+ r5 | R S7 P5 ~0 K$ }( H$ [define symbol m_data3_start = 0x80000000;
$ G* _: a) a0 {! R5 rdefine symbol m_data3_end = 0x82FFFFFF;
! d2 Q" x0 Z, ]9 b: Tdefine symbol m_qacode_start = 0x00000000;( I& m5 O* P7 N
define symbol m_qacode_end = 0x0003FFFF;# o T8 s- w. v3 b7 q' `
define region DATA3_region = mem:[from m_data3_start to m_data3_end-__size_cstack__];1 ?5 J4 w! S! S! k& p
define region QACODE_region = mem:[from m_qacode_start to m_qacode_end];( {3 M: R/ r# I: C
define block RW { first readwrite, section m_usb_dma_init_data };8 Z3 E! L. C0 P$ L) o) J8 g* X
define block QACCESS_CODE { section CodeQuickAccess };
. l8 o" w& ^; Y8 zinitialize by copy { readwrite, section .textrw, section CodeQuickAccess };4 u5 a' h( w1 |0 V2 ~. B Q
place in DATA3_region { block RW };
! Q$ _6 Q; u/ oplace in QACODE_region { block QACCESS_CODE };
( Y0 t+ }" \7 i! H, c/ m編譯鏈接 hello_world_demo_cm7.ewp 工程,然后查看其映射文件(hello_world_demo_cm7.map)找到跟 UpdateSemcClock() 函數(shù)相關的內(nèi)容如下,顯然這是符合預期的。這里特別注意一下,CodeQuickAccess 的類別顯示的是 inited,表明其不是常見的 ro code,而是經(jīng)過重定向的,而且 UpdateSemcClock() 函數(shù)所在 clock_config.o 里包含了 60個字節(jié)的 rw code。
, c ^; N2 H- F+ a( p*******************************************************************************
3 c- u" w. w. I1 ^+ W6 Y0 t*** PLACEMENT SUMMARY. @( X( f) e) H+ b6 v* p
***
7 x" w# N0 [0 J i i+ adefine block QACCESS_CODE { section CodeQuickAccess };8 h) X6 b9 J) L' ^2 Y
"P7": place in [from 0x0 to 0x3'ffff] { block QACCESS_CODE };
1 s7 H( u6 H4 ~8 A3 s- r Section Kind Address Size Object! I0 P3 J7 \, a1 W3 D' q
------- ---- ------- ---- ------
4 B& V2 f% a1 g* A8 k"P7": 0x3c
$ O, s/ S& P. Z) I7 t# u, { QACCESS_CODE 0x0 0x3c [B]3 q( F& h y- N' |
QACCESS_CODE-1 0x0 0x3c [I] s' S4 X. R- |9 [6 V
CodeQuickAccess inited 0x0 0x3c clock_config.o [1]
3 _4 S5 b8 @; o1 Z; s% w - 0x3c 0x3c
' |0 s* z$ `, p9 C, G/ q*******************************************************************************
r7 D- F! t1 B, Y! N5 W*** MODULE SUMMARY
% Q( Z- u5 D# O4 U***
& n+ R" @, `$ e: M Module ro code rw code ro data rw data
1 |8 m& o& e. k+ {0 e ------ ------- ------- ------- -------
1 ~0 K3 L* r( Z2 r+ n7 ? q! Q clock_config.o 2'644 60 844 I. P. x6 P5 J% v6 t) i- ]; @7 T
*******************************************************************************7 H# U( M0 Q9 g' `2 E" L
*** ENTRY LIST
/ M" m$ N5 C* F) z***7 l. X% V. ]0 F# L& d v9 b
Entry Address Size Type Object
# B' w8 h# B4 \6 p: k7 T ---- ------- ---- ---- ------* k7 _& r' I; t) I4 h! ^
UpdateSemcClock 0x1 0x3c Code Gb clock_config.o [1]
7 Y v1 m" J) O$ S# A- G二、引出RT-Thread下函數(shù)重定向失效問題現(xiàn)在來看 RT-Thread 工程,也是一個簡單的 hello world(具體工程略去不表),其中 i.MXRT1170 芯片 BSP 部分直接來自于官方 SDK,鏈接文件也與 SDK 里一致,但是編譯鏈接工程后查看其映射文件,發(fā)現(xiàn)跟 UpdateSemcClock() 函數(shù)相關的內(nèi)容如下,CodeQuickAccess 的類別顯示的是 ro code, UpdateSemcClock() 函數(shù)所在 clock_config.o 里干脆連 rw code 都沒有。顯然函數(shù)重定向失效了,鏈接文件里 initialize by copy { section CodeQuickAccess }; 語句沒起作用,這顯然就是一個分散鏈接而已。/ | c) o" b2 M; K2 X
*******************************************************************************2 S% J. n4 B4 ~
*** PLACEMENT SUMMARY* g4 b! I7 E. ^' Q- l3 _. a
***
5 s6 f5 G b6 G+ z5 qdefine block QACCESS_CODE { section CodeQuickAccess };
- e7 U9 P4 h5 u; p; `/ E$ u! t"P7": place in [from 0x0 to 0x3'ffff] { block QACCESS_CODE };
' y! g9 y. I8 a" T Section Kind Address Size Object/ [9 n$ [, B! j- @" g# @' v
------- ---- ------- ---- ------, s( b0 p. u9 T) _" T; `
"P7": 0x3c
& W7 U6 i$ Y4 w QACCESS_CODE 0x0 0x3c [B]
# X* N. p% K7 X* {# C$ J! R CodeQuickAccess ro code 0x0 0x3c clock_config.o [4]% t9 D1 g9 {4 d
- 0x3c 0x3c/ D& v- I: e- K+ O5 f
*******************************************************************************; A- \; W& @7 _0 `0 s7 O
*** MODULE SUMMARY
6 K9 G+ \) H. A% ]+ z# B& }% r***
3 q9 l; W2 T4 X( z5 l Module ro code ro data rw data& J$ `: e- @% p1 x
------ ------- ------- -------
" c4 \& p4 [- S3 ] w5 C" ~% a9 W clock_config.o 2'768 784
7 l' I& N# }5 c* J: h* o5 k V*******************************************************************************
. C2 e/ q- p s. I5 a0 c*** ENTRY LIST
6 ], S" o6 k" l6 ]* ]. d# Q***' C0 p7 _ N- E4 ]
Entry Address Size Type Object6 x+ d. t. w' H* o
---- ------- ---- ---- ------1 S4 u: ], F, s0 ?( G
UpdateSemcClock 0x1 0x3c Code Gb clock_config.o [4]
: V0 \* @( r2 [! O! W三、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 內(nèi)核啟動是在 main() 里),所以這個問題主要跟 RT-Thread 內(nèi)核代碼結(jié)構設計有關。
+ V& ?2 B' L* r4 U+ g) h3 K經(jīng)過裸機工程、RT-Thread 工程、FreeRTOS 工程三者對比,痞子衡找到了問題所在。RT-Thread 內(nèi)核啟動是在 /src/components.c 文件中的 __low_level_init() 函數(shù)里,而這個 __low_level_init() 函數(shù)本應是 IAR 入口函數(shù) __iar_program_start() 中的一部分(IAR 系統(tǒng)庫里有一個內(nèi)置 PUBWEAK 版本),但是 RT-Thread 重實現(xiàn)了這個 __low_level_init() 函數(shù),很不幸的是 IAR 鏈接器對于自定義段的函數(shù)重定向認定與原內(nèi)置 __low_level_init() 函數(shù)設計有某種內(nèi)在關聯(lián)。
1 e; Z8 F/ w& j! P! B/ qRT-Thread 代碼:https://gitee.com/rtthread/rt-thread/blob/gitee_master/src/components.c |
|