keil arm 为什么要有startup.s

本文详细解析了ARM7启动文件STARTUP.S,包括模式定义、堆栈大小、中断向量表、初始化寄存器等内容,帮助读者理解和实现自己的启动程序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

对于操作系统来讲,从系统上电到操作系统开始运行之间,要做的事情很多。
比如,检测设备,解压内核,文件系统,设置中断,开启虚拟内存管理等等,这个是平台相关但有几乎相同的。这些看看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  Undef_handler
SWI_handler   SWI_handler
PAbt_handler  PAbt_handler
DAbt_handler  DAbt_handler
FIQ_handler   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()
     __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


<think>好的,我现在需要帮助用户解决Keil5中缺失startup.a51文件的问题。首先,我得回想一下自己对Keil和C51的了解。记得startup.a51是启动代码,负责初始化堆栈、内存等,对于单片机程序很重要。用户提到文件缺失,可能是在新建项目时没有自动生成或者版本问题。 接下来,我应该确认用户的问题具体是什么情况导致的。可能的原因有几个:使用新版本Keil时默认不包含该文件,项目配置不当,或者用户自己误删了。根据引用内容,比如引用1提到startup.a51的作用,引用3和4说明初始化全局变量和内存设置需要它,所以缺失会导致编译错误。 然后,解决方案方面,首先想到的是手动添加startup.a51。用户需要从安装目录或示例项目里复制这个文件到自己的项目,并添加到工程中。另外,检查项目配置,确保在创建新项目时选择生成启动代码,或者调整链接器设置。如果用户使用新的编译器如C51,可能默认不再需要这个文件,但需要确认是否正确处理了初始化部分。 可能还需要考虑不同版本的Keil是否有差异,比如Keil5是否默认不再自动包含该文件,或者是否被其他配置替代。同时,用户可能需要根据具体芯片型号调整启动文件的设置,比如堆栈大小等,如引用3提到的内存初始化。 最后,生成相关问题时要围绕启动文件的作用、配置方法、不同处理方式以及错误排查等,帮助用户深入理解问题。需要确保回答结构清晰,分步骤给出解决方法,并引用相关资料支持。</think>关于Keil5中缺失startup.a51文件的问题,以下是具体原因及解决方案: ### 一、缺失原因分析 1. **新版默认配置变化** Keil MDK-ARM版本默认使用ARM编译器,不会自动包含针对8051架构的startup.a51文件。该文件是C51编译器的专属启动代码[^3] 2. **项目类型选择错误** 创建新项目时若错误选择了ARM项目模板而非C51项目模板,系统不会生成该启动文件[^1] 3. **手动删除或路径错误** 用户可能误删除了工程目录下的startup.a51文件,或文件被移动到非常规路径导致编译器无法识别[^2] ### 二、解决方案步骤 1. **手动添加标准文件** - 打开Keil安装目录:`C:\Keil_v5\C51\LIB` - 复制`STARTUP.A51`到项目目录 - 右击工程目录选择"Add Existing Files to Group..." 2. **修改工程配置** ```plaintext Project -> Options for Target -> Device 确认选择正确的8051芯片型号 ``` 在Linker选项卡勾选"Use Memory Layout from Target Dialog"[^4] 3. **自定义启动文件(高级)** 若需要修改初始化配置: ```assembly ; 示例堆栈设置 IDATALEN EQU 80H ; 设置idata内存大小 XDATASTART EQU 0x1000 ; 定义xdata起始地址 ``` 建议保留默认值除非有特殊内存规划[^3] 4. **检查编译器兼容性** 通过`Project -> Manage -> Project Items`确认已安装C51编译器套件,且项目未错误使用ARM编译器 ### 三、验证方法 编译后查看.map文件,应出现以下关键初始化流程: ```plaintext C:0x0000 LJMP STARTUP1 ; 程序入口跳转 C:0x0003 DB 0x02 ; 中断向量表 ... STARTUP1: MOV SP,#0x60 ; 堆栈指针初始化 ``` [^1][^4]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值