找回密码
 注册
关于网站域名变更的通知
查看: 373|回复: 1
打印 上一主题 下一主题

Cortex-M/R 内核启动过程 / 程序启动流程之启动流程

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2020-10-28 13:21 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
- q# L8 @3 L+ h
启动流程
& I/ G" y/ T; v- l: H0 h' @7 k* @  d  嵌入式应用程序在用户定义的 main() 函数启动之前需要初始化序列。 这称为启动代码或启动代码。 ARM C 库包含启动应用程序所必需的预编译和预组装代码段。链接应用程序时,链接器会根据应用程序从 C 库中包含必要的代码,以便为应用程序创建自定义启动代码。但需要注意的是,ARM 自己的编译套件提供了如下三种库:! ?% ]) `, _3 w. H6 ?% J* W7 ~

8 j3 b8 m, U1 u0 ^+ s * C' f1 Z, z/ ]1 b/ H' Y
* i( Y2 V! Y2 a, f+ `& K
根据ARM官方的文档说明,以下分析描述的启动代码适用于标准 ARM C 库。 它不适用于 ARM C 微库。 启动流程同样适用于 ARMv4T 及更高版本的架构。如下图清晰的表示了程序启动到用户的main() 之前的流程:& ]+ G1 W- J9 b% c3 ?5 R
6 O0 Z, l+ s0 e

! u7 K9 ?% ^0 H9 u* r$ f0 g
5 w3 I" ?. c: X. T__main! M: ?, k4 Y# U* J$ `1 k
  函数__main是C库的入口点。 除非您更改它,否则__main是ARM链接器(armlink)在创建映像时使用的ELF映像的缺省入口点。 下图显示了C库启动期间__main调用的函数。7 ?1 `# l  b2 U6 s/ G# @# {

1 ^& |  W2 c! |0 h: Y
+ ^% G, M$ }- {" Y& w' w% ^* ^" l) x! u6 {! [7 G9 }. D
__scatterload
7 N( _* |8 E3 i. [/ ?7 A8 l  Application code and data can be in a root region or a non-root region. Root regions have the same load-time and execution-time addresses. Non-root regions have different load-time and execution-time addresses. The root region contains a region table output by the ARM linker.应用程序代码和数据可以位于根区域或非根区域中。 根区域具有相同的加载时间和执行时间地址。 非根区域具有不同的加载时间和执行时间地址。 根区域包含ARM链接器输出的区域表。
6 I$ E8 z: N6 H+ Q8 y9 Y  The region table contains the addresses of the non-root code and data regions that require initialization. The region table also contains a function pointer that indicates what initialization is needed for the region, for example a copying, zeroing, or decompressing function. region表包含需要初始化的非根代码和数据区域的地址。 区域表还包含一个函数指针,指示区域需要初始化,例如复制,归零或解压缩功能。2 D* r6 _8 y+ D3 Q7 E. U) @# v- p
__scatterload遍历区域表并初始化各种执行时区域。 功能如下:6 f' M- `, {, F2 v
! \* x6 @3 U" Z" _. y4 }
Initializes the Zero Initialized (ZI) regions to zero
5 a3 d% ]; v4 v! I. t3 T; Q% `7 ^Copies or decompresses the non-root code and data region from their load-time locations to the execute-time regions.
' X* b$ a7 ?+ N/ T' ]__main always calls this function during startup before calling __rt_entry .
5 O/ o* v) ?& t/ z9 l. N  [3 C9 S( i! _; `' y5 U  y
__rt_entry
: c7 r  s7 e+ k) N7 o+ I  __main调用__rt_entry来初始化堆栈,堆和其他C库子系统。__rt_entry调用各种初始化函数,然后调用用户级main()。以下列出了_rt_entry可以调用的函数。 这些函数按它们被调用的顺序列出:
: B! q7 g% `6 \" S0 i5 u& I
" L% ^" R- _" o_platform_pre_stackheap_init+ d  [7 f6 h3 _0 ]
__user_setup_stackheap or setup the Stack Pointer (SP) by another method& L9 i% T$ r* n4 I
_platform_post_stackheap_init
' M, Z, T, v0 @  H( u* s' x__rt_lib_init
) z6 V& Q: V& A, V. c- q6 c_platform_post_lib_init
  O3 {0 z+ W/ o2 Y3 _0 Wmain()
7 }; ]- i' S$ J, U* a% C/ R7 n! nexit()
0 a1 n" F4 n) W4 x( i" G3 X; Dplatform *函数不是标准C库的一部分。 如果你定义它们,则链接器会在__rt_entry中对它们进行调用。$ f! l7 M1 n% a/ j
main()是用户级应用程序的入口点。 寄存器r0和r1包含main()的参数。 如果main()返回,则将其返回值传递给exit()并退出应用程序。
6 k1 H6 D+ H9 d: l# [. I__rt_entry还负责设置堆栈和堆。 但是,设置堆栈和堆取决于用户指定的方法。 可以通过以下任何方法设置堆栈和堆:
; a& B0 s4 G/ _! \; r  _2 y1 u: j, \6 D' C4 v9 g9 w
调用__user_setup_stackheap。 这也获得了堆使用的内存边界(堆顶部和堆基)。1 Y4 p, \& E9 [! _& Y; X
使用符号__initial_sp的值加载 SP。: e" B' d, f2 K" y4 D) F
Using the top of the ARM_LIB_STACK or ARM_LIB_STACKHEAP region specified in the linker scatter file.
  \' ?6 N% X9 t  __rt_entry and __rt_lib_init do not exist as complete functions in the C library. Small sections of these functions are present in several internal objects that are part of the C library. Not all of these code sections are useful for a given user application. The linker decides which subset of those code sections are needed for a given application, and includes just those sections in the startup code. The linker places these sections in the correct order to create custom __rt_entry and __rt_lib_init functions as required by the user application.__rt_entry和__rt_lib_init在C库中不作为完整函数存在。这些函数的小部分存在于作为类库一部分的几个内部对象中。并非所有这些代码段都对给定的用户应用程序有用。链接器决定给定应用程序需要这些代码段的哪个子集,并且只在启动代码中包含这些部分。链接器按照正确的顺序放置这些部分,以便根据用户应用程序的要求创建自定义的__rt_entry和__rt_lib_init函数。
) I' Z6 L0 s" O, ]- L" a/ D5 t( m& T  _; y% V1 S3 g4 x" q
_platform_pre_stackheap_init: h. O5 q2 Q- ~8 e" U4 |) X
  The standard C library does not provide this function but you can define it if you require it. You can use this function to setup hardware for example. __rt_entry calls this function, if you define it, before the code that initializes the stack and heap. 标准C库不提供此函数,但您可以根据需要定义它。 例如,您可以使用此函数设置硬件。如果您定义了该函数,那么`__rt_entry会在初始化堆栈和堆的代码之前调用此函数。
