ARM基础概念 异常处理01 day52
四:ARM汇编语言程序格式
ARM汇编语言是以段(section)为单位来组织源文件的。段是相对独立的、具有特定名称的、不可分割的指令或者数据序列。
段又可以分为代码段和数据段,代码段存放执行代码,数据段存放代码运行时的数据,A搜素解释快速润色总一个ARM源程序至少需要一个代码段,大的程序可以包含多个代码段和数据段。
在汇编文件中,我们需要先定义一个段,在段中添加我们实现的汇编程序语句
一:六大指令集
1.分别为数据处理指令 //(完成CPU内部的计算)
2.Load/Store指令 //(完成CPU与内存IO外设之间的数据传输)
3.跳转指令 //(完成程序的跳转)
4.程序状态寄存器处理指令 //(完成 CPSR的管理)
5.协处理器指令 //(完成CPU扩展功能的实现)
6.异常产生指令 //(用户程序异常触发)
二:指令格式中符号说明
〈opcode〉{〈cond〉}{S} 〈Rd〉,〈Rn〉{,〈operand2〉}
opcode //操作码;指令助记符,如LDR、STR等。
cond //可选的条件码;执行条件,如EQ(相同)、NE(uneq 不相等)等。
S //可选后缀;若指定“S”,//则根据指令执行结果更新CPSR中的条件码。
Rd //目标寄存器。
Rn //存放第1操作数的寄存器。
Operand2 //第2个操作数
三:数据处理指令
算术指令: ADD ADC SUB SBC RSB(反向减,就是2 - 1 => 1 - 2) RSC
位 运 算 指令: AND(&) ORR(|) EOR(异或) BIC(位清零)
比较指令: CMP CMN TST TEQ
数据搬移: MOV MVN(按位取反放进去)语法:<操作> {<cond>} {S} Rd, Rn, Operand2
有比较指令影响标志位 -不指定Rd
数据搬移(MOV指令)不指定Rn
area reset, code, readonlycode32entrymov r0,#1 ;1搬移到r0中 # 不超过256mov r1,#2 ;2搬移到r1中add r2, r1, r0sub r3, r1, r0rsb r4, r0, r1and r5, r0, #0xfforr r6, r1, #0x01eor r7, r0, #0xfebic r8, r7, #0xfemvn r9,#0x01adc r10, r1, r0, LSL#1;sbc r11, r1, r1, LSL#1;rsc r12, r1, r0, LSL#1end
3.1进位的问题
;进位adc的使用area reset, code, readonlycode32entry;0x1 ffff ffff;0x2 ffff ffffmov r0, #0x01 mov r1, #0xffffffff mov r2, #0x02 mov r3, #0xffffffff adds r5, r1, r3 ;产生进位;产生进位需要+sadc r4, r0, r2 ;使用进位end
3.4比较的问题
;比较的使用有进位问题,也不需要+scmp r0, r1 ;只能两两比较movgt r2,r0 ;大于moveq ;等于movgt ;小于;所有指令都将可以 + eq 等。。。可选的条件码;执行为真才能执行 本质上先运算(真?/假?),在放入;图很重要,是判断标志位的启示,可以视为if判断的真假之说
;if判断
mov r0 #4
mov rl #5
mov r2 #3
cmp r0 rl ;先判断r0,r1
cmpgt r0 r2 ;上句成立,接着比较
;为什么用gt,因为涉及到截断特性,不加gt,就随便放入,随便执行了
movgt r3 r0
;1 ~ 100 相加area reset, code, readonlycode32entrymov r0, #1mov r1, #0
loopadd r1, r1, r0add r0, r0 ,#1cmp r0, #101bne loop ;这里用blt还是其他都合理,还是要看标志位end
3.5立即数
一个数(或按位取反)循环右移2^n(移动偶次)位后中所有的1能放进低8位中 范围0~255
;放非立即数或超过范围
ldr sp, =0x40001000 ;将一个地址加载到寄存器中
mov r0, #1 ;将立即数1搬移到r0中, #代表立即数
3.6入栈操作指令
ldr sp, =0x40001000 ;栈顶
;Load/Store指令 入栈只是其中之一
;(完成CPU与内存 IO外设之间的数据传输)
STMFD (Push) 块存储- Full Descending stack [STMDB]
LDMFD (Pop) 块装载-Full Descending stack [LDMIA]
------------------------------------------------
;用法
STMFD sp!,{r4-r7,lr} ;表示为r4 ~ r7 再加上一个lr
LDMFD sp!,{r4-r7,pc} ;入栈出栈的顺序要对 先进后出
3.7函数应用(栈)
ldr sp, =0x40001000 ;栈顶
;例子
funstmfd sp!,{lr}:;保护现场;代码。。。。。。。ldmfd sp!,{lr} ;恢复现场
3.8声明外部函数.c
preserve8 ;当c和汇编语言需要对齐8字节,放在最上面,是关键字;函数调用规则
;前四个参数,使用r0,r1,r2,r3存放参数,剩余参数使用栈传递
;返回值存放在r0中;
ldr sp, =0x40001000 ;栈顶
mov r0, #1
mov r1, #1
mov r2, #1
mov r3, #1
mov r4, #1
mov r5, #1
stmfd sp!, {r4,r5} ;用站import c_add ;声明一个外部符号,给汇编文件使用
bl c_add ;汇编语言不能带参数,不像c
int asm_add(int x,int y); //c中调汇编,声明int c_add(int a,int b)
{int sum = asm_add(a,b);return sum;
}
export asm_add ;声明一个内部符号给外部文件使用
ldr sp, =0x40001000 ;栈顶ams_addstmfd sp!,{r4 - r12,lr} ;保险,防止数据篡改add r0,r0,r1ldmfd sp!,{r4 - r12,pc}
3.9出栈代码简化问题
ldmfd sp!, {pc}
{lr} → 出栈到 LR,相当于“把栈顶值存到返回地址寄存器”,并不直接跳转。{pc} → 出栈到 PC,相当于“出栈并跳转到该地址”,这常用于函数返回。
3.10更改工作状态
mrs r0 cpsr
bic r0 r0 #0xlf
orr r0 r0 #0x10
msr cpsr_c r0
3.11软中断
swi #5 ;软中断指令 进入svc模式
;pc会默认跳到8
3.12总测试
int asm_add(int x,int y);//c中调汇编,声明int c_add(int a,int b)
{int sum = asm_add(a,b);return sum;
}
preserve8area reset, code, readonlycode32entryldr sp, =0x40001000 ;初始化svc模式的栈;进入C程序,里面也涉及到栈的使用mrs r0, cpsrbic r0, r0, #0x1forr r0, r0, #0x10msr cpsr_c, r0ldr sp, =0x4000c000 ;初始化user模式的栈import c_addbl c_addexport asm_add ;声明一个内部符号给外部文件使用asm_addstmfd sp!,{r4-r12,lr} ;保险,防止数据篡改mov r0, #1mov r1, #1add r0,r0,r1ldmfd sp!,{r4-r12,pc}end
五:异常处理
ARM 有两级外部中断 FIQ,IRQ.
可是大多数的基于ARM 的系统有有>2个的中断源,因此需要一个中断控制器
ps
:通常中断处理程序总是应该包含清除中断源的代码
为什么:外设或事件(比如定时器溢出、GPIO 变化、串口接收)会设置一个中断挂起标志位(pending flag)。CPU 检测到这个标志后,进入中断服务程序(ISR)。如果这个标志位不被清除,那么:ISR 执行结束时,CPU 发现中断源还在挂起 → 马上再次进入 ISR。程序就可能死在中断里,永远不回到主程序。
其中保存返回地址到LR ,软中断pc会默认跳到8
看图的右边偏移量对应就是每种异常pc默认回到的地址
一:异常规范函数
preserve8area reset, code, readonlycode32entry
;这里就是异常向量表 预设b start ; resetnop ; undefb deal_swi ; swinop ; prefetch abortnop ; data abortnop ; reservednop ; irqnop ; fiqdeal_swi ;预设stmfd sp!, {r4-r12, lr} add r0, r0, r1ldmfd sp!, {r4-r12, pc} startldr sp, =0x40001000 mrs r0, cpsrbic r0, r0, #0x1forr r0, r0, #0x10msr cpsr_c, r0 ldr sp, =0x40000C00 swi #5 ;ÈíÖжÏÖ¸Áîmov r0, #1mov r1, #2import c_add bl c_add nop b startexport asm_add
asm_addstmfd sp!, {r4-r12, lr} add r0, r0, r1ldmfd sp!, {r4-r12, pc} end