arm异常向量表与arm汇编

异常向量表:

    .global _start   ; 声明_start为全局符号,作为程序的入口点,链接器会从这里开始执行

; 异常向量表(Exception Vector Table)
; ARM处理器规定在地址0x00000000开始的位置必须存放异常向量表
; 当发生复位或各类异常时,CPU会自动跳转到对应位置执行
_start:
    ldr pc, =_reset_handler        ; 0x00: 复位异常向量,程序启动或复位时执行
    ldr pc, =_undefine_handler     ; 0x04: 未定义指令异常向量
    ldr pc, =_svc_handler          ; 0x08: 管理模式(SVC)异常向量
    ldr pc, =_prefetch_abort_handler ; 0x0C: 预取中止异常向量(取指令出错)
    ldr pc, =_data_abort_handler   ; 0x10: 数据中止异常向量(访问数据出错)
    ldr pc, =_reserved_handler     ; 0x14: 保留向量(未使用)
    ldr pc, =_irq_handler          ; 0x18: 中断请求(IRQ)异常向量
    ldr pc, =_fiq_handler          ; 0x1C: 快速中断请求(FIQ)异常向量

; 异常处理函数(当前均为简单的死循环,仅作占位使用)
_undefine_handler:
    ldr pc, =_undefine_handler     ; 未定义指令异常:无限循环(原地跳转)

_svc_handler:
    ldr pc, =_svc_handler          ; 管理模式异常:无限循环

_prefetch_abort_handler:
    ldr pc, =_prefetch_abort_handler ; 预取中止异常:无限循环

_data_abort_handler:
    ldr pc, =_data_abort_handler   ; 数据中止异常:无限循环

_reserved_handler:
    ldr pc, =_reserved_handler     ; 保留向量:无限循环

_irq_handler:
    ldr pc, =_irq_handler          ; IRQ中断:无限循环

_fiq_handler:
    ldr pc, =_fiq_handler          ; FIQ中断:无限循环

; 复位处理函数(系统上电或复位后实际执行的第一个函数)
_reset_handler:
    ; 配置IRQ模式的堆栈
    mrs r0, cpsr                   ; 将当前程序状态寄存器(CPSR)的值读取到r0
    bic r0, r0, #0x1F              ; 清除CPSR的低5位(模式控制位)
    orr r0, r0, #0x12              ; 设置为IRQ模式(0x12表示IRQ模式,禁止IRQ中断)
    msr cpsr, r0                   ; 将修改后的值写回CPSR,完成模式切换
    
    ldr sp, =0x86000000            ; 设置IRQ模式下的栈指针(SP)到0x86000000地址
    
    ; 配置系统模式的堆栈
    mrs r0, cpsr                   ; 再次读取CPSR寄存器
    bic r0, r0, #0x1F              ; 清除模式控制位
    orr r0, r0, #0x1F              ; 设置为系统模式(0x1F表示系统模式,特权模式)
    msr cpsr, r0                   ; 切换到系统模式
    
    ldr sp, =0x84000000            ; 设置系统模式下的栈指针(SP)到0x84000000地址
    
    ; 初始化硬件并点亮LED
    bl _enable_clock               ; 跳转到时钟使能函数(bl指令会保存返回地址到lr寄存器)
    bl _init_led                   ; 跳转到LED初始化函数
    bl _led_on                     ; 跳转到点亮LED函数
    b finished                     ; 跳转到主循环(程序主体逻辑结束)

; 点亮LED函数(控制LED输出低电平点亮)
_led_on:
    ldr r0, =0x0209C000            ; 加载GPIO1_DR寄存器地址到r0(数据输出寄存器)
    ldr r1, [r0]                   ; 读取当前GPIO1_DR寄存器的值到r1
    bic r1, r1, #(1 << 3)          ; 清除r1的第3位(bit3),对应LED引脚输出低电平
    str r1, [r0]                   ; 将修改后的值写回GPIO1_DR寄存器,LED点亮
    bx lr                          ; 返回到调用处(利用lr寄存器中的返回地址)