, P# q5 K$ y$ H5 N& X
0 E, M) ]. d# b$ O- ?/ @__user_setup_stackheap; q7 M6 Q. a3 x+ O
  This function enables you to setup and return the location of the initial stack and heap. The C library does not provide this function but you can define it if you require it. __rt_entry calls this function if you define it or if you define the legacy function __user_initial_stackheap . If you define __user_initial_stackheap , then the C library provides a default __user_setup_stackheap as a wrapper around your __user_initial_stackheap function. 此函数使您可以设置并返回初始堆栈和堆的位置。C库不提供此函数,但您可以根据需要定义它。 如果你定义了该函数或者定义了老版本的函数__user_initial_stackheap,那么__rt_entry 会调用此函数。 如果定义了__user_initial_stackheap,则C库提供默认的__user_setup_stackheap作为__user_initial_stackheap函数的包装器。, Z1 L0 C) C1 G; j

9 k  }2 ?. T' u0 E! K_platform_post_stackheap_init
3 C# I3 S: \, v  The C library does not provide this function but you can define it if you require it. You can use this function to setup hardware for example. __rt_entry calls this function, if you define it, after the code that initializes the stack and heap. C库不提供此功能,但您可以根据需要定义它。 例如,您可以使用此功能设置硬件。 如果您定义了该函数,那么__rt_entry会在初始化堆栈和堆的代码之后调用此函数。1 d1 R, K# i) @4 E
  Q9 m$ x4 s# q2 H% ]
