電子產(chǎn)業(yè)一站式賦能平臺(tái)

PCB聯(lián)盟網(wǎng)

搜索
查看: 48|回復(fù): 0
收起左側(cè)

深扒IAR啟動(dòng)函數(shù)流程里RW/ZI段初始化實(shí)現(xiàn)

[復(fù)制鏈接]

302

主題

307

帖子

1896

積分

三級(jí)會(huì)員

Rank: 3Rank: 3

積分
1896
跳轉(zhuǎn)到指定樓層
樓主
發(fā)表于 2021-11-27 23:19:00 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
大家好,我是痞子衡,是正經(jīng)搞技術(shù)的痞子。今天痞子衡給大家分享的是IAR啟動(dòng)函數(shù)流程里的段初始化函數(shù)__iar_data_init3實(shí)現(xiàn)。
$ f6 F& x, t! R" c本篇是 《IAR啟動(dòng)函數(shù)流程及其__low_level_init設(shè)計(jì)對(duì)函數(shù)重定向的影響》 一文的后續(xù),在上篇文章里我們?cè)?IAR 軟件安裝目錄下找到了標(biāo)準(zhǔn)啟動(dòng)函數(shù) __iar_program_start() 相關(guān)源文件,并且分析了 __iar_program_start() 函數(shù)里的全部動(dòng)作。我們知道了其中負(fù)責(zé) .data/.bss/.textrw 段初始化工作的是 __iar_data_init3() 函數(shù),但是這個(gè)函數(shù)的具體實(shí)現(xiàn)并沒(méi)有詳細(xì)介紹,今天我們就仔細(xì)說(shuō)說(shuō)這個(gè) __iar_data_init3() 函數(shù):# G7 o8 T6 f3 \: i4 V
  • Note 1:閱讀本文前需要對(duì) 《IAR鏈接文件(.icf)》 有所了解。
  • Note 2:本文使用的 IAR EWARM 軟件版本是 v9.10.2。一、為什么有些段需要初始化?《IAR鏈接文件(.icf)》 一文第一小節(jié)列出了 IAR 工程里定義的全部系統(tǒng)段(Section)名,其中 .data/.bss/.textrw 段是需要初始化的,因?yàn)檫@些段是鏈接在 RAM 里,而 RAM 上電其內(nèi)容都是隨機(jī)值,所以需要一段啟動(dòng)代碼將 .data/.bss/.textrw 段所在的 RAM 區(qū)填上對(duì)應(yīng)的初值(初值來(lái)自于下載了程序鏡像文件的 Flash 區(qū)),然后應(yīng)用程序才能正常運(yùn)行。+ b) p. I+ w4 s; f
  • Note: 除了 .data/.bss/.textrw 之外,還有一些段(.noinit/CSTACK/HEAP等)也鏈接在 RAM 區(qū),但這些段對(duì)初值沒(méi)有依賴,所以不需要初始化。.bss                 // 初值為 0 的靜態(tài)/全局變量(RAM)# r# X$ {; ~5 l% F4 J2 c
    .data                // 初值為非 0 的全局變量(RAM)9 [; n; W, f" l! G. z" B
    .data_init           // .data 段的初值(Flash)
    , g5 u7 e5 I9 v2 U/ g& @.textrw              // __ramfunc 修飾的重定向函數(shù)實(shí)際執(zhí)行區(qū)(RAM)+ E# k/ n) {' X2 F' p  I
    .textrw_init         // .textrw 段的機(jī)器碼存儲(chǔ)區(qū)(Flash)
    0 S( z! X- _, y- A( L二、RW/ZI段初始化的一般實(shí)現(xiàn)應(yīng)用程序工程在編譯鏈接結(jié)束后,.data/.bss/.textrw 段實(shí)際鏈接地址就確定了(這里指默認(rèn)由 IAR 鏈接器自由分配具體鏈接地址,而不是用戶在鏈接文件中指明具體鏈接地址的情況),我們知道了這些段的鏈接地址,就可以完成對(duì)應(yīng)初始化工作(說(shuō)白了,就是初值數(shù)據(jù)從 Flash 到 RAM 的拷貝工作),實(shí)際鏈接地址可以通過(guò)如下 IAR 鏈接器提供的接口來(lái)獲取,具體拷貝過(guò)程可參看 《IAR下將關(guān)鍵函數(shù)重定向到RAM中執(zhí)行的方法》 一文最后一節(jié)里的代碼。
    2 O! o" D, H" D, h' [) K+ R, b
  • Note: IAR 鏈接器為了后續(xù)初始化的方便,都是將程序中全部的全局變量緊挨著放到一塊連續(xù)的 RAM 區(qū)域(.data),然后其全部初值也一一對(duì)應(yīng)緊挨著放一起(.data_init,下載到一塊連續(xù)的 Flash 區(qū));對(duì)于 .textrw 的處理也類似。#pragma section = ".data"
    ; \2 F7 l- N) m, Q#pragma section = ".data_init"
    : J( I9 ]! d/ F* |" V#pragma section = ".bss"
    / O% g$ B* I8 L  @#pragma section = ".textrw"4 n6 u/ h! V' B8 V% s. H
    #pragma section = ".textrw_init"5 ?- d1 h3 s8 \" j1 e% n! C6 c
    uint8_t *data_ram              = __section_begin(".data");- k1 N: X" F( [, I$ s! [, q3 ]
    uint8_t *data_rom              = __section_begin(".data_init");
    # u# K& l3 K$ ?2 Auint8_t *data_rom_end          = __section_end(".data_init");: x, E4 x/ i1 f7 w  n  f: S0 W
    uint8_t *bss_start             = __section_begin(".bss");9 i9 B3 I3 v/ V, s2 n
    uint8_t *bss_end               = __section_end(".bss");
    : K8 k1 `( p5 y8 j% w: E. j8 B" zuint8_t *code_relocate_ram     = __section_begin(".textrw");6 {# T9 m) k- [: J* F8 q7 z0 Z
    uint8_t *code_relocate_rom     = __section_begin(".textrw_init");
    , W2 d' L+ y8 ouint8_t *code_relocate_rom_end = __section_end(".textrw_init");4 I! u& m' M$ k6 D
    段初始化的一般實(shí)現(xiàn)雖然簡(jiǎn)單,但有個(gè)缺點(diǎn),就是對(duì)于用戶自定義 RW/ZI 段或者多個(gè)分散的 RW/ZI 段無(wú)法自動(dòng)適應(yīng),需要根據(jù)實(shí)際情況不斷調(diào)整代碼實(shí)現(xiàn)。7 h. p, Q. S8 \
    三、__iar_data_init3() 函數(shù)實(shí)現(xiàn)細(xì)節(jié)前面鋪墊了這么多,終于到了圍觀 IAR 標(biāo)準(zhǔn)段初始化函數(shù) __iar_data_init3() 實(shí)現(xiàn)的時(shí)候了,跟這個(gè)函數(shù)相關(guān)的源文件在如下路徑下,核心代碼在 data_init.c 文件中:
    9 G& U% s' I; L) s( d5 _% \, x! g; Z\IAR Systems\Embedded Workbench 9.10.2\arm\src\lib\init\data_init.c6 k1 v# L5 R; Y2 I! j
    \IAR Systems\Embedded Workbench 9.10.2\arm\src\lib\init\zero_init3.c  - 存放 __iar_zero_init3 函數(shù)
    ; u+ F  w! U' \5 @: b0 n1 X\IAR Systems\Embedded Workbench 9.10.2\arm\src\lib\init\copy_init3.c  - 存放 __iar_copy_init3 函數(shù)
    ! r1 \  `) `) B# b% n* w: y在 data_init.c 文件中有一個(gè)叫 IAR_DATA_INIT 的函數(shù),其實(shí)它就是 __iar_data_init3,光看這個(gè)函數(shù)里的代碼會(huì)讓人有點(diǎn)摸不著頭腦,因?yàn)橛昧?IAR 鏈接器里的接口及一些特殊定義,我們結(jié)合一個(gè)具體應(yīng)用程序工程來(lái)講解會(huì)更清晰。
    - `  |- r" ^# |. ?// 在 IAR 目錄 \arm\inc\c\DLib_Product.h 中宏定義
    6 s# @0 j& L3 ?) o* y#define _DLIB_ELF_INIT_INTERFACE_VERSION 36 I, X: u  N5 t2 S* M6 u
    // 在 IAR 目錄 \arm\src\lib\init\data_init.h 中的宏定義" I+ s: j6 E$ ?! _, ~1 T& d" l
    #define IAR_DATA_INIT _GLUE(__iar_data_init, _DLIB_ELF_INIT_INTERFACE_VERSION)7 y; q. B; B; u9 h9 y: c% \. N" r
    #pragma section = "Region$$Table" const TABLE_MEM
    / I( @  g3 i1 V) }$ G, `) Xvoid IAR_DATA_INIT(void)
    1 s; E* _, K9 i7 ]{- p" t, ?$ q+ ^
        FAddr TABLE_MEM const * pi = __section_begin("Region$$Table");
    1 }7 d0 j7 t, _    table_ptr_t             pe = __section_end  ("Region$$Table");
      s, X8 m/ b' A- M$ h! Z+ o8 G# @" D    while (pi != pe)% Z. t9 W  Y9 j. {' V
        {
    ( p5 z$ \9 s4 U        init_fun_t * fun = FAddr_GetPtr(pi);( \( [0 ?: A+ y+ D
            ++pi;
    1 f/ J& K% Z, t- c1 Z        pi = fun(pi);" O/ ]& h, Y1 o; |. Q- T
        }, {! n$ u  G  a( ~# w: _* d
    }
    : n1 o+ p+ _" G! w我們現(xiàn)在隨便編譯一個(gè) SDK 例程(痞子衡選擇的是 \SDK_2.11.0_MIMXRT1170-EVK\boards\evkmimxrt1170\demo_apps\hello_world\cm7\iar,切到 flexspi_nor_debug build,即代碼 RO 段鏈接在 0x30000000 開(kāi)始的 Flash 區(qū),代碼 RW 段鏈接在 0x20000000 開(kāi)始的 DTCM 區(qū)),查看其對(duì)應(yīng)映射文件(.map),摘出其中跟段初始化相關(guān)的一些內(nèi)容如下,初始化工作包含:利用 __iar_zero_init3 函數(shù)清零起始地址為 0x20000040 長(zhǎng)度為 0x4c 字節(jié)的 ZI 段空間,利用 __iar_copy_init3 函數(shù)拷貝 0x40 字節(jié) RW 段數(shù)據(jù)(從 0x300060fc 到 0x20000000):% b/ V7 d, y& z
    *******************************************************************************
    * `3 _- E( t1 b8 V% U2 Y4 q*** INIT TABLE
    & s2 E3 A; q2 c& D***6 p" w) z& e# q! `! |
              Address      Size- T  m6 P; h0 `" _# F) p$ L
              -------      ----
    - p9 U3 T" k9 M+ q) m2 W: b0 V! tZero (__iar_zero_init3)
    2 u1 m1 y! }- u  a% g7 t    1 destination range, total size 0x4c:$ Q& O' J: c7 `# c1 u9 r9 J1 l+ `
              0x2000'0040  0x4c
    , G* M' ^9 y5 D$ c6 a3 m, b* H$ RCopy (__iar_copy_init3)# @! V* P+ o# z; O
        1 source range, total size 0x40:
    6 f' R, f% y. P! A7 J* j. s          0x3000'60fc  0x40/ q, p$ v' k8 w  H# b& i
        1 destination range, total size 0x40:; G5 O# d- R: [
              0x2000'0000  0x402 h0 ?) Z& [" h( O
    *******************************************************************************: d' Q0 Y: D# l2 G# J4 a
    *** ENTRY LIST
    . A& X. R# _# j+ g" t" w***
    6 G4 E) Q0 i! M, ?6 F) M, E' P: {$ ]Entry                       Address   Size  Type      Object2 e8 m' }( g- B8 O
    ----                       -------   ----  ----      ------
    , {9 R! u, v8 Y9 c3 D( A/ |.iar.init_table$$Base   0x3000'63d4          --   Gb  - Linker created -
    4 s8 x8 j5 _0 t; K.iar.init_table$$Limit  0x3000'63f8          --   Gb  - Linker created -3 b3 f8 _# C' z7 M. V
    Region$$Table$$Base     0x3000'63d4          --   Gb  - Linker created -
    * C- B  W, i0 F- I" d! ZRegion$$Table$$Limit    0x3000'63f8          --   Gb  - Linker created -
      S% D6 r, p1 U" v7 v__iar_copy_init3        0x3000'630d   0x2c  Code  Gb  copy_init3.o [6]/ o- [  p" E7 C
    __iar_zero_init3        0x3000'613d   0x3c  Code  Gb  zero_init3.o [6]" m: L* @0 C9 A: B" q
    在映射文件里,我們知道了 Region$$Table 區(qū)域的起止地址 [0x300063d4 - 0x300063f8),打開(kāi)鏡像文件或者在線調(diào)試找到這段區(qū)域里的內(nèi)容,你會(huì)發(fā)現(xiàn)段初始化工作所需的全部信息(操作函數(shù)地址、操作數(shù)據(jù)長(zhǎng)度、操作源地址、操作目標(biāo)地址)都記錄在里面,其中特別注意的是涉及 Flash 區(qū)的地址都是以相對(duì)地址來(lái)存放的:) d2 Z- [4 u; o2 X1 o
  • Note:FAddr_GetPtr 函數(shù)負(fù)責(zé)地址轉(zhuǎn)換,0x300063d4 地址處的值是 0xfffffd69,那么 0x300063d4 + 0xfffffd69 = 0x13000613d,保留低 32bit 即是 __iar_zero_init3 函數(shù)地址。
  • 發(fā)表回復(fù)

    本版積分規(guī)則


    聯(lián)系客服 關(guān)注微信 下載APP 返回頂部 返回列表