ARM Cortex-M3的startup.s文件详解

以LM3S9B90为例。Startup.s文件是系统的启动文件,主要包括堆和栈的初始化配置、中断向量表的配置以及将程序引导到main( )函数等。

Startup.s主要完成三个工作:栈和堆的初始化、定位中断向量表、调用Reset Handler。

a)堆和栈的初始化

Startup.s中的代码如下图所示:

1.程序分别对堆和栈进行了大小的规定以及空间的分配。

Stack   EQU     0x00002000     //定义栈的大小。EQU相当于汇编当中的宏定义,Stack替换0x00002000,即8*1024字节=8KB。

Heap    EQU     0x00000000         //定义堆的大小。

2.为栈分配8K Byte空间。

AREA    STACK, NOINIT, READWRITE, ALIGN=3  //堆栈段, 未初始化, 允许读写, 8字节边界对齐。

说明:AREA命令指示汇编器汇编一个新的代码段或者数据段。Contrx-M3的指令地址要求是字边界对齐(4字节),但是代码段是要求8字节边界对齐的。NOINIT:指定此数据段仅仅保留了内存单元,而没有将各初始值写入内存单元,或者将各个内存单元值初始化为0。

StackMem    SPACE   Stack    //分 配连续 Stack_Size 字节的存储单元并初始化为 0

__initial_sp                    //标号,代表堆栈顶部地址

3.为堆分配空间。

  .             

        AREA    HEAP, NOINIT, READWRITE, ALIGN=3  //堆栈段, 未初始化, 允许读写, 8字节边界对齐。

__heap_base      //标号,代表堆末底部地址

HeapMem

        SPACE   Heap  //分配堆空间

__heap_limit      //标号,代表堆界限地址

PRESERVE8       //指示编译器8字节对齐。

说明:PRESERVE8 指令指定当前文件保持堆栈八字节对齐。 它设置 PRES8 编译属性以通知链接器。链接器检查要求堆栈八字节对齐的任何代码是否仅由保持堆栈八字节对齐的代码直接或间接地调用。

b)定位中断向量表

;******************************************************************************

;

; Place code into the reset code section.

;

;******************************************************************************

    AREA    RESET, CODE, READONLY   //定义只读数据段,放在CODE区,位于0地址

        THUMB           //指示编译器以后的指令为THUMB指令

;******************************************************************************

;

; The vector table.

;以下为向量表,在复位时被映射到FLASH的0地址。

;******************************************************************************

    EXPORT  __Vectors     //EXPORT:在程序中声明一个全局的标号__Vectors,该标号可在其他的文件中引用。EXPORT 命令声明一个符号,可由链接器用于解释各个目标和库文件中的符号引用,相当于声明了一个全局变量。 

IMPORT uart0_interrupt         //引入UART0中断    

IMPORT tick_interrupt          //引入systick中断

IMPORT eth_interrupt           //引入eth中断

IMPORT timer0_interrupt  //引入timer0中断

IMPORT reset_interrupt  //引入reset中断

 //DCD 命令分配一个或多个字的存储器,在四个字节的边界上对齐,并定义存储器的运行时初值。