__rt_lib_init7 x7 B( p9 }# {. A
  This function initializes the various C library subsystems. It initializes the referenced library functions, initializes the locale and, if necessary, sets up argc and argv for main() . __rt_entry calls this function always during startup.此函数初始化各种C库子系统。 它初始化引用的库函数,初始化语言环境,并在必要时为main()设置 argc 和 argv。 __rt_entry在启动期间始终调用此函数。
3 f# l) c3 m# q+ A$ C  If you use the __user_setup_stackheap or __user_initial_stackheap functions to setup the stack pointer and heap, then the start and end address of the heap memory block are passed as arguments to __rt_lib_init in registers r0 and r1 respectively.如果使用了函数__user_setup_stackheap 或函数 __user_initial_stackheap来设置堆栈指针和堆,那么堆内存块的起始和结束地址将作为参数通过寄存器 r0 和 r1传递给__rt_lib_init。
8 R0 z1 L/ y9 }+ O  The function returns argc and argv in registers r0 and r1 respectively if the user-level main() requires them. 如果用户级main()需要,该函数分别在寄存器 r0 和 r1 中返回argc和argv。
# F8 t* k) |' C6 G/ {0 s
* p5 q2 H3 Q! p+ D& hThe linker includes various initialization code sections from the internal object files to create a custom __rt_lib_int function. The linker places a function in __rt_lib_init only if it is needed by the application. This lists the functions that _rt_lib_init can call. The functions are listed in the order they get called:链接器包括内部对象文件中的各种初始化代码部分,以创建自定义__rt_lib_int函数。 只有在应用程序需要时,链接器才会在__rt_lib_init中放置一个函数。 以下列出了_rt_lib_init可以调用的函数。 这些函数按它们被调用的顺序列出:8 v, J* ]! D% @2 S. }
4 c( C/ Y. |! d0 r: Y
_fp_init
- V. I6 V# c0 L_init_alloc
6 H7 Y; j* W& f& p  W& s_rand_init0 _- E& }: d2 }: I5 k5 O
_get_lc_collate
; R+ _' s! A5 Z+ [! f8 I/ X_get_lc_ctype
7 s$ W/ B! b2 Y8 m_get_lc_monetary
( Y9 r5 E; ?# ^0 m9 D& }2 I, D  B: e_get_lc_numeric$ v# K. f- r- W
_get_lc_time" H* j/ |% U0 m6 s# |- N. c
_atexit_init. r8 u& A6 M' u( K# d( g
_signal_init. }8 Y  v) J. n- `0 d
_fp_trap_init7 d: G+ C( D" i# Q
_clock_init
3 e3 w$ k$ G: @! M3 O_getenv_init
# f# n7 }& }4 d+ \_initio
5 @: l; W& y# S- C! y_ARM_get_argv
0 n- |. b7 A6 z) w_alloca_initialize
7 T  y; l+ b% @_ARM_exceptions_init0 R7 K; @9 X( Q
_cpp_initialize__aeabi5 `) k, w, D6 S& t: X8 o- R
这里就不一一介绍各函数了,想进一步了解的去查看官方文档即可!; U7 ]& b3 N' I1 V/ m
  M2 b4 M- ?1 |( M) P
_platform_post_lib_init
, P  H8 ?5 X: W3 Z  The C library does not provide this function but you can define it if you require it. You can use this function to setup hardware for example. __rt_entry calls this function, if you define it, after the call to __rt_lib_init and before the call to the user-level main() function. C库不提供此功能,但您可以根据需要定义它。 例如,您可以使用此功能设置硬件。 如果定义了该函数,那么__rt_entry在调用__rt_lib_init之后和调用用户级main()函数之前,调用此函数。

该用户从未签到

2#
发表于 2020-10-28 14:09 | 只看该作者
Cortex-M/R 内核启动过程 / 程序启动流程之启动流程
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-11-24 23:55 , Processed in 0.171875 second(s), 26 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表