ARM 之九 Cortex-M/R 内核启动过程 / 程序启动流程(基于ARMCC、Keil)

内核规范

  ARM Cortex-M/R 内核的复位启动过程也被称为复位序列(Reset sequence)。ARM Cortex-M/R内核的复位启动过程与其他大部分CPU不同,也与之前的ARM架构(ARM920T、ARM7TDMI等)不相同。大部分CPU复位后都是从 0x00000000 处取得第一条指令开始运行的,然而在ARM Cortex-M/R内核中并不是这样的。其复位序列为:

  1. 从地址 0x0000_0000 处取出 MSP 的初始值;
  2. 从地址 0x0000_0004 处取出PC的初始值,然后从这个值对应的地址处取指。事实上,地址 0x00000004 开始存放的就是默认中断向量表
    在这里插入图片描述
    ARM Cortex-M/R 内核的中断向量表布局情况如下图所示:
    在这里插入图片描述

注意:中断向量表的位置可以改变,此处是默认情况下的设置。

  在 ARM Cortex-M/R 内核中,发生异常后,并不是去执行中断向量表中对应位置处的代码,而是将对应位置处的数据存入PC中,然后去此地址处进行取指。简而言之,在ARM Cortex-M/R的中断向量表中不应该放置跳转指令,而是该放置 ISR 程序的入口地址。另外还有两个细节问题需要注意:

  1. 0x00000000 处存放的 MSP 初始值最低三位需要是 0;
  2. 0x00000004 处存放的地址最低位必须是 1。

  第一条是因为在ARM上编程,但凡涉及到调用,就需要遵循一套规约AAPCS ——《Procedure Call Standard for the ARM Architecture》。AAPCS 中对栈使用的约定是这样的:

5.2.1.1
Universal stack constraints
At all times the following basic constraints must hold:
Stack-limit < SP <= stack-base. The stack pointer must lie within the extent of the stack.
SP mod 4 = 0. The stack must at all times be aligned to a word boundary.
5.2.1.2
Stack constraints at a public interface
The stack must also conform to the following constraint at a public interface:
SP mod 8 = 0. The stack must be double-word aligned.

简而言之,规约规定栈任何时候都必须 4 字节对齐,在调用入口需8字节对齐,而且 SP 的最低两位在硬件上就被置为 0 了。
  第二条与 ARM 模式与 Thumb 模式有关。ARM 中 PC 中的地址必须是 32 位对齐的,其最低两位也被硬件上置 0 了,故写入PC 中的数据最低两位并不代表真实的取址地址。ARM中使用最低一位来判断这条指令是 ARM 指令还是 Thumb 指令,若最低位为 0,代表 ARM 指令;若最低位为 1,代表 Thumb 指令。在 Cortex-M/R 内核中,并不支持 ARM 模式,若强行切换到 ARM 模式会引发一个 Hard Fault。

启动流程

  嵌入式应用程序在用户定义的 main() 函数启动之前需要初始化序列。 这称为启动代码或启动代码。 ARM C 库包含启动应用程序所必需的预编译和预组装代码段。链接应用程序时,链接器会根据应用程序从 C 库中包含必要的代码,以便为应用程序创建自定义启动代码。但需要注意的是,ARM 自己的编译套件提供了如下三种库:
在这里插入图片描述
根据ARM官方的文档说明,以下分析描述的启动代码适用于标准 ARM C 库。 它不适用于 ARM C 微库。 启动流程同样适用于 ARMv4T 及更高版本的架构。如下图清晰的表示了程序启动到用户的main() 之前的流程:
在这里插入图片描述

__main

  函数__main是C库的入口点。 除非您更改它,否则__main是ARM链接器(armlink)在创建映像时使用的ELF映像的缺省入口点。 下图显示了C库启动期间__main调用的函数。
在这里插入图片描述

__scatterload

  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链接器输出的区域表。
  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表包含需要初始化的非根代码和数据区域的地址。 区域表还包含一个函数指针,指示区域需要初始化,例如复制,归零或解压缩功能。
__scatterload遍历区域表并初始化各种执行时区域。 功能如下:

  • Initializes the Zero Initialized (ZI) regions to zero
  • Copies or decompresses the non-root code and data region from their load-time locations to the execute-time regions.

__main always calls this function during startup before calling __rt_entry .

__rt_entry

  __main调用__rt_entry来初始化堆栈,堆和其他C库子系统。__rt_entry调用各种初始化函数,然后调用用户级main()。以下列出了_rt_entry可以调用的函数。 这些函数按它们被调用的顺序列出:

  1. _platform_pre_stackheap_init
  2. __user_setup_stackheap or setup the Stack Pointer (SP) by another method
  3. _platform_post_stackheap_init
  4. __rt_lib_init
  5. _platform_post_lib_init
  6. main()
  7. exit()

platform *函数不是标准C库的一部分。 如果你定义它们,则链接器会在__rt_entry中对它们进行调用。
main()是用户级应用程序的入口点。 寄存器r0r1包含main()的参数。 如果main()返回,则将其返回值传递给exit()并退出应用程序。
__rt_entry还负责设置堆栈和堆。 但是,设置堆栈和堆取决于用户指定的方法。 可以通过以下任何方法设置堆栈和堆:

  • 调用__user_setup_stackheap。 这也获得了堆使用的内存边界(堆顶部和堆基)。
  • 使用符号__initial_sp的值加载 SP。
  • Using the top of the ARM_LIB_STACK or ARM_LIB_STACKHEAP region specified in the linker scatter file.

  __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函数。

_platform_pre_stackheap_init

  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会在初始化堆栈和堆的代码之前调用此函数。

__user_setup_stackheap

  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函数的包装器。

_platform_post_stackheap_init

  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会在初始化堆栈和堆的代码之后调用此函数。

__rt_lib_init

  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在启动期间始终调用此函数。
  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。
  The function returns argc and argv in registers r0 and r1 respectively if the user-level main() requires them. 如果用户级main()需要,该函数分别在寄存器 r0 和 r1 中返回argc和argv。

The 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可以调用的函数。 这些函数按它们被调用的顺序列出:

  1. _fp_init
  2. _init_alloc
  3. _rand_init
  4. _get_lc_collate
  5. _get_lc_ctype
  6. _get_lc_monetary
  7. _get_lc_numeric
  8. _get_lc_time
  9. _atexit_init
  10. _signal_init
  11. _fp_trap_init
  12. _clock_init
  13. _getenv_init
  14. _initio
  15. _ARM_get_argv
  16. _alloca_initialize
  17. _ARM_exceptions_init
  18. _cpp_initialize__aeabi

这里就不一一介绍各函数了,想进一步了解的去查看官方文档即可!

_platform_post_lib_init

  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()函数之前,调用此函数。

ARM 库分析

  上面介绍了各函数,这些函数全部位于 ARM 提供的 C 库中。我们可以参看任意项目的map文件,来看看都用了哪些库,如下:
在这里插入图片描述
其中,左侧的图为 Image Symbol Table 部分;右侧图为 Image component sizes 部分。从中可以看到:

  1. __main 位于 __main.o 中
  2. __scatterload 位于 __scatter.o 中

其他函数同理,这里暂不说明。在右侧可以看到,对应的 C 库文件为c_w.lfz_wm.l 。我们可以在 ARM 编译套件的目录下找到这两个文件,路径如下图所示:
在这里插入图片描述
下面我们使用 ARM 编译套件中相应的工具来看看具体文件。关于编译套件的详细使用说明可以参考博文《ARM 之 主流编译器(armcc、iar、gcc for arm)详细介绍》。具体使用的工具就是armar.exe,这是 ARM 的库文件管理工具。