; LED初始化函数(配置GPIO引脚为输出模式)
_init_led:
    ; 配置引脚复用功能
    ldr r0, =0x020E0068            ; 加载IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03寄存器地址
    mov r1, #0x05                  ; 设置值为0x05,将引脚复用为GPIO功能
    str r1, [r0]                   ; 写入配置值到复用控制寄存器
    
    ; 配置引脚电气属性
    ldr r0, =0x020E02F4            ; 加载IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03寄存器地址
    ldr r1, =0x10B0                ; 加载电气属性配置值(驱动强度、速度等)
    str r1, [r0]                   ; 写入电气属性配置
    
    ; 配置GPIO为输出模式
    ldr r0, =0x0209C004            ; 加载GPIO1_GDIR寄存器地址(方向控制寄存器)
    ldr r1, [r0]                   ; 读取当前方向寄存器值
    orr r1, r1, #(1 << 3)          ; 设置第3位(bit3)为1,配置为输出模式
    str r1, [r0]                   ; 写入方向配置值
    bx lr                          ; 返回到调用处

; 时钟使能函数(开启外设时钟,硬件才能工作)
_enable_clock:
    ldr r0, =0x020C4068            ; 加载CCM_CCGR0寄存器地址(时钟门控寄存器0)
    mov r1, #0xFFFFFFFF            ; 设置所有位为1,使能对应外设时钟
    str r1, [r0]                   ; 写入CCM_CCGR0寄存器
    
    ldr r0, =0x020C406C            ; 加载CCM_CCGR1寄存器地址
    str r1, [r0]                   ; 使能对应外设时钟
    
    ldr r0, =0x020C4070            ; 加载CCM_CCGR2寄存器地址
    str r1, [r0]                   ; 使能对应外设时钟
    
    ldr r0, =0x020C4074            ; 加载CCM_CCGR3寄存器地址
    str r1, [r0]                   ; 使能对应外设时钟
    
    ldr r0, =0x020C4078            ; 加载CCM_CCGR4寄存器地址
    str r1, [r0]                   ; 使能对应外设时钟
    
    ldr r0, =0x020C407C            ; 加载CCM_CCGR5寄存器地址
    str r1, [r0]                   ; 使能对应外设时钟
    
    ldr r0, =0x020C4080            ; 加载CCM_CCGR6寄存器地址
    str r1, [r0]                   ; 使能对应外设时钟
    
    ldr r0, =0x020C4088            ; 加载CCM_CCGR7寄存器地址
    str r1, [r0]                   ; 使能对应外设时钟
    bx lr                          ; 返回到调用处

; 程序主循环(完成初始化后进入无限循环)
finished:
    b finished                     ; 无限循环(原地跳转,防止程序跑飞)

arm.s文件编译烧录:

# 查看当前目录文件,显示有imxdownload工具和start.S汇编源文件
linux@ubuntu:~/IMX6ULL/LED_ASM$ ls
imxdownload  start.S

# 使用交叉编译器arm-linux-gnueabihf-gcc编译汇编文件
# -g: 生成调试信息
# -c: 只编译不链接,生成目标文件
# start.S: 输入的汇编源文件
# -o start.o: 输出目标文件为start.o
linux@ubuntu:~/IMX6ULL/LED_ASM$ arm-linux-gnueabihf-gcc -g -c start.S -o start.o

# 再次查看目录,确认生成了start.o目标文件
linux@ubuntu:~/IMX6ULL/LED_ASM$ ls
imxdownload  start.o  start.S

# 使用交叉链接器arm-linux-gnueabihf-ld进行链接
# -Ttext 0X87800000: 指定代码段起始地址为0X87800000(IMX6ULL的运行地址)
# start.o: 输入的目标文件
# -o start.elf: 输出可执行文件为start.elf
linux@ubuntu:~/IMX6ULL/LED_ASM$ arm-linux-gnueabihf-ld -Ttext 0X87800000 start.o -o start.elf

