本博客的参考文章及相关资料下载 :
参考手册 :
异常定义 :
异常类型 : ARM 架构 支持 七种类型的异常,
异常处理简介 :
Start.S 汇编程序解析 :
.text
宏 指明汇编代码段;.global _start
将 _start 声明成全局符号; 使用 _start:
标明程序的入口标号是 _start; 标号:
, 例如 irq:
;
irq : nop
;nop
表示 什么操作都不执行; 标号: .word 存储值的内容
;
_irq: .word irq
, 定义 _irq 标号, .word
表示该标号存储的是 32 位值, 这个值的大小就是 irq
地址;b{条件} 地址
, 如果①满足条件, 就跳转到 地址 位置, 如果②不满足条件, 就执行下面的语句, ③如果没有条件, 就是 100% 执行;b reset
, 异常发生时, 直接跳转到 reset
标号处执行代码;ldr 寄存器, 地址
, 将 地址 中存放的数据 装载 到 寄存器中; irq
, 即跳转到该标号处, 就开始执行标号下面的指令, irq : nop
; _irq
, 用于存放一个 32 位的值, 这里用于存放 上面 定义的标号 地址, _irq .word irq
ldr pc, _irq
, 将 _irq
标号中存放的值, 这个值是 irq
标号的地址, 就是跳转到该地址去执行指令; @****************************
@File:start.S
@
@异常处理框架
@****************************
.text @ 宏 指明代码段
.global _start @ 伪指令声明全局开始符号
_start: @ 程序入口标志
b reset @ reset 复位异常
ldr pc, _undefined_instruction @ 未定义异常, 将 _undefined_instruction 值装载到 pc 指针中
ldr pc, _software_interrupt @ 软中断异常
ldr pc, _prefetch_abort @ 预取指令异常
ldr pc, _data_abort @ 数据读取异常
ldr pc, _not_used @ 占用 0x00000014 地址
ldr pc, _irq @ 普通中断异常
ldr pc, _fiq @ 软中断异常
_undefined_instruction: .word undefined_instruction @ _undefined_instruction 标号存放了一个值, 该值是 32 位地址 undefined_instruction, undefined_instruction 是一个地址
_software_interrupt: .word software_interrupt @ 软中断异常
_prefetch_abort: .word prefetch_abort @ 预取指令异常 处理
_data_abort: .word data_abort @ 数据读取异常
_not_used: .word not_used @ 空位处理
_irq: .word irq @ 普通中断处理
_fiq: .word fiq @ 快速中断处理
undefined_instruction: @ undefined_instruction 地址存放要执行的内容
nop
software_interrupt: @ software_interrupt 地址存放要执行的内容
nop
prefetch_abort: @ prefetch_abort 地址存放要执行的内容
nop
data_abort: @ data_abort 地址存放要执行的内容
nop
not_used: @ not_used 地址存放要执行的内容
nop
irq: @ irq 地址存放要执行的内容
nop
fiq: @ fiq 地址存放要执行的内容
nop
reset: @ reset 地址存放要执行的内容
nop
gboot.lds 链接器脚本 代码解析 :
OUTPUT_ARCH(架构名称)
指明输出格式, 即处理器的架构, 这里是 arm 架构的, OUTPUT_ARCH(arm)
;ENTRY(入口位置)
, 在上面的 Start.S 中设置的程序入口是 _start
, 代码为 ENTRY(_start)
;.text :
设置代码段; .data :
设置数据段;.bss :
设置 BSS 段;
bss_start = .;
;bss_end = .;
;. = ALIGN(4);
设置四字节对齐即可;OUTPUT_ARCH(arm) /*指明处理器结构*/
ENTRY(_start) /*指明程序入口 在 _start 标号处*/
SECTIONS {
. = 0x50008000; /*整个程序链接的起始位置, 根据开发板确定, 不同开发板地址不一致*/
. = ALIGN(4); /*对齐处理, 每段开始之前进行 4 字节对齐*/
.text : /*代码段*/
{
start.o (.text) /*start.S 转化来的代码段*/
*(.text) /*其它代码段*/
}
. = ALIGN(4); /*对齐处理, 每段开始之前进行 4 字节对齐*/
.data : /*数据段*/
{
*(.data)
}
. = ALIGN(4); /*对齐处理, 每段开始之前进行 4 字节对齐*/
bss_start = .; /*记录 bss 段起始位置*/
.bss : /*bss 段*/
{
*(.bss)
}
bss_end = .; /*记录 bss 段结束位置*/
}
makefile 文件编写 :
%.o : %.S
, 产生过程是 arm-linux-gcc -g -c $^
, 其中 ^
标识是所有的依赖文件, 在该规则下 start.S 会被变异成 start.o ; %.o : %.c
, 产生过程是 arm-linux-gcc -g -c $^
; all: start.o #依赖于 start.o
arm-linux-ld -Tgboot.lds -o gboot.elf $^ #使用链接器脚本, 将 start.o 转为 gboot.elf
arm-linux-objcopy -O binary gboot.elf gboot.bin #将 gboot.elf 转化为可以直接在板子上执行的 gboot.bin 文件
%.o : %.S #通用规则, 如 start.o 是由 start.S 编译来的, -c 是只编译不链接
arm-linux-gcc -g -c $^
%.o : %.c #通用规则, 如 start.o 是由 start.c 编译来的, -c 是只编译不链接
arm-linux-gcc -g -c $^
.PHONY: clean
clean: #清除编译信息
rm *.o *.elf *.bin
编译过程 :
make
; 本博客的参考文章及相关资料下载 :