keil arm 为什么要有startup.s

对于操作系统来讲,从系统上电到操作系统开始运行之间,要做的事情很多。
比如,检测设备,解压内核,文件系统,设置中断,开启虚拟内存管理等等,这个是平台相关但有几乎相同的。这些看看bootloader和boot.s吧。

但对于一般的程序,运行的是链接器给的一些东西,比如crtbegin.o,其实涉及到elf里面的一些段的概念,执行main函数前,要执行一些东西比如,
1,环境变量加载,

2,c++的全局构造函数...等



说实话,现在还不很清楚arm为什么必须要有startup.s,IAR的有,realview也有,就像x86里面的BIOS一样,作为CPU引导程序。
      arm存在7种模式,所以在使用的时候需要预先配置,可能因为汇编语言配置快速有效。
     另外main函数在arm中好像也需要startup.s程序引导。
     也许是编译器不直接支持c语言编制的文件吧,所以才需要startup.s引导


ARM7 startup.s 文件解析


前些天写过,我在学ARM的过程中,虽然看了书,对ARM的体系结构有了了解,可是当我实际想操作操作,写个程序的时候,却发现,真正的启动文件里面,还有很多书里面没有讲过的东西,看不懂。
 
为了弄懂这些看不懂的部分的含义,让自己真正能做到可以自己写程序,我把ADS带的英文帮助文件仔仔细细看了一遍,这才算明白一点了,前两天自己说现在把STARTUP.S里面所有的东西都弄明白了,其实也不是,但是大部分算是明白了。
 
我自己试着写了个启动程序,然后用C写了个LPC2220的外部中断的程序,两部分结合起来,用ADS编译,在ZLG的开发板上调试通过。
 
下面就是我写的STARTUP.S程序,贴在这里,说一下我对各部分的理解吧。文件中的注释是我当时加的,现在加的说明我用颜色区别开。程序主要参考了KEIL的启动文件,所以像堆栈设置等部分,方法也和KEIL的一样。

; A startup file for ARM by myself

; defination for mode (used for change work mode to setup stack)

MODE_USR  EQU  0X10
MODE_FIQ  EQU  0X11
MODE_IRQ  EQU  0X12
MODE_SVC  EQU  0X13
MODE_ABT  EQU  0X17
MODE_UND  EQU  0X1B
MODE_SYS  EQU  0X1F

I_BIT   EQU  0X80 ; I bit set to 1 to disable IRQ
F_BIT   EQU  0X40 ; F bit set to 1 to disable FIQ

 

; defination of stack size

UND_StackSize EQU  0X00*4
SVC_StackSize EQU  0X02*4
ABT_StackSize EQU  0X00*4
FIQ_StackSize EQU  0X20*4
IRQ_StackSize EQU  0X20*4
USR_StackSize EQU  0X100*4
ISR_StackSize EQU  (UND_StackSize + SVC_StackSize + ABT_StackSize + \
      FIQ_StackSize + IRQ_StackSize)
这个ISR_StackSize就是指所有中断程序的堆栈的尺寸之和,用来在后面计算堆栈top地址用的

    AREA STACK, NOINIT, READWRITE, ALIGN=4
USR_Stack  space USR_StackSize     定义堆栈的空间,usr在下面,isr的在上面
USR_StackTop space ISR_StackSize
StackTop         在这里放个标号,以获得堆栈顶部的地址

Heap_Size       EQU     0x100     heap好像主要是给c程序动态分配的内存使用的,如果不用 malloc, new, printf一类的,好像也可以不要(我的理解,不一定对阿)

                AREA    HEAP, NOINIT, READWRITE, ALIGN=4
__heap_base
Heap_Mem        SPACE   Heap_Size
__heap_limit


    AREA RESET, CODE, READONLY
    ENTRY
    CODE32
Vectors   LDR  PC, Reset_addr
    LDR  PC, Undef_addr
    LDR  PC, SWI_addr
    LDR  PC, PAbt_addr
    LDR  PC, DAbt_addr
    NOP       ; RESERVED VECTOR
    LDR  PC, [PC, #-0X0FF0] ; FOR VIC, FOR NORMAL USE LDR PC, IRQ_addr
    LDR  PC, FIQ_addr

Reset_addr  dcd  Reset_handler
Undef_addr  dcd  Undef_handler
SWI_addr  dcd  SWI_handler
PAbt_addr  dcd  PAbt_handler
DAbt_addr  dcd  DAbt_handler
FIQ_addr  dcd  FIQ_handler

Undef_handler b  Undef_handler
SWI_handler  b  SWI_handler
PAbt_handler b  PAbt_handler
DAbt_handler b  DAbt_handler
FIQ_handler  b  FIQ_handler

    EXPORT Reset_handler

Reset_handler LDR  R0,=StackTop    先把r0设置为stack的top address
    MSR  CPSR_c, #MODE_UND :OR: I_BIT :OR: F_BIT   ; ENTER UNDEFINED MODE
    MOV  SP, R0           ; SET SP TO THE TOP OF IT'S STACK
    SUB  R0, R0, #UND_StackSize       ; CALCULATE THE NEXT STACK'S TOP

    MSR  CPSR_c, #MODE_SVC :OR: I_BIT :OR: F_BIT
    MOV  SP, R0
    SUB  R0, R0, #SVC_StackSize   每设置完一种模式的堆栈,就减去,已得到下一种堆栈的top地址

    MSR  CPSR_c, #MODE_ABT :OR: I_BIT :OR: F_BIT
    MOV  SP, R0
    SUB  R0, R0, #ABT_StackSize
    
    MSR  CPSR_c, #MODE_FIQ :OR: I_BIT :OR: F_BIT
    MOV  SP, R0
    SUB  R0, R0, #FIQ_StackSize
    
    MSR  CPSR_c, #MODE_IRQ :OR: I_BIT :OR: F_BIT
    MOV  SP, R0
    SUB  R0, R0, #IRQ_StackSize
    
    MSR  CPSR_c, #MODE_USR        ; NO I/F BIT SETTING
    MOV  SP, R0
    SUB  SL, R0, #USR_StackSize       ; SET SL THE BOTTOM OF USER STACK, I DON'T KNOW WHAT IT MEAN  这里我有点不明白,谁能给说一下啊?
    
    IMPORT __main   __main是c环境的一个库函数,可以完成一些初始化的工作,然后跳转到用户的main()
    B  __main

 

                IMPORT  __use_two_region_memory   如果stack和heap在内存里分成了两段地址,就要用这个标志告诉编译器
                EXPORT  __user_initial_stackheap  如果使用了scatter文件来控制链接,则必须重载__user_initial_stackheap函数,否则编译器找不到heap的起始地址
__user_initial_stackheap

                LDR     R0, = __heap_base   为什么这么写,我也不知道,还请明白人指点一下吧。
                BX      LR
    
    END


你可能感兴趣的:(keil arm 为什么要有startup.s)