# 查看目录,确认生成了start.elf可执行文件
linux@ubuntu:~/IMX6ULL/LED_ASM$ ls
imxdownload  start.elf  start.o  start.S

# 使用objcopy工具将ELF文件转换为二进制文件(适合烧录)
# -O binary: 指定输出格式为二进制
# -S: 不复制重定位信息和符号信息
# -g: 不复制调试信息
# start.elf: 输入的ELF文件
# start.bin: 输出的二进制文件
linux@ubuntu:~/IMX6ULL/LED_ASM$ arm-linux-gnueabihf-objcopy -O binary -S -g start.elf start.bin

# 查看目录,确认生成了start.bin二进制文件
linux@ubuntu:~/IMX6ULL/LED_ASM$ ls
imxdownload  start.bin  start.elf  start.o  start.S

# 使用objdump工具反汇编ELF文件,生成汇编代码文本(用于调试分析)
# -D: 对所有段进行反汇编
# start.elf: 输入的ELF文件
# > start.dis: 将反汇编结果重定向到start.dis文件
linux@ubuntu:~/IMX6ULL/LED_ASM$ arm-linux-gnueabihf-objdump -D start.elf > start.dis

# 查看目录,确认生成了start.dis反汇编文件
linux@ubuntu:~/IMX6ULL/LED_ASM$ ls
imxdownload  start.bin  start.dis  start.elf  start.o  start.S

# 给imxdownload工具添加可执行权限(IMX6ULL专用下载工具)
linux@ubuntu:~/IMX6ULL/LED_ASM$ chmod +x imxdownload

# 确认imxdownload已具有可执行权限(文件名颜色通常会变为绿色)
linux@ubuntu:~/IMX6ULL/LED_ASM$ ls
imxdownload  start.bin  start.dis  start.elf  start.o  start.S

# 查看系统中的磁盘设备,确认SD卡对应的设备文件(这里/dev/sdb是目标SD卡)
linux@ubuntu:~/IMX6ULL/LED_ASM$ ls /dev/sd*
/dev/sda  /dev/sda1  /dev/sda2  /dev/sda3  /dev/sdb  /dev/sdb1

# 使用imxdownload工具将二进制文件下载到SD卡
# start.bin: 要下载的二进制程序
# /dev/sdb: 目标SD卡设备(注意不要选错设备,否则会损坏数据)
linux@ubuntu:~/IMX6ULL/LED_ASM$ ./imxdownload start.bin /dev/sdb
I.MX6ULL bin download software  # 工具提示信息:IMX6ULL专用下载软件
Edit by:zuozhongkai             # 作者信息
Date:2019/6/10                  # 日期
Version:V1.1                    # 版本
log:V1.0 initial version,just support 512MB DDR3  # 版本日志
    V1.1 and support 256MB DDR3
file start.bin size = 340Bytes  # 显示要下载的文件大小
Board DDR SIZE: 512MB           # 检测到开发板DDR容量为512MB
Delete Old load.imx             # 删除旧的load.imx文件(中间过渡文件)
Create New load.imx             # 创建新的load.imx文件
Download load.imx to /dev/sdb  ......  # 开始下载到SD卡

[sudo] password for linux:  # 提示输入sudo密码(操作磁盘设备需要管理员权限)

6+1 records in    # 输入的记录数(dd命令输出)
6+1 records out   # 输出的记录数
3412 bytes (3.4 kB, 3.3 KiB) copied, 0.139808 s, 24.4 kB/s  # 传输统计信息


arm-linux-gnueabihf-gcc -g -c start.S -o start.o

arm-linux-gnueabihf-ld -Ttext 0X87800000 start.o -o start.elf

arm-linux-gnueabihf-objcopy -O binary -S -g start.elf start.bin

arm-linux-gnueabihf-objdump -D start.elf > start.dis

chmod +x imxdownload

ls /dev/sd*

./imxdownload start.bin /dev/sdb

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值