前言:本篇分析的是一个最精简的
启动代码,并且包含一个简单的
中断处理,C程序部分省略,重点分析汇编部分,这是因为对于我来说,汇编代码实在是让人厌烦,但是又不能不用。
下面是对代码的分析,红色部分是分析结果
.extern main //.extern 表示main在另外的文件中定义,在这里要引用,至于为什么只声明了extern而没 //有声明别的,目前还不知道,不过都声明一下,应该没问题
.text //.text 表示后面的内容编译出来放在代码段
.global _start //.global 告诉编译器后面声明的是一个全局可见的名字,由于这是启动代码,所以cpu上电后 //必须要找到_start函数,所以_start必须声明为全局的,当然这个名字可以改,无所谓
_start: //查看反汇编地址就可以发现,_start的地址就是0x0
b Reset //不带返回的跳转到Reset中,为什么不用返回呢,因为没必要,reset中直接进入到主函数内了
HandleUndef: //查看反汇编地址可知HandleUndef的地址位0x04,这个很好理解,因为一条指令4个字节
b HandleUndef //在这里由于是精简的启动代码,所以一旦发生了未定义异常时,就让CPU自己玩死自己吧
HandleSWI: //反汇编地址0x08,其他分析同上
b HandleSWI
HandlePrefetchAbort: //反汇编地址0x0C,其他分析同上
b HandlePrefetchAbort
HandleDataAbort: //反汇编地址0x10,其他分析同上
b HandleDataAbort
HandleNotUsed: //反汇编地址0x14,其他分析同上
b HandleNotUsed
HandleIRQ:
b HandlerIRQ //反汇编地址0x18,看到这里相比就有点感觉了,0x18是普通中断向量地址,这个就有很 //多地方可说了,首先这里依然是使用B指令进行跳转,这个之所以不直接用BL的原因 ///是,中断还不太算是调用函数那么简单,发生中断的时候,要保存现场,而现场的数 //据有很多,具体为R0-R12、PC、CPSR的内容,这些都需要进栈保存,所以这些的内容不 //是BL一条命令能完成的,所以保存现场的内容就直接放到了中断程序中了。其次要特别 //注意这个里面跳转的程序时HandlerIRQ不是HandleIRQ,如果还像上面那样,那么发生中 //断时,CPU就会不停的循环来回跳了,所以这点需要特别留意,当然还有一种方法,就是 //不要这条命令的标号HandleIRQ,直接使用一条 b HandlerIRQ即可。
HandleFIQ:
b HandleFIQ //反汇编地址位0x1C,由于本程序只分析简单的普通中断,所以认为发生快速 //中断的时候,让CPU自己玩
Reset:
ldr sp,=4096 //由于要在汇编中调用C函数,所以要先设置堆栈指针,具体为什么,就 //不详细分析了,简单的说,C函数要使用很多的中间内存存放运算数据,所以 //要开辟一段堆栈用。这里还要特别提到一点,由于ARM工作模式的特点,此时 //设置的堆栈指针SP,即R14,对应的是系统模式下的堆栈指针寄存器,即R14_svc
bl disable_watch_dog //关闭看门狗
msr cpsr_c,# 0xd2 //设置CPU进入到中断模式
ldr sp,=3072 //由于发生中断时,要用到堆栈用于保存现场,所以需要先设置中断模式下的堆 //栈指针地址(设置堆栈指针就相当于开辟堆栈了,因为堆栈就是有堆栈指针的 //一片普通内存区域),即设置R14_irq,特别注意R14_irq和R14_svc是不一样 //的,只是同名,但是指向的物理地址是完全不同的。
msr cpsr_c,# 0xdf //从普通中断模式返回到系统模式
bl init_led //这个非常值得分析,首先这里使用了BL指令进行跳转,BL指令的特点就是,跳转 //的同时,会自动的将PC的值放到LR中,而且,如果后面跳转的是C函数的话,C函 //数中就不用设置返回命令了,而如果BL后面跟的是一个汇编子程序,那就需要程 //序员自己添加返回命令,这是为什么呢?如果用专业术语说,如果调用C函数, //函数运行结束后,编译器会自动的将上面保存的LR中的内容减去4重新传递给 //PC(为什么减4下面分析),也就实现了自动返回的功能,但是汇编函数不行,因 //为汇编的编译器没有这项功能,所以通俗的讲,为什么C语言是高级语言,除了语 //法高级人性化,配套的编译器也比较人性化,会帮程序员做一些通用的工作。而 //汇编语言就比较一根筋,所有的事儿,哪怕是最简单的事儿,都要程序员一条一 //条的把代码敲上去告诉它怎么干(这也是我为什么讨厌汇编的原因,比较懒,呵 //呵),至于调用汇编子程序怎么返回怎么做,分析在下面