__Vectors

        DCD     StackMem + Stack            // ; Top of Stack;栈顶指针,被放在向量表的开始,FLASH的0地址,复位后首先装载栈顶指针

        DCD     Reset_Handler               //; Reset Handler。复位异常,装载完栈顶后,第一个执行的,并且不返回

        DCD     NmiSR                     //  ; NMI Handler。不可屏蔽中断

        DCD     FaultISR                   // ; Hard Fault Handler。硬件错误中断

        DCD     IntDefaultHandler           //; MPU Fault Handler。内存管理错误中断

        DCD     IntDefaultHandler           //; Bus Fault Handler。总线错误中断

        DCD     IntDefaultHandler           //; Usage Fault Handler。用法错误中断

        DCD     0                        //; Reserved

        DCD     0                        //; Reserved

        DCD     0                        //; Reserved

        DCD     0                        //; Reserved

        DCD     IntDefaultHandler          //; SVCall Handler。系统调用异常,主要是为了调用操作系统内核服务

        DCD     IntDefaultHandler          //; Debug Monitor Handler

        DCD     0                        // ; Reserved

        DCD     IntDefaultHandler          //; PendSV Handler

        DCD     tick_interrupt            //; SysTick Handler

        DCD     IntDefaultHandler         // ; GPIO Port A

        DCD     reset_interrupt             //; reset Handler

        DCD     IntDefaultHandler         // ; GPIO Port C

        DCD     IntDefaultHandler         //; GPIO Port D

        DCD     IntDefaultHandler         //; GPIO Port E

        DCD     uart0_interrupt           //; UART0

        DCD     IntDefaultHandler         //; UART1

        DCD     IntDefaultHandler        // ; SSI

        DCD     IntDefaultHandler        //; I2C

        DCD     IntDefaultHandler        //; PWM Fault

        DCD     IntDefaultHandler        //; PWM Generator 0

        DCD     IntDefaultHandler        //; PWM Generator 1

        DCD     IntDefaultHandler        //; PWM Generator 2

        DCD     IntDefaultHandler        //; Quadrature Encoder

        DCD     IntDefaultHandler        //; ADC Sequence 0

        DCD     IntDefaultHandler        //; ADC Sequence 1

        DCD     IntDefaultHandler        //; ADC Sequence 2

        DCD     IntDefaultHandler        //; ADC Sequence 3

        DCD     IntDefaultHandler        //; Watchdog

        DCD     timer0_interrupt          //; Timer 0A

        DCD     IntDefaultHandler        // ; Timer 0B

        DCD     IntDefaultHandler        //; Timer 1A

        DCD     IntDefaultHandler        //; Timer 1B

        DCD     IntDefaultHandler        //; Timer 2A

        DCD     IntDefaultHandler        //; Timer 2B

        DCD     IntDefaultHandler        //; Comp 0

        DCD     IntDefaultHandler        //; Comp 1

        DCD     IntDefaultHandler        //; Comp 2

        DCD     IntDefaultHandler        //; System Control

        DCD     IntDefaultHandler        //; Flash Control

        DCD     IntDefaultHandler        //; GPIO Port F

        DCD     IntDefaultHandler        //; GPIO Port G

        DCD     IntDefaultHandler        //; GPIO Port H

        DCD     IntDefaultHandler        // ; UART2 Rx and Tx

        DCD     IntDefaultHandler        // ; SSI1 Rx and Tx

        DCD     IntDefaultHandler        // ; Timer 3 subtimer A

        DCD     IntDefaultHandler        //; Timer 3 subtimer B

        DCD     IntDefaultHandler        //; I2C1 Master and Slave

        DCD     IntDefaultHandler        //; Quadrature Encoder 1

        DCD     IntDefaultHandler        // ; CAN0

        DCD     IntDefaultHandler        // ; CAN1

        DCD     IntDefaultHandler        // ; CAN2

        DCD     eth_interrupt            //; Ethernet

        DCD     IntDefaultHandler        //; Hibernate

        DCD     IntDefaultHandler        //; USB0

        DCD     IntDefaultHandler        //; PWM Generator 3

        DCD     IntDefaultHandler        // ; uDMA Software Transfer

        DCD     IntDefaultHandler        // ; uDMA Error

c)调用Reset Handler

IMPORT  _main     //通知编译器要使用的标号在其他文件

B         _main    //把程序流程转到主应用程序

ALIGN         //默认是字对齐方式,也说明了代码是4字节对齐的

|.text|  用于表示由 C 编译程序产生的代码段,或用于以某种方式与 C 库关联的代码段。

AREA    |.text|, CODE, READONLY       //定义C编译器源代码的代码段,只读

堆栈的初始化:

IF :DEF: __MICROLIB  //“DEF”的用法——:DEF:X 就是说X定义了则为真,否则为假;如果定义了MICORLIB。

        EXPORT  __initial_sp  //则将栈顶地址、

        EXPORT  __heap_base  //堆起始地址、

        EXPORT __heap_limit   //堆末端界限地址赋予全局属性,使外部程序可调用

    ELSE    //如果没定义__MICROLIB,则使用默认的C运行时库

        IMPORT  __use_two_region_memory  //通知编译器要使用的标号在其他文件

        EXPORT  __user_initial_stackheap  

__user_initial_stackheap

           //此处是初始化两区的堆栈空间,堆是从由低到高的增长,栈是由高向低生长的,两个是互相独立的数据段,并不能交叉使用。

        LDR     R0, =HeapMem           //保存堆始地址

        LDR     R1, =(StackMem + Stack)   //保存栈的大小

        LDR     R2, =(HeapMem + Heap)   //保存堆的大小

        LDR     R3, =StackMem          //保存栈顶指针

        BX      LR

    ENDIF

;******************************************************************************

;

; Make sure the end of this section is aligned.

;

;******************************************************************************

        ALIGN     //填充字节使地址对齐

;******************************************************************************

;

; Tell the assembler that we're done.

;

;******************************************************************************

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

转自:https://blog.csdn.net/binghuoqian/article/details/25961719

发布了264 篇原创文章 · 获赞 520 · 访问量 300万+

猜你喜欢

转载自blog.csdn.net/phenixyf/article/details/96319913