D:\ARM\ARM_Compiler_5.06u4>armar --zt ./lib/armlib/c_w.l

      Code    RO Data    RW Data    ZI Data      Debug   Object Name
        48          0          0          0         84   version.o
        58          0          0          0         68   __dczerorl.o
        90          0          0          0         68   __dczerorl2.o
       100          0          0          0         68   __dclz77c.o
         0          0         28          0          0   dc.o
       102         12          0          0        240   sys_io.o
        18          0          0          0         76   sys_tmpnam.o
        14          0          0          0         76   sys_wrch.o
        18          0          0          0         76   sys_system.o
        18          0          0          0         76   sys_remove.o
        32          0          0          0         80   sys_rename.o
        24          0          0          0         76   sys_command.o
         4          0          0          0         68   getenv.o
        32          0          4          0         84   sys_clock.o
        18          0          0          0         76   sys_time.o
        12          0          0          0         68   sys_exit.o
         8          0          0         96         68   libspace.o
         2          0          0          0         68   use_semi.o
         2          0          0          0         68   use_no_semi.o
         4          0          0          0         68   mutex_dummy.o
         2          0          0          0         68   use_no_semi_2.o
         0          0          0          0          0   indicate_semi.o
        48          0          0          0         80   sys_stackheap.o
        74          0          0          0         80   sys_stackheap_outer.o
        96          0          0          0          0   tempstk.o
         0          0          0          0          0   __rtentry.o
        32         40          0          0          0   __rtentry2.o
         4          8          0          0          0   __rtentry3.o
         6          8          0          0          0   __rtentry4.o
         8         24          0          0          0   __rtentry5.o
         8         24          0          0          0   __rtentry6.o
		............省略一大部分...........
         0          0          0          0          0   maybefptrapshutdown1.o
         0          0          0          0          0   maybefptrapshutdown2.o
        16          0          0          0         76   fptrapshutdown.o
         8          0          4          0         68   _signgam.o
        22          0          0          0        100   _rserrno.o
        18          0          0          0         76   isalnum.o
        18          0          0          0         76   isalpha.o
        18          0          0          0         76   iscntrl.o
        24          0          0          0         76   isdigit.o
        18          0          0          0         76   isgraph.o
        18          0          0          0         76   islower.o
        18          0          0          0         76   isprint.o
        18          0          0          0         76   ispunct.o
        18          0          0          0         76   isspace.o
        18          0          0          0         76   isupper.o
        22          0          0          0         76   isxdigit.o
        26          0          0          0         76   tolower.o
        30          0          0          0         76   toupper.o
       172       4490          0          0        164   wclass.o
        12          0          0          0         76   iswalnum.o
        12          0          0          0         76   iswalpha.o
        12          0          0          0         76   iswblank.o
        12          0          0          0         76   iswcntrl.o
        12          0          0          0         76   iswgraph.o
        12          0          0          0         76   iswprint.o
        12          0          0          0         76   iswpunct.o
         4          0          0          0         68   iswspace.o
        12          0          0          0         76   iswlower.o
        12          0          0          0         76   iswupper.o
        12          0          0          0         76   iswdigit.o
        12          0          0          0         76   iswxdigit.o
       148        888          0          0        152   towlower.o
       156        948          0          0        152   towupper.o
       356          0          0          0         92   wctype.o
        64          0          0          0         92   wctrans.o
        12          0          0          0         76   _iswspace.o
        86          0          0          0        136   _small_iswspace.o
       100          0          0          0         76   wclass_c.o
        10          0          0          0         68   towlower_c.o
        10          0          0          0         68   towupper_c.o
        32          0          0          0         76   isblank.o
        24          0          0          0         84   printf.o
        12          0          0          0         68   vprintf.o
        20          0          0          0         84   fprintf.o
        10          0          0          0         68   vfprintf.o
        44          0          0          0         84   sprintf.o
        36          0          0          0         76   vsprintf.o
        56          0          0          0         88   snprintf.o
        52          0          0          0         80   vsnprintf.o
        24          0          0          0         84   wprintf.o
        12          0          0          0         68   vwprintf.o
        20          0          0          0         84   fwprintf.o
        10          0          0          0         68   vfwprintf.o
        72          0          0          0         92   swprintf.o
        72          0          0          0         80   vswprintf.o
        54          0          0          0         92   asprintf.o
        56          0          0          0         96   vasprintf.o
        54          0          0          0         92   __ARM_asprintf.o
        56          0          0          0         96   __ARM_vasprintf.o
        56          0          0          0         88   __ARM_snprintf.o
        52          0          0          0         80   __ARM_vsnprintf.o
        24          0          0          0         84   _printf.o
        12          0          0          0         68   _vprintf.o
        20          0          0          0         84   _fprintf.o
        10          0          0          0         68   _vfprintf.o
        44          0          0          0         84   _sprintf.o
        36          0          0          0         76   _vsprintf.o
        56          0          0          0         88   _snprintf.o
        52          0          0          0         80   _vsnprintf.o
        24          0          0          0         84   _wprintf.o
        12          0          0          0         68   _vwprintf.o
        20          0          0          0         84   _fwprintf.o
        10          0          0          0         68   _vfwprintf.o
        72          0          0          0         92   _swprintf.o
        72          0          0          0         80   _vswprintf.o
        54          0          0          0         92   _asprintf.o
        56          0          0          0         96   _vasprintf.o
        54          0          0          0         92   ___ARM_asprintf.o
        56          0          0          0         96   ___ARM_vasprintf.o
        56          0          0          0         88   ___ARM_snprintf.o
        52          0          0          0         80   ___ARM_vsnprintf.o
        24          0          0          0         84   __0printf.o
        12          0          0          0         68   __0vprintf.o
        20          0          0          0         84   __0fprintf.o
        10          0          0          0         68   __0vfprintf.o
        44          0          0          0         84   __0sprintf.o
        36          0          0          0         76   __0vsprintf.o
        56          0          0          0         88   __0snprintf.o
        52          0          0          0         80   __0vsnprintf.o
        24          0          0          0         84   __0wprintf.o
        12          0          0          0         68   __0vwprintf.o
        20          0          0          0         84   __0fwprintf.o
        10          0          0          0         68   __0vfwprintf.o
        72          0          0          0         92   __0swprintf.o
        72          0          0          0         80   __0vswprintf.o
        54          0          0          0         92   __0asprintf.o
        56          0          0          0         96   __0vasprintf.o
        54          0          0          0         92   __0__ARM_asprintf.o
        56          0          0          0         96   __0__ARM_vasprintf.o
        56          0          0          0         88   __0__ARM_snprintf.o
        52          0          0          0         80   __0__ARM_vsnprintf.o
        24          0          0          0         84   c89printf.o
        12          0          0          0         68   c89vprintf.o
        20          0          0          0         84   c89fprintf.o
        10          0          0          0         68   c89vfprintf.o
        44          0          0          0         84   c89sprintf.o
        36          0          0          0         76   c89vsprintf.o
        56          0          0          0         88   c89snprintf.o
        52          0          0          0         80   c89vsnprintf.o
        24          0          0          0         84   c89wprintf.o
        12          0          0          0         68   c89vwprintf.o
        20          0          0          0         84   c89fwprintf.o
        10          0          0          0         68   c89vfwprintf.o
        72          0          0          0         92   c89swprintf.o
        72          0          0          0         80   c89vswprintf.o
        54          0          0          0         92   c89asprintf.o
        56          0          0          0         96   c89vasprintf.o
        54          0          0          0         92   c89__ARM_asprintf.o
        56          0          0          0         96   c89__ARM_vasprintf.o
        56          0          0          0         88   c89__ARM_snprintf.o
        52          0          0          0         80   c89__ARM_vsnprintf.o
        24          0          0          0         84   __2printf.o
        12          0          0          0         68   __2vprintf.o
        20          0          0          0         84   __2fprintf.o
        10          0          0          0         68   __2vfprintf.o
        44          0          0          0         84   __2sprintf.o
        36          0          0          0         76   __2vsprintf.o
        56          0          0          0         88   __2snprintf.o
        52          0          0          0         80   __2vsnprintf.o
        24          0          0          0         84   __2wprintf.o
        12          0          0          0         68   __2vwprintf.o
        20          0          0          0         84   __2fwprintf.o
        10          0          0          0         68   __2vfwprintf.o
        72          0          0          0         92   __2swprintf.o
        72          0          0          0         80   __2vswprintf.o
        54          0          0          0         92   __2asprintf.o
        56          0          0          0         96   __2vasprintf.o
        54          0          0          0         92   __2__ARM_asprintf.o
        56          0          0          0         96   __2__ARM_vasprintf.o
        56          0          0          0         88   __2__ARM_snprintf.o
        52          0          0          0         80   __2__ARM_vsnprintf.o
        24          0          0          0         84   __1printf.o
        12          0          0          0         68   __1vprintf.o
        20          0          0          0         84   __1fprintf.o
        10          0          0          0         68   __1vfprintf.o
        44          0          0          0         84   __1sprintf.o
        36          0          0          0         76   __1vsprintf.o
        56          0          0          0         88   __1snprintf.o
        52          0          0          0         80   __1vsnprintf.o
        24          0          0          0         84   __1wprintf.o
        12          0          0          0         68   __1vwprintf.o
        20          0          0          0         84   __1fwprintf.o
        10          0          0          0         68   __1vfwprintf.o
        72          0          0          0         92   __1swprintf.o
        72          0          0          0         80   __1vswprintf.o
        54          0          0          0         92   __1asprintf.o
        56          0          0          0         96   __1vasprintf.o
        54          0          0          0         92   __1__ARM_asprintf.o
        56          0          0          0         96   __1__ARM_vasprintf.o
        56          0          0          0         88   __1__ARM_snprintf.o
        52          0          0          0         80   __1__ARM_vsnprintf.o
		............省略一大部分...........
       104          0          0          0         84   __printf.o
        78          0          0          0        108   _printf_pad.o
        36          0          0          0         84   _printf_truncate.o
        82          0          0          0         80   _printf_str.o
       178          0          0          0         88   _printf_intcommon.o
       120          0          0          0         92   _printf_dec.o
        40          0          0          0         68   _printf_charcount.o
      1050          0          0          0        216   _printf_fp_dec.o
       764         38          0          0        100   _printf_fp_hex.o
        48          0          0          0         96   _printf_char_common.o
        10          0          0          0         68   _sputc.o
        16          0          0          0         68   _snputc.o
       128          0          0          0         84   _printf_fp_infnan.o
        40          0          0          0         84   __printf_nopercent.o
        44          0          0          0        108   _printf_char.o
        36          0          0          0         80   _printf_char_file.o
        64          0          0          0         84   _printf_char_file_locked.o
       188          8          0          0         92   _printf_wctomb.o
       144          8          0          0         88   _printf_mbtowc.o
        48          0          0          0         96   _printf_wchar_common.o
        16          0          0          0         68   _snputwc.o
        44          0          0          0        108   _printf_wchar.o
        86          0          0          0         80   _printf_wc.o
        36          0          0          0         80   _printf_wchar_file.o
        64          0          0          0         84   _printf_wchar_file_locked.o
       124          0          0          0         92   _printf_longlong_dec.o
       160          0          0          0         84   _printf_fp_infnan_snan.o
        84          0          0          0         80   _printf_oct_ll.o
        80          0          0          0         88   _printf_oct_int.o
       112          0          0          0        124   _printf_oct_int_ll.o
        92         40          0          0         88   _printf_hex_ll.o
        88         40          0          0         88   _printf_hex_int.o
       124         40          0          0        140   _printf_hex_int_ll.o
        84         40          0          0         88   _printf_hex_ptr.o
       124         40          0          0        144   _printf_hex_int_ptr.o
       120         40          0          0        124   _printf_hex_ll_ptr.o
       148         40          0          0        160   _printf_hex_int_ll_ptr.o
       148         17          0          0         84   __printf_flags.o
       184          0          0          0         84   __printf_ss.o
       236         17          0          0         88   __printf_flags_ss.o
       284          0          0          0        156   __printf_wp.o
       326         17          0          0        160   __printf_flags_wp.o
       366          0          0          0        156   __printf_ss_wp.o
       406         17          0          0        160   __printf_flags_ss_wp.o
         6          0          0          0          0   _printf_c.o
         6          0          0          0          0   _printf_s.o
         6          0          0          0          0   _printf_n.o
         6          0          0          0          0   _printf_x.o
         6          0          0          0          0   _printf_p.o
         6          0          0          0          0   _printf_o.o
         6          0          0          0          0   _printf_i.o
         6          0          0          0          0   _printf_d.o
         6          0          0          0          0   _printf_u.o
         6          0          0          0          0   _printf_f.o
         6          0          0          0          0   _printf_e.o
         6          0          0          0          0   _printf_g.o
         6          0          0          0          0   _printf_a.o
         0          0          0          0          0   _printf_percent.o
         4          0          0          0          0   _printf_percent_end.o
         6          0          0          0          0   _printf_lli.o
         6          0          0          0          0   _printf_lld.o
         6          0          0          0          0   _printf_llu.o
        10          0          0          0          0   _printf_ll.o
        10          0          0          0          0   _printf_l.o
         6          0          0          0          0   _printf_lc.o
         6          0          0          0          0   _printf_ls.o
         6          0          0          0          0   _printf_llo.o
         6          0          0          0          0   _printf_llx.o
        32          0          0          0         84   scanf.o
        24          0          0          0         84   fscanf.o
        60          0          0          0         84   sscanf.o
        24          0          0          0         80   vscanf.o
        16          0          0          0         80   vfscanf.o
        52          0          0          0         80   vsscanf.o
        60          0          0          0         84   swscanf.o
        52          0          0          0         80   vswscanf.o
        52          0          0          0         80   __ARM_vsscanf.o
        32          0          0          0         84   scanfn.o
        24          0          0          0         84   fscanfn.o
        60          0          0          0         84   sscanfn.o
		............省略一大部分...........
        16          0          0          0         80   vfwscanf.o
        28          0          0          0         68   _chval.o
       884          0          0          0        100   _scanf.o
       342          0          0          0        100   _scanf_longlong.o
       332          0          0          0         96   _scanf_int.o
       224          0          0          0         96   _scanf_str.o
      1202          0          0          0        216   scanf_fp.o
         0          0          0          0          0   scanf_nofp.o
       800          0          0          0        100   scanf_hexfp.o
        44          0          0          0         84   scanf_char.o
        64          0          0          0         84   _sgetc.o
        26          0          0          0         80   atoi.o
        26          0          0          0         80   atol.o
        26          0          0          0         80   atoll.o
       308          0          0          0        100   scanf_infnan.o
        24          0          0          0         68   scanf_char_file.o
        64          0          0          0         84   scanf_char_file_locked.o
		............省略一大部分...........
         8          0          0          0         68   feof.o
         8          0          0          0         68   ferror.o
       100          0          0          0        120   fflush.o
        26          0          0          0        136   fgetc.o
        32          0          0          0         80   fgetpos.o
        74          0          0          0         84   fgets.o
       570          0          0          0        132   filbuf.o
       470          0          0          0         88   flsbuf.o
        28          0          0          0        136   fputc.o
        34          0          0          0         80   fputs.o
        58          0          0          0         88   fread.o
       248          0          0          0         84   fseek.o
        40          0          0          0         80   fsetpos.o
        66          0          0          0         76   ftell.o
        50          0          0          0         84   fwrite.o
         4          0          0          0         68   getc.o
        12          0          0          0         68   getchar.o
        56          0          0          0         80   gets.o
        60          0          0          0         80   perror.o
         4          0          0          0         68   putc.o
        12          0          0          0         68   putchar.o
        44          0          0          0         84   puts.o
        22          0          0          0         80   rewind.o
        70          0          0          0         80   setvbuf.o
       240          0          0          0        156   stdio.o
        88          0          4        256        108   tmpnam.o
        72          0          0          0         68   ungetc.o
        78          0          0          0        112   __dup.o
       280          0          0          0         96   freadfast.o
       214          0          0          0         88   fread_bytes_avail.o
        26          0          0          0         76   fread_bytes_avail_replaced.o
       188          0          0          0         88   fwritefast.o
         0          0          4          0          0   streamlock.o
       312          0          0          0        112   initio.o
       236          0          0          0        128   fopen.o
        20          0          0          0         68   setbuf.o
         0          0         12        252          0   stdio_streams.o
        76          0          0          0         88   fclose.o
        56          0          0          0         80   flushlinebuffered.o
       102          0          0          0         96   fclose_tmpfile.o
        32          0          0          0         80   fgetc_locked.o
        36          0          0          0         80   fputc_locked.o
        32          0          0          0         80   ftell_locked.o
        52          0          0          0         80   fclose_locked.o
        36          0          0          0         80   ungetc_locked.o
        44          0          0          0         84   fseek_locked.o
        86          0          0          0         84   fgets_locked.o
        76          0          0          0         80   gets_locked.o
        54          0          0          0         80   fputs_locked.o
        64          0          0          0         80   puts_locked.o
		............省略一大部分...........
        16          0          0         42         68   locale.o
       114          0          0          0         76   _lconv.o
        16          0          0         48         76   localeconv.o
        36          0          0          0         76   aeabi_lconv.o
        16          0          0         56         76   aeabi_localeconv.o
        60          0          0          0         80   findlocale.o
       428          0          0          0        188   locale_r.o
         2          0          0          0         68   locale_8859.o
        16          0          0         88        136   mbdata.o
        68          0          0          0         84   mblen.o
       122          0          0          0         88   mbtowc.o
        56          0          0          0         80   wctomb.o
        80          0          0          0         88   mbstowcs.o
       100          0          0          0         92   wcstombs.o
        14          0          0          0         68   mbsinit.o
        36          0          0          0         88   mbrlen.o
       120          0          0          0         88   mbrtowc.o
        58          0          0          0         80   wcrtomb.o
       114          0          0          0         92   mbsrtowcs.o
       140          0          0          0        100   wcsrtombs.o
        40          0          0          0         80   btowc.o
        42          0          0          0         84   wctob.o
		............省略一大部分...........
         8          0          0          0         68   labs.o
        20          0          0          0         76   ldiv.o
        20          0          0          0         68   llabs.o
        24          0          0          0         80   lldiv.o
        20          0          0          0         68   imaxabs.o
        24          0          0          0         80   imaxdiv.o
       112          0          0        228        160   rand.o
        36          0          4          0         84   ANSI_rand.o
       120          0          0          0         92   rand_r.o
        28          0          0          0         84   ANSI_rand_r.o
        18          0          0          0         80   exit.o
        22          0          0          0         80   abort.o
         4          0          0          0         68   _Exit.o
   		............省略一大部分...........
        20          0          0          0         68   strchr.o
        32          0          0          0         80   strcspn.o
        36          0          0          0         76   strncat.o
        30          0          0          0         76   strpbrk.o
        28          0          0          0         80   strspn.o
        36          0          0          0         80   strstr.o
        80          0          0          0         84   strxfrm.o
       184          0          0          0         84   strlcat.o
       142          0          0          0         84   strlcpy.o
        88          0          0          0         76   memcmp.o
        72          0          0          0         80   strcpy.o
        50          0          0          0         84   strncasecmp.o
        42          0          0          0         84   strcasecmp.o
        22          0          0          0         68   strrchr.o
        62          0          0          0         76   strlen.o
        18          0          0          0         68   wcscpy.o
       		............省略一大部分...........
         8          0          0          0         76   memcpy.o
         8          0          0          0         76   memmove.o
       214          0          0          0         68   rt_memcpy.o
       202          0          0          0         68   rt_memmove.o
       100          0          0          0         80   rt_memcpy_w.o
       122          0          0          0         80   rt_memmove_w.o
        22          0          0          0         76   memset.o
        16          0          0          0         68   aeabi_memset.o
        16          0          0          0         68   aeabi_memset4.o
        18          0          0          0         68   rt_memset.o
        68          0          0          0         68   rt_memclr.o
        78          0          0          0         80   rt_memclr_w.o
       250          0          0          0        196   rt_neon_memcpy_w.o
        84          0          0          0        172   rt_neon_memclr_w.o
       128          0          0          0        172   rt_neon_memmove_w.o
       220          0          0          0        164   rt_neon_memcpy_ca8.o
       228          0          0          0        164   rt_neon_memcpy_ca9.o
       236          0          0          0        164   rt_neon_memmove_ca8.o
       236          0          0          0        164   rt_neon_memmove_ca9.o
       130          0          0          0         96   rt_memcpy_w_ca8.o
       118          0          0          0         96   rt_memcpy_w_qsp.o
       118          0          0          0         96   rt_memcpy_w_ca9.o
       216          0          0          0         96   rt_memcpy_w_ldrd.o
       118          0          0          0        192   rt_noneon_memcpy_w_ca9.o
    		............省略一大部分...........
        14          0          0          0         80   ctime.o
         4          0          0          0         68   gmtime.o
        12          0          0         44         68   localtime.o
       428          0          0          0        116   mktime.o
       864          0          0          0        184   strftime.o
         0         12          0          0          0   _monlen.o
         0          0          0          0          0   asctime_r.o
         0          0          0          0          0   localtime_r.o
       104          0          0          0         88   asctime_internal.o
       184          0          0          0         80   localtime_internal.o
      		............省略一大部分...........
         0          0          0          0          0   cpuinit.o
       264          0          0          0         96   _get_argv.o
       302          0          0          0        168   _get_argv_nomalloc.o
         4          0          0          0         84   _main.o
       320          0          0          0        152   _main_redirect.o
         2          0          0          0         68   _main_arg.o
         4          0          0          0         68   argv_veneer.o
         2          0          0          0         68   no_argv.o
         2          0          0          0         68   no_excepts.o
         2          0          0          0         68   no_errno.o
         2          0          0          0         68   use_snan.o
         2          0          0          0          0   libinit.o
       136          0          0          0          0   libinit2.o
        36          0          0          0          0   libinit3.o
        36          0          0          0          0   libinit4.o
        36          0          0          0          0   libinit5.o
         2          0          0          0          0   libshutdown.o
        28          0          0          0          0   libshutdown2.o
         8          0          0          0         68   __main.o
        52          0          0          0         68   __scatter.o
        76          0          0          0         68   __scatters.o
        26          0          0          0         68   __scatter_copy.o
        28          0          0          0         68   __scatter_zi.o
        32          0          0          0        272   irqnopfx.o
       314          0          0          0         92   bitcpy0.o
       322          0          0          0         92   bitcpy1.o
       362          0          0          0         92   bitcpy2.o
       608          0          0          0        100   bitcpy3.o
       468          0          0          0         92   bitmove0.o
       474          0          0          0         92   bitmove1.o
       508          0          0          0         92   bitmove2.o
       764          0          0          0        100   bitmove3.o
    		............省略一大部分...........
        34          0          0          0         76   prim_new.o
         2          8          0          0         68   init.o
        36          8          0          0         80   init_aeabi.o
        44          8          0          0         76   arm_relocate.o
        36          8          0          0         80   preinit_aeabi.o
         4          0          0          0         68   _memcpy.o
         8          0          0          0         84   _urdwr4.o
       		............省略一大部分...........
       112          0          0          0        104   fputwc.o
        36          0          0          0         80   fputws.o
       200          0          0          0        104   fgetwc.o
        82          0          0          0         84   fgetws.o
         4          0          0          0         68   getwc.o
        12          0          0          0         68   getwchar.o
         4          0          0          0         68   putwc.o
        12          0          0          0         68   putwchar.o
       108          0          0          0         68   ungetwc.o
        44          0          0          0         84   backspacewc.o
        44          0          0          0         68   fwide.o
        36          0          0          0         84   filbuf_fwide.o
        36          0          0          0         84   flsbuf_fwide.o
        36          0          0          0         80   fputwc_locked.o
        32          0          0          0         80   fgetwc_locked.o
        66          0          0          0         80   fwide_locked.o
       132          0          0          0         80   ungetwc_locked.o
        32          0          0          0         80   backspacewc_locked.o
        54          0          0          0         80   fputws_locked.o
        94          0          0          0         84   fgetws_locked.o
     73526      40563        112       1686      76484   TOTAL

ENTRY at offset 1 in section !!!main of __main.o

从中我们可以看到有__main.o等文件,接下来我们可以使用armar -x命令将c_w.l解压出以上全部文件,然后使用fromelf来查看__main.o的详细信息,这里就不一一尝试了!

启动实例分析

  下面我们以STM32F407VG片子为例,看看其调试时的汇编代码(Keil5中)。直接进调试模式,注意:最好将汇编窗口右键改为assembly mode。
在这里插入图片描述
首先看看定义的中断向量表部分,如下图:
在这里插入图片描述
其中,SystemInit为 ST 提供的时钟初始化函数(如果使用了外部RAM,可能还包含外部RAM的配置)。接着,就会有如下汇编代码(具体看里面的注释即可):

0x08000180 0243      DCW           0x0243       ; 小端模式,地址:0x08000243
0x08000182 0800      DCW           0x0800
0x08000184 0243      DCW           0x0243       ; 小端模式,地址:0x08000243
0x08000186 0800      DCW           0x0800                                   
; 从此往上即为中断向量表,与开发环境的启动文件中的中断向量表相对应,32位地址,小端模式
; 下面就是上文介绍的启动流程:
                 __main:
0x08000188 F000F802  BL.W          __scatterload (0x08000190)       ; 负责把RW/RO输出段从装载域地址复制到运行域地址,并完成了ZI运行域的初始化工作。
0x0800018C F000F83C  BL.W          __rt_entry (0x08000208)          ; 负责初始化堆、栈,完成C库函数的初始化。其会调用一系列初始化函数,最后自动跳转向main()函数。

; 执行完后,R10和R11就被赋给成了下面两个值,Map文件中的symbol:
;       Region$$Table$$Base                      0x08000898   Number         0  anon$$obj.o(Region$$Table)
;       Region$$Table$$Limit                     0x080008b8   Number         0  anon$$obj.o(Region$$Table)
; !!!-----------注意:以下注释中括号中的数据为我在调试时的值,自行调试时值可能有变化-----------!!!
; !!!-----------注意:以下注释中非括号中的数据一般为左侧地址或者立即数-----------!!!
                 __scatterload:
0x08000190 A00A      ADR           r0,{pc}+0x2C     ; 将基于PC相对偏移的地址值(0x080001BC)读取到寄存器r0中。
0x08000192 E8900C00  LDM           r0,{r10-r11}     ; 将R0对应地址存放的的2个字copy到R10~R11中。即:r10 = 0x000006DC; r11 = 0x000006FC
0x08000196 4482      ADD           r10,r10,r0       ; r10 = r10 + r0 = 0x000006DC + 0x080001BC = 0x08000898
0x08000198 4483      ADD           r11,r11,r0       ; r11 = r11 + r0 = 0x000006FC + 0x080001BC = 0x080008B8
0x0800019A F1AA0701  SUB           r7,r10,#0x01     ; r7 = r10 - 0x01 = 0x08000898 - 0x01 = 0x08000897
                 __scatterload_null:
0x0800019E 45DA      CMP           r10,r11          ; 比较r10和r11。实际做r10-r11操作,根据结果修改CPSR中条件标志位的值
0x080001A0 D101      BNE           0x080001A6       ; Z 标志位不等于零时, 跳转到0x080001A6
0x080001A2 F000F831  BL.W          __rt_entry (0x08000208)  ; 最后一步:在执行完__scatterload_copy和__scatterload_zeroinit后,r10 == r11 ,上面的跳转不成立,执行该句
0x080001A6 F2AF0E09  ADR.W         lr,{pc}-0x07     ; 将基于PC相对偏移的地址值(0x0800019F)读取到寄存器lr中。lr = 0x0800019F
0x080001AA E8BA000F  LDM           r10!,{r0-r3}     ; 将R10对应地址存放的的4个双字copy到R0~R3中,!表示执行语句后将地址赋值给r10。r10 = r10 + 4*4 = 0x08000898 + 0x10 = 0x080008A8. 
                                                    ;       R0:表示的是程序加载视图的RW区的起始地址(0x080008B8;       R1:要复制到的运行域地址(RAM中0x20000000;       R2:要复制的RW数据的个数(0x00000020;       R3:是__scatterload_copy函数的起始地址0x080001C4
0x080001AE F0130F01  TST           r3,#0x01         ; 
0x080001B2 BF18      IT            NE
0x080001B4 1AFB      SUBNE         r3,r7,r3
0x080001B6 F0430301  ORR           r3,r3,#0x01
0x080001BA 4718      BX            r3               ; 跳转到r3,也就是__scatterload_copy函数,开始复制数据
0x080001BC 06DC      DCW           0x06DC
0x080001BE 0000      DCW           0x0000
0x080001C0 06FC      DCW           0x06FC
0x080001C2 0000      DCW           0x0000
                 __scatterload_copy:                ; 该函数负责将镜像中的RW数据复制到芯片的ARM中
0x080001C4 3A10      SUBS          r2,r2,#0x10      ; 循环:R2=R2-0x10,SUBS中S表示把进位结果写入CPSR。
0x080001C6 BF24      ITT           CS
0x080001C8 C878      LDMCS         r0!,{r3-r6}
0x080001CA C178      STMCS         r1!,{r3-r6}
0x080001CC D8FA      BHI           __scatterload_copy (0x080001C4)  ; 循环:条件成立跳转到回去
0x080001CE 0752      LSLS          r2,r2,#29
0x080001D0 BF24      ITT           CS
0x080001D2 C830      LDMCS         r0!,{r4-r5}
0x080001D4 C130      STMCS         r1!,{r4-r5}
0x080001D6 BF44      ITT           MI
0x080001D8 6804      LDRMI         r4,[r0,#0x00]
0x080001DA 600C      STRMI         r4,[r1,#0x00]
0x080001DC 4770      BX            lr               ; 这里返回到lr = 0x0800019F,即在此调用__scatterload_null。会继续将R10对应地址存放的的4个双字copy到R0~R3中,但是,此时的R10由于之前的一次调用,其值已经增加
                                                    ;       R0:是程序加载视图的RW区的起始地址(0x080008D8 = 0x080008B8 + 0x20 上面执行后面的部分)
                                                    ;       R1:是要输出的执行视图的RW区的地址(RAM中 0x20000020;       R2:要复制的RW数据的个数(0x00000660;       R3:是__scatterload_zeroinit函数的起始地址0x080001E0
                                                    ;       接下来就会跳转到__scatterload_zeroinit

0x080001DE 0000      MOVS          r0,r0
                 __scatterload_zeroinit:
0x080001E0 2300      MOVS          r3,#0x00
0x080001E2 2400      MOVS          r4,#0x00
0x080001E4 2500      MOVS          r5,#0x00
0x080001E6 2600      MOVS          r6,#0x00
0x080001E8 3A10      SUBS          r2,r2,#0x10      ; 循环:
0x080001EA BF28      IT            CS
0x080001EC C178      STMCS         r1!,{r3-r6}
0x080001EE D8FB      BHI           0x080001E8       ; 循环:条件成立跳转到回去
0x080001F0 0752      LSLS          r2,r2,#29
0x080001F2 BF28      IT            CS
0x080001F4 C130      STMCS         r1!,{r4-r5}
0x080001F6 BF48      IT            MI
0x080001F8 600B      STRMI         r3,[r1,#0x00]
0x080001FA 4770      BX            lr               ; 这里返回到lr = 0x0800019F,即在此调用__scatterload_null。这次回去后r10 == r11.回去后会跳转到__rt_entry
                 __rt_lib_init:
0x080001FC B51F      PUSH          {r0-r4,lr}
                 __rt_lib_init_fp_1:
0x080001FE F000FB45  BL.W          _fp_init (0x0800088C)
                 __rt_lib_init_alloca_1:
0x08000202 BD1F      POP           {r0-r4,pc}
                 __rt_lib_shutdown:
0x08000204 B510      PUSH          {r4,lr}
                 __rt_lib_shutdown_cpp_1:
0x08000206 BD10      POP           {r4,pc}
                 __rt_entry:                        ; 在执行完__scatterload后,会紧接着执行该函数
0x08000208 F000F831  BL.W          __user_setup_stackheap (0x0800026E)  ; 设置堆栈的函数,该函数中会调用由用户实现的__user_initial_stackheap函数,如第二节的启动文件中最后的代码即为用户实现的堆栈初始化该函数
0x0800020C 4611      MOV           r1,r2
                 __rt_entry_li:
0x0800020E F7FFFFF5  BL.W          __rt_lib_init (0x080001FC)   ; 初始化C库
                 __rt_entry_main:
0x08000212 F000FA3B  BL.W          main (0x0800068C)            ; 跳转到C的main函数
0x08000216 F000F84F  BL.W          exit (0x080002B8)            ; 如果main返回,则执行该函数,结束程序运行
                 __rt_exit:
0x0800021A B403      PUSH          {r0-r1}
                 __rt_exit_ls:
0x0800021C F7FFFFF2  BL.W          __rt_lib_shutdown (0x08000204)
                 __rt_exit_exit:
0x08000220 BC03      POP           {r0-r1}
0x08000222 F000F857  BL.W          _sys_exit (0x080002D4)
0x08000226 0000      MOVS          r0,r0
0x08000226 0000      MOVS          r0,r0
; 此处往下,就是定义的各个中断向量的实现代码,第一个就是复位中断,程序就是从复位中断开始执行的
                 Reset_Handler:
0x08000228 4809      LDR           r0,[pc,#36]  ; @0x08000250
0x0800022A 4780      BLX           r0
0x0800022C 4809      LDR           r0,[pc,#36]  ; @0x08000254
0x0800022E 4700      BX            r0
                 NMI_Handler:
0x08000230 E7FE      B             NMI_Handler (0x08000230)
                 HardFault_Handler:
0x08000232 E7FE      B             HardFault_Handler (0x08000232)
                 MemManage_Handler:            
0x08000234 E7FE      B             MemManage_Handler (0x08000234)
                 BusFault_Handler:
0x08000236 E7FE      B             BusFault_Handler (0x08000236)
                 UsageFault_Handler:
0x08000238 E7FE      B             UsageFault_Handler (0x08000238)
                 SVC_Handler:
0x0800023A E7FE      B             SVC_Handler (0x0800023A)
                 DebugMon_Handler:
0x0800023C E7FE      B             DebugMon_Handler (0x0800023C)
                 PendSV_Handler:
0x0800023E E7FE      B             PendSV_Handler (0x0800023E)
                 SysTick_Handler:
0x08000240 E7FE      B             SysTick_Handler (0x08000240)
                 Default_Handler:
0x08000242 E7FE      B             Default_Handler (0x08000242)
                 __user_initial_stackheap:
0x08000244 4804      LDR           r0,[pc,#16]  ; @0x08000258
0x08000246 4905      LDR           r1,[pc,#20]  ; @0x0800025C
0x08000248 4A05      LDR           r2,[pc,#20]  ; @0x08000260
0x0800024A 4B06      LDR           r3,[pc,#24]  ; @0x08000264
0x0800024C 4770      BX            lr
0x0800024E 0000      DCW           0x0000
0x08000250 0621      DCW           0x0621
0x08000252 0800      DCW           0x0800
0x08000254 0189      DCW           0x0189
0x08000256 0800      DCW           0x0800
0x08000258 0080      DCW           0x0080
0x0800025A 2000      DCW           0x2000
0x0800025C 0680      DCW           0x0680
0x0800025E 2000      DCW           0x2000
0x08000260 0280      DCW           0x0280
0x08000262 2000      DCW           0x2000
0x08000264 0280      DCW           0x0280
0x08000266 2000      DCW           0x2000
                 __use_two_region_memory:
0x08000268 4770      BX            lr
                 __rt_heap_escrow$2region:
0x0800026A 4770      BX            lr
                 __rt_heap_expand$2region:
0x0800026C 4770      BX            lr
                 __user_setup_stackheap:
0x0800026E 4675      MOV           r5,lr
0x08000270 F000F82C  BL.W          __user_libspace (0x080002CC)
0x08000274 46AE      MOV           lr,r5
0x08000276 0005      MOVS          r5,r0
0x08000278 4669      MOV           r1,sp
0x0800027A 4653      MOV           r3,r10
0x0800027C F0200007  BIC           r0,r0,#0x07
0x08000280 4685      MOV           sp,r0
0x08000282 B018      ADD           sp,sp,#0x60
0x08000284 B520      PUSH          {r5,lr}
0x08000286 F7FFFFDD  BL.W          __user_initial_stackheap (0x08000244)
0x0800028A E8BD4020  POP           {r5,lr}
0x0800028E F04F0600  MOV           r6,#0x00
0x08000292 F04F0700  MOV           r7,#0x00
0x08000296 F04F0800  MOV           r8,#0x00
0x0800029A F04F0B00  MOV           r11,#0x00
0x0800029E F0210107  BIC           r1,r1,#0x07
0x080002A2 46AC      MOV           r12,r5
0x080002A4 E8AC09C0  STM           r12!,{r6-r8,r11}
0x080002A8 E8AC09C0  STM           r12!,{r6-r8,r11}
0x080002AC E8AC09C0  STM           r12!,{r6-r8,r11}
0x080002B0 E8AC09C0  STM           r12!,{r6-r8,r11}
0x080002B4 468D      MOV           sp,r1
0x080002B6 4770      BX            lr
                 exit:
0x080002B8 B510      PUSH          {r4,lr}
0x080002BA 4604      MOV           r4,r0
0x080002BC F3AF8000  NOP.W         
0x080002C0 4620      MOV           r0,r4
0x080002C2 E8BD4010  POP           {r4,lr}
0x080002C6 F7FFBFA8  B.W           __rt_exit (0x0800021A)
0x080002CA 0000      MOVS          r0,r0
                 __user_libspace:
0x080002CC 4800      LDR           r0,[pc,#0]  ; @0x080002D0
0x080002CE 4770      BX            lr
0x080002D0 0020      DCW           0x0020
0x080002D2 2000      DCW           0x2000
                 _sys_exit:
0x080002D4 4901      LDR           r1,[pc,#4]  ; @0x080002DC
0x080002D6 2018      MOVS          r0,#0x18
0x080002D8 BEAB      BKPT          0xAB
0x080002DA E7FE      B             0x080002DA
0x080002DC 0026      DCW           0x0026
0x080002DE 0002      DCW           0x0002

启动文件

  目前,多数 MCU 厂商都提供一个启动文件。当然,编程者也可以自己编写启动文件,具体编写要求ARM的网站上都有相关文档进行说明。下面分析一下 STM32 启动文件startup_stm32f407xx.s,具体看里面的注释。

;******************** (C) COPYRIGHT 2017 STMicroelectronics ********************
;* File Name          : startup_stm32f407xx.s
;* Author             : MCD Application Team
;* Version            : V2.6.1
;* Date               : 14-February-2017
;* Description        : STM32F407xx devices vector table for MDK-ARM toolchain. 
;*                      This module performs:
;*                      - Set the initial SP
;*                      - Set the initial PC == Reset_Handler
;*                      - Set the vector table entries with the exceptions ISR address
;*                      - Branches to __main in the C library (which eventually
;*                        calls main()).
;*                      After Reset the CortexM4 processor is in Thread mode,
;*                      priority is Privileged, and the Stack is set to Main.
;* <<< Use Configuration Wizard in Context Menu >>>   
;*******************************************************************************
; 
;* Redistribution and use in source and binary forms, with or without modification,
;* are permitted provided that the following conditions are met:
;*   1. Redistributions of source code must retain the above copyright notice,
;*      this list of conditions and the following disclaimer.
;*   2. Redistributions in binary form must reproduce the above copyright notice,
;*      this list of conditions and the following disclaimer in the documentation
;*      and/or other materials provided with the distribution.
;*   3. Neither the name of STMicroelectronics nor the names of its contributors
;*      may be used to endorse or promote products derived from this software
;*      without specific prior written permission.
;*
;* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
;* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
;* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
;* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
;* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
;* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
;* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
;* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
;* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
;* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
; 
;*******************************************************************************

; Amount of memory (in bytes) allocated for Stack
; Tailor this value to your application needs
; <h> Stack Configuration
;   <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>

Stack_Size      EQU     0x0800                                  ; 定义栈大小
                ; AREA 命令指示汇编器汇编一个新的代码段或数据段。 
                AREA    STACK, NOINIT, READWRITE, ALIGN=3       ; 代码段名称为STACK,未初始化,允许读写,8字节对齐
Stack_Mem       SPACE   Stack_Size                              ; 分配Stack_Size的栈空间,首地址赋给Stack_Mem
__initial_sp                                                    ; 栈顶指针,全局变量


; <h> Heap Configuration
;   <o>  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>

Heap_Size      EQU     0x200

                AREA    HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base                                                     ; 堆末底部地址
Heap_Mem        SPACE   Heap_Size
__heap_limit                                                    ; 堆界限地址

                PRESERVE8                                       ; 指定当前文件保持堆栈八字节对齐
                THUMB                                           ; Thumb命令模式


; Vector Table Mapped to Address 0 at Reset                     ; 终端向量表 重启时程序从这里运行,必须将该地址映射到0x00000000
                AREA    RESET, DATA, READONLY                   ; 代码段名称为RESET,DATA类型,只读
                EXPORT  __Vectors                               ; 导出中断向量表地址(供外部可以使用)
                EXPORT  __Vectors_End                           ; 导出中断向量表结束指针(供外部可以使用)
                EXPORT  __Vectors_Size                          ; 中断向量表大小(供外部可以使用)
__Vectors       DCD     __initial_sp               ; Top of Stack
                DCD     Reset_Handler              ; Reset Handler
                DCD     NMI_Handler                ; NMI Handler
                DCD     HardFault_Handler          ; Hard Fault Handler
                DCD     MemManage_Handler          ; MPU Fault Handler
                DCD     BusFault_Handler           ; Bus Fault Handler
                DCD     UsageFault_Handler         ; Usage Fault Handler
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     SVC_Handler                ; SVCall Handler
                DCD     DebugMon_Handler           ; Debug Monitor Handler
                DCD     0                          ; Reserved
                DCD     PendSV_Handler             ; PendSV Handler
                DCD     SysTick_Handler            ; SysTick Handler

                ; External Interrupts
                DCD     WWDG_IRQHandler                   ; Window WatchDog                                        
                DCD     PVD_IRQHandler                    ; PVD through EXTI Line detection                        
                DCD     TAMP_STAMP_IRQHandler             ; Tamper and TimeStamps through the EXTI line            
                DCD     RTC_WKUP_IRQHandler               ; RTC Wakeup through the EXTI line                       
                DCD     FLASH_IRQHandler                  ; FLASH                                           
                DCD     RCC_IRQHandler                    ; RCC                                             
                DCD     EXTI0_IRQHandler                  ; EXTI Line0                                             
                DCD     EXTI1_IRQHandler                  ; EXTI Line1                                             
                DCD     EXTI2_IRQHandler                  ; EXTI Line2                                             
                DCD     EXTI3_IRQHandler                  ; EXTI Line3                                             
                DCD     EXTI4_IRQHandler                  ; EXTI Line4                                             
                DCD     DMA1_Stream0_IRQHandler           ; DMA1 Stream 0                                   
                DCD     DMA1_Stream1_IRQHandler           ; DMA1 Stream 1                                   
                DCD     DMA1_Stream2_IRQHandler           ; DMA1 Stream 2                                   
                DCD     DMA1_Stream3_IRQHandler           ; DMA1 Stream 3                                   
                DCD     DMA1_Stream4_IRQHandler           ; DMA1 Stream 4                                   
                DCD     DMA1_Stream5_IRQHandler           ; DMA1 Stream 5                                   
                DCD     DMA1_Stream6_IRQHandler           ; DMA1 Stream 6                                   
                DCD     ADC_IRQHandler                    ; ADC1, ADC2 and ADC3s                            
                DCD     CAN1_TX_IRQHandler                ; CAN1 TX                                                
                DCD     CAN1_RX0_IRQHandler               ; CAN1 RX0                                               
                DCD     CAN1_RX1_IRQHandler               ; CAN1 RX1                                               
                DCD     CAN1_SCE_IRQHandler               ; CAN1 SCE                                               
                DCD     EXTI9_5_IRQHandler                ; External Line[9:5]s                                    
                DCD     TIM1_BRK_TIM9_IRQHandler          ; TIM1 Break and TIM9                   
                DCD     TIM1_UP_TIM10_IRQHandler          ; TIM1 Update and TIM10                 
                DCD     TIM1_TRG_COM_TIM11_IRQHandler     ; TIM1 Trigger and Commutation and TIM11
                DCD     TIM1_CC_IRQHandler                ; TIM1 Capture Compare                                   
                DCD     TIM2_IRQHandler                   ; TIM2                                            
                DCD     TIM3_IRQHandler                   ; TIM3                                            
                DCD     TIM4_IRQHandler                   ; TIM4                                            
                DCD     I2C1_EV_IRQHandler                ; I2C1 Event                                             
                DCD     I2C1_ER_IRQHandler                ; I2C1 Error                                             
                DCD     I2C2_EV_IRQHandler                ; I2C2 Event                                             
                DCD     I2C2_ER_IRQHandler                ; I2C2 Error                                               
                DCD     SPI1_IRQHandler                   ; SPI1                                            
                DCD     SPI2_IRQHandler                   ; SPI2                                            
                DCD     USART1_IRQHandler                 ; USART1                                          
                DCD     USART2_IRQHandler                 ; USART2                                          
                DCD     USART3_IRQHandler                 ; USART3                                          
                DCD     EXTI15_10_IRQHandler              ; External Line[15:10]s                                  
                DCD     RTC_Alarm_IRQHandler              ; RTC Alarm (A and B) through EXTI Line                  
                DCD     OTG_FS_WKUP_IRQHandler            ; USB OTG FS Wakeup through EXTI line                        
                DCD     TIM8_BRK_TIM12_IRQHandler         ; TIM8 Break and TIM12                  
                DCD     TIM8_UP_TIM13_IRQHandler          ; TIM8 Update and TIM13                 
                DCD     TIM8_TRG_COM_TIM14_IRQHandler     ; TIM8 Trigger and Commutation and TIM14
                DCD     TIM8_CC_IRQHandler                ; TIM8 Capture Compare                                   
                DCD     DMA1_Stream7_IRQHandler           ; DMA1 Stream7                                           
                DCD     FMC_IRQHandler                    ; FMC                                             
                DCD     SDIO_IRQHandler                   ; SDIO                                            
                DCD     TIM5_IRQHandler                   ; TIM5                                            
                DCD     SPI3_IRQHandler                   ; SPI3                                            
                DCD     UART4_IRQHandler                  ; UART4                                           
                DCD     UART5_IRQHandler                  ; UART5                                           
                DCD     TIM6_DAC_IRQHandler               ; TIM6 and DAC1&2 underrun errors                   
                DCD     TIM7_IRQHandler                   ; TIM7                   
                DCD     DMA2_Stream0_IRQHandler           ; DMA2 Stream 0                                   
                DCD     DMA2_Stream1_IRQHandler           ; DMA2 Stream 1                                   
                DCD     DMA2_Stream2_IRQHandler           ; DMA2 Stream 2                                   
                DCD     DMA2_Stream3_IRQHandler           ; DMA2 Stream 3                                   
                DCD     DMA2_Stream4_IRQHandler           ; DMA2 Stream 4                                   
                DCD     ETH_IRQHandler                    ; Ethernet                                        
                DCD     ETH_WKUP_IRQHandler               ; Ethernet Wakeup through EXTI line                      
                DCD     CAN2_TX_IRQHandler                ; CAN2 TX                                                
                DCD     CAN2_RX0_IRQHandler               ; CAN2 RX0                                               
                DCD     CAN2_RX1_IRQHandler               ; CAN2 RX1                                               
                DCD     CAN2_SCE_IRQHandler               ; CAN2 SCE                                               
                DCD     OTG_FS_IRQHandler                 ; USB OTG FS                                      
                DCD     DMA2_Stream5_IRQHandler           ; DMA2 Stream 5                                   
                DCD     DMA2_Stream6_IRQHandler           ; DMA2 Stream 6                                   
                DCD     DMA2_Stream7_IRQHandler           ; DMA2 Stream 7                                   
                DCD     USART6_IRQHandler                 ; USART6                                           
                DCD     I2C3_EV_IRQHandler                ; I2C3 event                                             
                DCD     I2C3_ER_IRQHandler                ; I2C3 error                                             
                DCD     OTG_HS_EP1_OUT_IRQHandler         ; USB OTG HS End Point 1 Out                      
                DCD     OTG_HS_EP1_IN_IRQHandler          ; USB OTG HS End Point 1 In                       
                DCD     OTG_HS_WKUP_IRQHandler            ; USB OTG HS Wakeup through EXTI                         
                DCD     OTG_HS_IRQHandler                 ; USB OTG HS                                      
                DCD     DCMI_IRQHandler                   ; DCMI  
                DCD     0                                 ; Reserved                                              
                DCD     HASH_RNG_IRQHandler               ; Hash and Rng
                DCD     FPU_IRQHandler                    ; FPU
                
                                         
__Vectors_End

__Vectors_Size  EQU  __Vectors_End - __Vectors              ; 计算中断向量表的大小

                AREA    |.text|, CODE, READONLY             ; 代码段,|.text| 用于表示由 C 编译程序产生的代码段,或用于以某种方式与 C 库关联的代码段。 CODE类型,只读
; 以下开始定义各种中断,第一个便是复位中断,顺序与上面的终端向量表一致!
; Reset handler
Reset_Handler    PROC                                       ; 代码开始,与ENDP成对出现    
                 EXPORT  Reset_Handler             [WEAK]   ; 复位中断,[WEAK]修饰代表其他文件有函数定义优先调用
        IMPORT  SystemInit                                  ; 导入外部函数SystemInit
        IMPORT  __main                                      ; 导入外部函数__main

                 LDR     R0, =SystemInit
                 BLX     R0                                 ; 无返回调用SystemInit
                 LDR     R0, =__main
                 BX      R0                                 ; 有返回调用__main
                 ENDP                                       ; 代码结束,与PROC成对出现

; Dummy Exception Handlers (infinite loops which can be modified)

NMI_Handler     PROC
                EXPORT  NMI_Handler                [WEAK]
                B       .
                ENDP
HardFault_Handler\
                PROC
                EXPORT  HardFault_Handler          [WEAK]
                B       .
                ENDP
MemManage_Handler\
                PROC
                EXPORT  MemManage_Handler          [WEAK]
                B       .
                ENDP
BusFault_Handler\
                PROC
                EXPORT  BusFault_Handler           [WEAK]
                B       .
                ENDP
UsageFault_Handler\
                PROC
                EXPORT  UsageFault_Handler         [WEAK]
                B       .
                ENDP
SVC_Handler     PROC
                EXPORT  SVC_Handler                [WEAK]
                B       .
                ENDP
DebugMon_Handler\
                PROC
                EXPORT  DebugMon_Handler           [WEAK]
                B       .
                ENDP
PendSV_Handler  PROC
                EXPORT  PendSV_Handler             [WEAK]
                B       .
                ENDP
SysTick_Handler PROC
                EXPORT  SysTick_Handler            [WEAK]
                B       .
                ENDP
; 终端向量表的External Interrupts部分。 默认的外部中断,通常有外部实现。先导出各种符号以供外部使用,然后时默认的定义
Default_Handler PROC

                EXPORT  WWDG_IRQHandler                   [WEAK]                                        
                EXPORT  PVD_IRQHandler                    [WEAK]                      
                EXPORT  TAMP_STAMP_IRQHandler             [WEAK]         
                EXPORT  RTC_WKUP_IRQHandler               [WEAK]                     
                EXPORT  FLASH_IRQHandler                  [WEAK]                                         
                EXPORT  RCC_IRQHandler                    [WEAK]                                            
                EXPORT  EXTI0_IRQHandler                  [WEAK]                                            
                EXPORT  EXTI1_IRQHandler                  [WEAK]                                             
                EXPORT  EXTI2_IRQHandler                  [WEAK]                                            
                EXPORT  EXTI3_IRQHandler                  [WEAK]                                           
                EXPORT  EXTI4_IRQHandler                  [WEAK]                                            
                EXPORT  DMA1_Stream0_IRQHandler           [WEAK]                                
                EXPORT  DMA1_Stream1_IRQHandler           [WEAK]                                   
                EXPORT  DMA1_Stream2_IRQHandler           [WEAK]                                   
                EXPORT  DMA1_Stream3_IRQHandler           [WEAK]                                   
                EXPORT  DMA1_Stream4_IRQHandler           [WEAK]                                   
                EXPORT  DMA1_Stream5_IRQHandler           [WEAK]                                   
                EXPORT  DMA1_Stream6_IRQHandler           [WEAK]                                   
                EXPORT  ADC_IRQHandler                    [WEAK]                         
                EXPORT  CAN1_TX_IRQHandler                [WEAK]                                                
                EXPORT  CAN1_RX0_IRQHandler               [WEAK]                                               
                EXPORT  CAN1_RX1_IRQHandler               [WEAK]                                                
                EXPORT  CAN1_SCE_IRQHandler               [WEAK]                                                
                EXPORT  EXTI9_5_IRQHandler                [WEAK]                                    
                EXPORT  TIM1_BRK_TIM9_IRQHandler          [WEAK]                  
                EXPORT  TIM1_UP_TIM10_IRQHandler          [WEAK]                
                EXPORT  TIM1_TRG_COM_TIM11_IRQHandler     [WEAK] 
                EXPORT  TIM1_CC_IRQHandler                [WEAK]                                   
                EXPORT  TIM2_IRQHandler                   [WEAK]                                            
                EXPORT  TIM3_IRQHandler                   [WEAK]                                            
                EXPORT  TIM4_IRQHandler                   [WEAK]                                            
                EXPORT  I2C1_EV_IRQHandler                [WEAK]                                             
                EXPORT  I2C1_ER_IRQHandler                [WEAK]                                             
                EXPORT  I2C2_EV_IRQHandler                [WEAK]                                            
                EXPORT  I2C2_ER_IRQHandler                [WEAK]                                               
                EXPORT  SPI1_IRQHandler                   [WEAK]                                           
                EXPORT  SPI2_IRQHandler                   [WEAK]                                            
                EXPORT  USART1_IRQHandler                 [WEAK]                                          
                EXPORT  USART2_IRQHandler                 [WEAK]                                          
                EXPORT  USART3_IRQHandler                 [WEAK]                                         
                EXPORT  EXTI15_10_IRQHandler              [WEAK]                                  
                EXPORT  RTC_Alarm_IRQHandler              [WEAK]                  
                EXPORT  OTG_FS_WKUP_IRQHandler            [WEAK]                        
                EXPORT  TIM8_BRK_TIM12_IRQHandler         [WEAK]                 
                EXPORT  TIM8_UP_TIM13_IRQHandler          [WEAK]                 
                EXPORT  TIM8_TRG_COM_TIM14_IRQHandler     [WEAK] 
                EXPORT  TIM8_CC_IRQHandler                [WEAK]                                   
                EXPORT  DMA1_Stream7_IRQHandler           [WEAK]                                          
                EXPORT  FMC_IRQHandler                    [WEAK]                                             
                EXPORT  SDIO_IRQHandler                   [WEAK]                                             
                EXPORT  TIM5_IRQHandler                   [WEAK]                                             
                EXPORT  SPI3_IRQHandler                   [WEAK]                                             
                EXPORT  UART4_IRQHandler                  [WEAK]                                            
                EXPORT  UART5_IRQHandler                  [WEAK]                                            
                EXPORT  TIM6_DAC_IRQHandler               [WEAK]                   
                EXPORT  TIM7_IRQHandler                   [WEAK]                    
                EXPORT  DMA2_Stream0_IRQHandler           [WEAK]                                  
                EXPORT  DMA2_Stream1_IRQHandler           [WEAK]                                   
                EXPORT  DMA2_Stream2_IRQHandler           [WEAK]                                    
                EXPORT  DMA2_Stream3_IRQHandler           [WEAK]                                    
                EXPORT  DMA2_Stream4_IRQHandler           [WEAK]                                 
                EXPORT  ETH_IRQHandler                    [WEAK]                                         
                EXPORT  ETH_WKUP_IRQHandler               [WEAK]                     
                EXPORT  CAN2_TX_IRQHandler                [WEAK]                                               
                EXPORT  CAN2_RX0_IRQHandler               [WEAK]                                               
                EXPORT  CAN2_RX1_IRQHandler               [WEAK]                                               
                EXPORT  CAN2_SCE_IRQHandler               [WEAK]                                               
                EXPORT  OTG_FS_IRQHandler                 [WEAK]                                       
                EXPORT  DMA2_Stream5_IRQHandler           [WEAK]                                   
                EXPORT  DMA2_Stream6_IRQHandler           [WEAK]                                   
                EXPORT  DMA2_Stream7_IRQHandler           [WEAK]                                   
                EXPORT  USART6_IRQHandler                 [WEAK]                                           
                EXPORT  I2C3_EV_IRQHandler                [WEAK]                                              
                EXPORT  I2C3_ER_IRQHandler                [WEAK]                                              
                EXPORT  OTG_HS_EP1_OUT_IRQHandler         [WEAK]                      
                EXPORT  OTG_HS_EP1_IN_IRQHandler          [WEAK]                      
                EXPORT  OTG_HS_WKUP_IRQHandler            [WEAK]                        
                EXPORT  OTG_HS_IRQHandler                 [WEAK]                                      
                EXPORT  DCMI_IRQHandler                   [WEAK]                                                                                 
                EXPORT  HASH_RNG_IRQHandler               [WEAK]
                EXPORT  FPU_IRQHandler                    [WEAK]
                
WWDG_IRQHandler                                                       
PVD_IRQHandler                                      
TAMP_STAMP_IRQHandler                  
RTC_WKUP_IRQHandler                                
FLASH_IRQHandler                                                       
RCC_IRQHandler                                                            
EXTI0_IRQHandler                                                          
EXTI1_IRQHandler                                                           
EXTI2_IRQHandler                                                          
EXTI3_IRQHandler                                                         
EXTI4_IRQHandler                                                          
DMA1_Stream0_IRQHandler                                       
DMA1_Stream1_IRQHandler                                          
DMA1_Stream2_IRQHandler                                          
DMA1_Stream3_IRQHandler                                          
DMA1_Stream4_IRQHandler                                          
DMA1_Stream5_IRQHandler                                          
DMA1_Stream6_IRQHandler                                          
ADC_IRQHandler                                         
CAN1_TX_IRQHandler                                                            
CAN1_RX0_IRQHandler                                                          
CAN1_RX1_IRQHandler                                                           
CAN1_SCE_IRQHandler                                                           
EXTI9_5_IRQHandler                                                
TIM1_BRK_TIM9_IRQHandler                        
TIM1_UP_TIM10_IRQHandler                      
TIM1_TRG_COM_TIM11_IRQHandler  
TIM1_CC_IRQHandler                                               
TIM2_IRQHandler                                                           
TIM3_IRQHandler                                                           
TIM4_IRQHandler                                                           
I2C1_EV_IRQHandler                                                         
I2C1_ER_IRQHandler                                                         
I2C2_EV_IRQHandler                                                        
I2C2_ER_IRQHandler                                                           
SPI1_IRQHandler                                                          
SPI2_IRQHandler                                                           
USART1_IRQHandler                                                       
USART2_IRQHandler                                                       
USART3_IRQHandler                                                      
EXTI15_10_IRQHandler                                            
RTC_Alarm_IRQHandler                            
OTG_FS_WKUP_IRQHandler                                
TIM8_BRK_TIM12_IRQHandler                      
TIM8_UP_TIM13_IRQHandler                       
TIM8_TRG_COM_TIM14_IRQHandler  
TIM8_CC_IRQHandler                                               
DMA1_Stream7_IRQHandler                                                 
FMC_IRQHandler                                                            
SDIO_IRQHandler                                                            
TIM5_IRQHandler                                                            
SPI3_IRQHandler                                                            
UART4_IRQHandler                                                          
UART5_IRQHandler                                                          
TIM6_DAC_IRQHandler                            
TIM7_IRQHandler                              
DMA2_Stream0_IRQHandler                                         
DMA2_Stream1_IRQHandler                                          
DMA2_Stream2_IRQHandler                                           
DMA2_Stream3_IRQHandler                                           
DMA2_Stream4_IRQHandler                                        
ETH_IRQHandler                                                         
ETH_WKUP_IRQHandler                                
CAN2_TX_IRQHandler                                                           
CAN2_RX0_IRQHandler                                                          
CAN2_RX1_IRQHandler                                                          
CAN2_SCE_IRQHandler                                                          
OTG_FS_IRQHandler                                                    
DMA2_Stream5_IRQHandler                                          
DMA2_Stream6_IRQHandler                                          
DMA2_Stream7_IRQHandler                                          
USART6_IRQHandler                                                        
I2C3_EV_IRQHandler                                                          
I2C3_ER_IRQHandler                                                          
OTG_HS_EP1_OUT_IRQHandler                           
OTG_HS_EP1_IN_IRQHandler                            
OTG_HS_WKUP_IRQHandler                                
OTG_HS_IRQHandler                                                   
DCMI_IRQHandler                                                                                                             
HASH_RNG_IRQHandler
FPU_IRQHandler  
           
                B       .

                ENDP

                ALIGN

;*******************************************************************************
; User Stack and Heap initialization    编译器预处理命令,主要是用来初始化用户堆栈
;*******************************************************************************
                 IF      :DEF:__MICROLIB    ; "DEF"的用法为 :DEF:X 就是说X定义了则为真,否则为假。若定义了__MICROLIB,则将__initial_sp,__heap_base,__heap_limit亦即栈顶地址,堆始末地址赋予全局属性,使外部程序可以使用。
                
                 EXPORT  __initial_sp
                 EXPORT  __heap_base
                 EXPORT  __heap_limit
                
                 ELSE                       ; 如果没定义__MICROLIB,则使用默认的C运行时库
                
                 IMPORT  __use_two_region_memory        ; 用于指定存储器模式为双段模式,即一部分储存区用于栈空间,其他的存储区用于堆空间,堆区空间可以为0,但是,这样就不能调用malloc()内存分配函数;堆区空间也可以由存储器分配,也可以从执行环境中继承。在汇编代码中,通过 IMPORT __use_two_region_memory 表明使用双段模式;在C语言中,通过 #pragma import(__use_two_region_memory)语句表明使用双段模式。
                 EXPORT  __user_initial_stackheap
                 
__user_initial_stackheap                    ; 此处是初始化两区的堆栈空间,堆是从由低到高的增长,栈是由高向低生长的,两个是互相独立的数据段,并不能交叉使用。

                 LDR     R0, =  Heap_Mem                        ; 保存堆始地址
                 LDR     R1, =(Stack_Mem + Stack_Size)          ; 保存栈的大小
                 LDR     R2, = (Heap_Mem +  Heap_Size)          ; 保存堆的大小
                 LDR     R3, = Stack_Mem                        ; 保存栈顶指针
                 BX      LR

                 ALIGN                                          ; 填充字节使地址对齐

                 ENDIF

                 END                                            ; END 命令指示汇编器,已到达一个源文件的末尾。

;************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE*****

参考

  1. Developing Software for ARM Processors.pdf
  2. ARM Compiler C Library Startup and Initialization.pdf
  3. ARM C and C++ Libraries and Floating-Point Support.pdf
ZCShouEXP CSDN认证博客专家 砖家 码字员 没了
进步始于交流,收获源于分享!进步始于交流,收获源于分享!进步始于交流,收获源于分享!进步始于交流,收获源于分享!进步始于交流,收获源于分享!
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页