汇编
伪操作
GNU汇编中常用的伪操作:1>
1> .text KEIL中Text Start设置项关联,用以说明其下内容属于程序的代码,这些指令在内存中从Text Start设置项指定地t开始存放
2> .end当前源码文件内容结束
3> .global全局用于说明其后标号可以跨源文件使用用法:.global标号
.local局部用于说明其后标号不可以跨源文件使用,只能在当前源文件中使用用法:.local 标号
4>.equ //宏定义,相当于#defind
5>.text / .data / .bss(静态内存分配)
.text、.data和.bss将汇编系统预定义的段名编译到相应的代码段、数据段和bss段。
KEIL中Data Start设置项关联,用以说明其下内容属于程序的数据段,数据段在内存中从Data Start设置项指定地址开始存放程运行过程中用到的数据
裸机程序的数据段=进程的栈区+堆区+数据区
—些简单的裸机程序,无需对数据段进行细分(分为栈区、堆区、数据区)
复杂的裸机程序,对数据段的细分,由程序员自行实现:
1>栈区:指定栈底地址和栈区大小
2>数据区:采用相应伪操作在其中为相应数据准备空间
3>堆区:对除去栈区、数据区以外剩余空间采用相应的数据结构进行管理,管理代码以及动态分配和释放函数有程序员自行实现
6>用于在代码段(程序运行过程中只读)和数据段为指定数据分配空间的伪操作
.byte
用法1:byte 1个字节的值----分配1个字节并向该字节填上相应的值
例:DATA1: .byte 0xab类似于C语言中语句:char DATA1 = 0xab
用法2: byte 1个字节的值1,1个字节的值.n…个字节的值n ----分配n个字节,并在相应字节位置填上相应的数值
例:DATA2: .byte 0x12,0x34,0x56(同上)
.word
用法1: .word 4个字节的值---分面可以存放一个字(四个字节)的空间
用法2:.word 4个字节的值1,4个字节的值2.…4个字节的值n ----连续分配n个字的空间
.string
"字符串常量’---分配一块内存空间用于存放指定的字符串内容总计分配: strlen(字符串)+ 1个字节的空间
.space 用法:.space 字节数常量N值------分配N个字节的空间,并将该空间中的所有字节都填上指定的值
-----------也可以用标号对用这些伪操作分配好的空间命名,实际标号就是对应空间的首地址
伪指令 LDR STR
ARM这些RISC-CPJ不是所有指令都能访问内存的,访问内存需要用专门的指令进行,这些指令通称为访存指令:
1.从内存中读数据到寄存器------------ ARM以LD开头Load加载,比如:LDR LDM
2将寄存器中数据存储到指定内存------- ARM以ST开头 Store存储,比如:STR STM
------------涉及不索引,前索引,后索引(详情查阅资料)
LDR 加载
LDR R0,[R1] ;将存储器地址为R1的字数据读入寄存器R0。
LDR R0,[R1,R2] ;将存储器地址为R1+R2的字数据读入寄存器R0。
LDR R0,[R1,#8] ;将存储器地址为R1+8的字数据读入寄存器R0。
LDR R0,[R1,R2] ! ;将存储器地址为R1+R2的字数据读入寄存器R0,并将新地址R1+R2写入R1。
LDR R0,[R1,#8] ! ;将存储器地址为R1+8的字数据读入寄存器R0,并将新地址R1+8写入R1
LDR R0,[R1],R2 ;将存储器地址为R1的字数据读入寄存器R0,并将新地址R1+R2写入R1。
LDR R0,[R1,R2,LSL#2]! ;将存储器地址为R1+R2×4的字数据读入寄存器R0,并将新地址R1+R2×4写入R1。
LDR R0,[R1],R2,LSL#2 ;将存储器地址为R1的字数据读入寄存器R0,并将新地址R1+R2×4写入R1。
LDRB
LDRB R0,[R1] ;将存储器地址为R1的字节数据读入寄存器R0,并将R0的高24位清零。
LDRB R0,[R1,#8] ;将存储器地址为R1+8的字节数据读入寄存器R0,并将R0的高24位清零。
LDRH
并将R0的高16位清零。
STR、STRB、STRH 存储
STR R0,[R1],#8 ;将R0中的字数据写入以R1为地址的存储器中,并将新地址R1+8写入R1。
STRB R0,[R1] ;将寄存器R0中的字节数据写入以R1为地址的存储器中。//不是R1寄存器里
STRH R0,[R1] ;将寄存器R0中的半字数据写入以R1为地址的存储器中。
例1:LDR R0,=0x11223344
MOV R1,#0x40000000
STR R0,[R1]
LDRB R2,[R1]
例2:LDR R0,=V1 @取V1的地址
LDR R1, [R0],#4 @取R0地址了的数据(有点想数组的[])。
数据传输指令:
MOV:
MOV 条件码S标记 目标寄存器, 操作数
功能:将操作数写法表示的值传输给目标寄存器目标寄存器=操作数
例:MOV R1,#1 //把1赋值R1寄存器
MOV R1,R2 //把R2的值赋给R1
MVN:
MVN 条件码S标记 目标寄存器,操作数
功能:将操作数写法表示的值取反后传输给目标寄存器目标寄存器= ~(操作数)
移位码
LSL,LSR,ASR,ROR,RRX
1. LSL:逻辑左移去掉高位低位补零
2.LSR: 逻辑右移去掉低位高位补零
3.ASR: 算术右移去掉低位高位补符号位
4.ROR: 循环石移最低位补到最高位
5.RRX:带扩展的箭环右移连着CPSR的C位一起做循环右移每次只能移1位即用法
:某个寄存器名字,RRX
操作数写法:某个寄存器名字,移位码移位位数
移位位数支持两种写法:某个寄存器名,LSL或LSR或ASR或ROR #立即数
某个寄存器名,LSL或LSR或ASR或ROR另—个寄存器名
算术运算指令-----加减法
ADD:
ADD+条件码+S标记 目标寄存器,第一个操作数寄存器,第二个操作数
功能:目标寄存器=第一个操作数寄存器的当前值+第二个操作数的值
ADC:------带进位的加法指令 = ADDS
ADC+条件码+S标记目标寄存器,第一个操作数寄存器,第二个操作数
功能:目标寄存器=第一个操作数寄存器的当前值+第二个操作数的值+ CPSR的C位
SUB:
SUB+条件码+S标记目标寄存器,第一个操作数寄存器,第二个操作数
功能:目标寄存器=第一个操作数寄存器的当前值-第二个操作数的值
SBC:------带借位的减法指令
SBC+条件码+S标记目标寄存器,第一个操作数寄存器,第二个操作数
功能:目标寄存器=第一个操作数寄存器的当前值-第二个操作数的值- CPSR的C位的反
RSB: ------逆向减法
RSB+条件码+S标记目标寄存器,第一个操作数寄存器,第二个操作数
功能:目标寄存器=第二个操作数的值–第一个操作数寄存器的当前值
RSC: ------带借位逆向减法
RSC+条件码+S标记目标寄存器,第一个操作数寄存器,第二个操作数
功能:目标寄存器=第二个操作数的值–第一个操作数寄存器的当前值- CPSR的C位的反
位运算指令-----又称为逻辑运算指令
注意1:两个操作数的所有位依次做相应的运算注意 2:第一个操作数寄存器中的值并未改变
AND:--------按位与运算
AND+条件码+S标记目标寄存器,第一个操作数寄存器,第二个操作数
功能:目标寄存器=第一个操作数寄存器的当前值&第二个操作数的值
ORR:--------按位或运算
ORR+条件码+S标记目标寄存器,第一个操作数寄存器,第二个操作数
功能:目标寄存器=第一个操作数寄存器的当前值│第二个操作数的值
EOR:---------按位异或运算
EOR+条件码+S标记目标寄存器,第一个操作数寄存器,第二个操作数
功能:目标寄存器=第一个操作数寄存器的当前值^第二个操作数的值
BIC:------位清除指令
BIC+条件码+S标记目标寄存器,第一个操作数寄存器,第二个操作数
功能:第二个操作数的值中哪些位是1,就将第一个操作数寄存器当前值中的对应位置0,结果存放到目标寄存器中
相当于:目标寄存器=第一个操作数寄存器的当前值&(~第二个操作数的值)
数据处理类的比较指令:
特点:1)加S标记与不加S标记都会去修改CPSR的高4位 2)没有目标寄存器
CMP:---加
CMP+条件码第—个操作数寄存器第二操作数
第一个操作数寄存器的当前值-第二操作数的计算结果,不要差,只要记录减后的状态
CMN:---减 *******************************************************
CMN+条件码第一个操作数寄存器,第二操作数
第一个操作数寄存器的当前值+第二操作数的计算结果,不要和,只要记录加后的状态
TST:---按位与
TST+条件码第一个操作数寄存器,第二操作数
第一个操作数寄存器的当前值&第二操作数的计算结果,不要按位与的结果,只要记录按位与后的状态
TEQ:---按位异或
TEQ+条件码第一个操作数寄存器,第二操作数
第一个操作数寄存器的当前值^第二操作数的计算结果,不要按位异或的结构,只要记录按位异或后的状态
跳转指令(Branch分支)
B: --------程序中用于实现选择、码坏、goto
B:B+条件码标号
功能:跳转到标号指示代码位置,不做其它附带动作
BL:--------程序中用于实现函数调用
BL: Branch +Link BL+条件码标号
功能:跳转到标号指示代码位置,还要做一个附带动作:将下一条指令地址读到LR寄存器(R14)中
BX:-------程序中用于实现简单的函数返回
BX: Branch+X带状态转换BX+条件码目标寄存器
功能:跳转到目标寄存器中地址值指示的代码位置,并附带完或状态转换
状态转换的方式:
将目标位置的指令地址赋值给目标寄存器ADD目标寄存器,目标寄存器,1
BX目标寄存器-------ARM转换成Thumb状态
由于ARM指令在内存中按4字节对齐存放、Thumb指令在内存中按2字节对齐存放,因此任何一条指令所占内存的首地址一定是偶数(阅地址值最低位一定是O)O位实际没有什么作用。因此BX指令借助于0位作为状态转换位来用
BLX:旺带状态转换、又带髓接,还要进行跳转
BLX+条件码标号
保存PC到LR,跳转到指定位置,并切换为Thumb状态
BLX+条件码目标寄存器
保存PC到LR,跳转到指定位置,Rm的bits[0]为1切换为Thumb状态、bits[0]为0切换为ARM状态
例:MOV PC,LR 或者BX LR
真假条件跳转命令BNE BEQ MOVHI MOVLS
BNE:---判断是否为零(零标志位“Z”),为假执行
BEQ:---判断是否为零(零标志位“Z”),为真执行
例EBN loop
CMP R0,R1
SUBGT R0, R0, R1 如果R0大于R1,则执行R0=R0-R1
SUBLT R1,R1,R0 如果R0大于R1,则执行R1=R1-R0
MOVHI R3,R1 真
MOVLS R3,R2 假
汇编数组模板
/*给数组分配空间,并给数组命名以及给数组中的元素初始化*/Array:
.word 0x3,0x5,0x7,0×9,0xb,0x1
/为了方便计算数组中元素的个数,增加了此两行*/Array_end:
.word Ox00
/*分配一个字的空间,专门用于存放数组中元素的个数*/Length:
.word (Array_end -Array)/4
- 寄存器-LR-PC-SP-SPSR-PSR-CPSR
SP:堆栈指针R13
LR:连接寄存器R14
PC:程序计数器R15
PSR:程序状态寄存器
SPSR:程序状态保存寄存器
CPSR:程序状态寄存器(current program status register) (当前程序状态寄存器)
栈指令FD,ED,FA,EA,LDMF…,LDME…,STMDA…,STMDB…
栈操作伪指令:
STM+条件码+栈模式SP!,{寄存器列表}------批量入栈
LDM+条件码+栈模式SP!,{寄存器列表}------批量出栈
栈模式:
FD:满递减式顺序栈----出栈时等价于IA,入楼时等价于DB
LDMFD等价于LDMIA,STMFD等价于STMDB
ED:空递减式顺序栈----出栈时等价于IB,入栈时等价于DA
LDMED等价于LDMIB,STMED等价于STMDA
FA:满递增式顺序栈----出栈时等价于DA,入栈时等价于IB
LDMFA等价于LDMDA,STMFA等价于STMIB
EA:空递增式顺序栈-----出栈时等价于DB,入栈时等价于IA
LDMEA等价于LDMDB,STMEA等价于STMIA
例:STMFD(STMDB) SP!,{R4-R12,LR} //保护现场
LDMFD(LDMIA) SP!,{R4-R12,PC} //恢复现场
函数定义过程--- STMFD -- LDMFD
裸机程序调用
第一次函数调用前:指定栈底地址-----LDR SP,=栈底地址
STMFD SP!,{R4-R12,LR} //现场保护---保护调用本函数代码处的现场
LDMFD SP!,{R4-R12,PC} //恢复现场并返回到调用处
注:在“}”后加“^”,则LDM指令运行在异常模式,并且寄存器列表中含pc寄存器,^标记表示指令会做一个额外动作:将该异常工作模式专用的SPSR中的内容 还原到CPSR
工作模式切换—MRS—MSR
MRS -----将指定的PSR寄存器中内容读到一个通用寄存器中
用法:MRS 通用的目标寄存器,CPSR或SPSR_模式名称
MSR -----将指定的通用寄存器中的内容写到指定的PSR寄存器中
用法1: MSR CPSR或SPSR_模式名称,通用寄存器
用法2:MSR CPSR或SPSR_模式名称_后缀,通用寄存器----只将通用寄存器对应范围的那些位的值写到PSR寄存器中
c:只变更PSR寄存器的0~7位
×:只变更PSR寄存器的8~15位
s:只变更PSR寄存器的16~23位
f:只变更PSR寄存器的24~31位
例:手动切换工作模式的代码:
MRS R0,CPSR
BIC R0,#0x1F
ORR R0, R0 #目标模式对应的5位组合
MSR CPSR,R0或 MSR CPSR_c,R0
软中断指令—SWI
SWI---功能是产生指定编号的软中断异常
用法: SWI+条件码24位一个无符号整数值
操作系统内核实现系统调用时,需借助于SWI指令来完成,一个软中断编号对应这一个系统调用函数
例:SWI 0x11 @调用0x11号功能
SWI 0x01 @调用0x01号功能 //可参考上面的控制位的6-8位
七种异常模式—运行模式-SVC、UND、ABT、IRQ、FIQ
异常向量地址 | 异常名称 | 运行模式 | 模式位 | 优先级(6最低) | 可使用的寄存器 |
0x0 | 复位 | SVC | 0b10011 | 1 | PC,CPSR,R12-R0,R14_svc-R13_svc,SPSR_svc |
0x4 | 未定义指令 | UND | 0b11011 | 6 | PC,CPSR,R12-R0,R14_und-R13_und,SPSR_und |
0x8 | 软中断 | SVC | 0b10011 | 6 | PC,CPSR,R12-R0,R14_svc-R13_svc,SPSR_svc |
0xc | 指令预取中止 | ABT | 0b10111 | 5 | PC,CPSR,R12-R0,R14_abt-R13_abt,SPSR_abt |
0x10 | 数据访问中止 | ABT | 0b10111 | 2 | PC,CPSR,R12-R0,R14_abt-R13_abt,SPSR_abt |
0x14 | 保留 | 未使用 | 未使用 | 未使用 | 未使用 |
0x18 | 普通中断请求 | IRQ | 0b10010 | 4 | PC,CPSR,R12-R0,R14_irq-R13_irq,SPSR_irq |
0x1c | 快速中断请求 | FIQ | 0b10001 | 3 | PC,CPSR,R7-R0,R14_fiq-R8_fiq,SPSR_fiq |
中断处理过程
SWI地址 0Xxxxxxxx0 |
LR地址 0Xxxxxxxx4 |
PC地址0Xxxxxxxx8 |
LDR R0,[LR,#-4] @获取该SWI指令的地址
由上图可知;LR-4为SWI的地址,以此类推
STMFD SP!,{R0-R12,LR} @保存用到的寄存器
LDR R0,[LR,#-4] @获取该SWI指令的地址
BIC R0,R0,#0xFF000000 @得到SWI指令中的24位正整数
由此得:R0的值被赋值为SWI这行的机器码,如:EF000011
总结----综合代码可参考代码篇的中断部分
一、软中断的处理分为两级:
第一级完成如下动作:
1> 现场保护 STMFD 保护对象是SWI指令前的R0~R12,以及R14(LR)、
2> 获得SWI指令后的软中断编号
3> 调用第二级软中断处理函数
4> 第二级软中断处理函数返回后进行现场恢复
第二级软中断处理函数,可以采用汇编实现,也可以采用C语言实现
汇编实现:主体思路通过创建软中断向量表(一块连续内存空间,起始地址为SWIJumpTable,该空间连续存放了N个地址值,每个地址对应的空间就是与指定软中断编号对应的分软中断处理程序)
C语言实现:第一个参数传软中断编号,第二个参数传栈顶地址
二、汇编函数参数、返回值使用R0-R3
汇编调C函数参数、返回值也是使用R0-R3
向不同编号的软中断参数、以及获得处理结果也是使用R0-R3
三、其它的异常处理
IRQ、FIQ的处理也是分两级进行,第一类似于软中断的第一级,只是:
1> STMFD之前需要做LR-4
2> 中断号的获取(通过外设寄存器获取)于软中断号的获取方式不一样
UND、ABT异常处理产品中一般不考虑对它们的处理
代码
选择语句的实现
简单选择
MOV R0,#2
MOV R1,#1
CMP R0,R1
ADDHI R0,R0,#1
ADDLS R1,R1,#1
B .
判断奇偶数
MOV R0,#2
TST R0,#1
MOVEQ R1,#0
MOVNE R1,#1
B .
循环语句的实现
求1到100的和
MOV R0,#100
MOV R2,#0
loop:
ADD R2,R2,R0
SUBS R0,R0,#1
BNE loop
B .
函数调用的实现
例1
MOV R0,#3
MOV R1,#5
BL foo
B .
foo:
ADD R0,R0,R1
MOV PC,LR @BX LR
例2
MOV R0,#9
MOV R1,#15
loop:
CMP R0,R1
BEQ stop
SUBGT R0,R0,R1
SUBLT R1,R1,R0
B loop
stop:
B stop
.end
求最大公约数封装成函数
MOV R0,#6
MOV R1,#12
BL gcd
B .
gcd:
CMP R0,R1
BXEQ LR
SUBGT R0,R0,R1
SUBLT R1,R1,R0
B gcd
练习
猴子吃桃问题
有一只猴子摘了一堆桃子,当即吃了一半,又再多吃了一个.以后每天重复,到第10天发现只有1个桃子了,问最开始摘了多少个桃子
/*反推发*/ 1+1=2 2*2=4 为上一天的桃数
MOV R1,#9
MOV R0,#1
loop:
ADD R0,R0,#1
MOV R0,R0,LSL #1
SUBS R1,R1,#1
BNE loop
B .
求长方形周长
MOV R0,#3 @length
MOV R1,#4 @width
BL RECT_C
B .
RECT_C:
ADD R2,R0,R1
MOV R0,R2,LSL #1
BX LR
数组相加
.text
.global _start
_start:
LDR R0,=Array
LDR R2,=Length
LDR R1,[R2]
BL Get_Sum
LDR R2,=Sum
STR R0,[R2]
B .
/*
int Get_Sum(int *pi,int cnt)
{
int *p = NULL;
int sum = 0;
for(p=pi;p < pi+cnt;p++)
{
sum+=*p;
}
return sum;
}
*/
Get_Sum:
MOV R2,#0 @R2---->sum
loop:
LDR R3,[R0],#4
ADD R2,R2,R3
SUBS R1,R1,#1
BHI loop
MOV R0,R2
BX LR
.data @0x40000000
Array:
.word 0x3,0x5,0x7,0x9,0xb,0x1
Array_end:
.word 0x00
Length:
.word (Array_end - Array)/4
Sum:
.word 0x00
.end
伪指令练习
判断字节序
LDR R0,=0x11223344
MOV R1,#0x40000000
STR R0,[R1]
LDRB R2,[R1] @将存储器地址为R1的字节数据读入寄存器R2,并将R2的高24位清零。
B .
将内存中的两个数相加并保存到内存
LDR R0, =Value1 @把Value1的地址写入R0
LDR R1, [R0] @就像C语言,把地址交给一个指针变量,在用指针变量赋值
LDR R0, =Value2 @ADD R0, R0, #0x4
LDR R2, [R0]
ADD R1, R1, R2
LDR R0, =Result
STR R1, [R0]
B .
.data
Value1: .word 0x11111111
Value2: .word 0x22222222
Result: .word 0x0
找内存中两个32位数的最大数,并将最大数保存到新的内存块
LDR R0, =Value1
LDR R1, [R0],#4
LDR R2, [R0]
CMP R1,R2
MOVHI R3,R1
MOVLS R3,R2
LDR R0, =Result
STR R3, [R0]
B .
.data
Value1: .word 0x11111111
Value2: .word 0x22222222
Result: .word 0x0
将内存中的两个64位数相加,并将结果保存到新的内存块
LDR R6,=Value1
LDR R0,[R6],#4
LDR R1,[R6]
LDR R6,=Value2
LDR R2,[R6],#4
LDR R3,[R6]
ADDS R4,R0,R2
ADC R5,R1,R3
LDR R6,=Result
STR R4,[R6],#4
STR R5,[R6]
B .
.data
Value1: .word 0x12345678,0x12345678
.space 12,0x0
Value2: .word 0xF0000000,0x10000000
.space 8,0x0
Result: .word 0x0,0x0
块复制
.equ num,20
.text
.global _start
_start:
LDR R0,=src
LDR R1,=dst
MOV R2,#num
blockcopy: @以8个字为单位复制
MOVS R3,R2,LSR #3 @除以2的3次方,得到以8个字为单位复制的次数
BEQ copywords
octcopy:
LDMIA R0!,{R4-R11}
STMIA R1!,{R4-R11}
SUBS R3,R3,#1
BNE octcopy
copywords:@以单个字为单位复制
ANDS R2,R2,#7 @总字数对8取余,得到剩余要复制的字数
BEQ stop
wordcopy:
LDR R3,[R0],#4
STR R3,[R1],#4
SUBS R2,R2,#1
BNE wordcopy
stop:
B stop
.data
src:
.word 1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,1,2,3,4
dst:
.word 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.end
异常处理
切换工作模式
MRS R0,CPSR
BIC R0,R0,#0x1F
ORR R0,R0,#0x13
MSR CPSR,R0 @MSR CPSR_c,R0
无参单功能版:
.text
.global _start
_start:
Vector_Init_Block:
B Reset_Handler
B .
B SWI_Handler
B .
B .
NOP
B .
B .
Reset_Handler:
LDR SP,=0x40002000
@切换为用户模式
MRS R0,CPSR
BIC R0,R0,#0x1F
ORR R0,R0,#0x10
MSR CPSR,R0
SWI 0x11 @调用0x11号功能
B .
SWI_Handler:
STMFD SP!,{R0-R12,LR} @保存用到的寄存器
LDR R0,[LR,#-4] @获取该SWI指令的地址 //**
BIC R0,R0,#0xFF000000 @得到SWI指令中的24位正整数
CMP R0,#0x11
BNE SWI_END
LDR R1,=V1 //**
LDR R2,[R1],#4 //**
LDR R3,[R1],#4
ADD R0,R2,R3
SWI_END:
STR R0,[R1]
LDMFD SP!,{R0-R12,PC}^
.data
V1: .word 0x1
V2: .word 0x2
Ret: .word 0
.end
无参多功能版:
.equ MaxSWI,4
.text
.global _start
_start:
Vector_Init_Block:
B Reset_Handler @开机执行行
B .
B SWI_Handler
B .
B .
NOP
B .
B .
Reset_Handler:
LDR SP,=0x40002000
@切换为用户模式
MRS R0,CPSR
BIC R0,R0,#0x1F
ORR R0,R0,#0x10
MSR CPSR,R0
SWI 0x01 @调用0x01号功能
B .
SWI_Handler:
STMFD SP!,{R0-R12,LR} @保存用到的寄存器
LDR R0,[LR,#-4] @获取该SWI指令的地址(由SWI切换状态时,LR改变-4是上行)
BIC R0,R0,#0xFF000000 @得到SWI指令中的24位正整数
BL SWI_Handler2
SWI_END:
LDMFD SP!,{R0-R12,PC}^
/*第2级处理程序开始*/
SWI_Handler2:
CMP R0,#MaxSWI
LDRCC PC,[PC,R0,LSL #2] @跳转到相应位置 R0=01就是在PC的基础上下移1个字节,也就是执行.word SWINum0这句的函数,(类似switch语句)
B SWIOutOfRange @错误处理
SWIJumpTable: @设置多级跳转
.word SWINum0
.word SWINum1
.word SWINum2
.Word SWINum3
SWINum0:/*0号功能实现 --- 加*/
CMP R0,#0x0
BNE SWIOutOfRange
LDR R1,=V1
LDR R2,[R1],#4
LDR R3,[R1],#4
ADD R0,R2,R3
B EndOfSWI2
SWINum1:/*1号功能实现 --- 减*/
CMP R0,#0x1
BNE SWIOutOfRange
LDR R1,=V1
LDR R2,[R1],#4
LDR R3,[R1],#4
SUB R0,R2,R3
B EndOfSWI2
SWINum2:/*2号功能实现 --- 与*/
CMP R0,#0x2
BNE SWIOutOfRange
LDR R1,=V1
LDR R2,[R1],#4
LDR R3,[R1],#4
AND R0,R2,R3
B EndOfSWI2
SWINum3:/*3号功能实现 --- 或*/
CMP R0,#0x3
BNE SWIOutOfRange
LDR R1,=V1
LDR R2,[R1],#4
LDR R3,[R1],#4
ORR R0,R2,R3
B EndOfSWI2
EndOfSWI2:
STR R0,[R1]
SWIOutOfRange:
BX LR
/*第2级处理程序结束*/
.data
V1: .word 0x3
V2: .word 0x2
Ret: .word 0
.end
带参多功能C语言版
.text
.global _start
_start:
Vector_Init_Block:
B Reset_Handler
B .
B SWI_Handler
B .
B .
NOP
B .
B .
Reset_Handler:
LDR SP,=0x40002000
@切换为用户模式
MRS R0,CPSR
BIC R0,R0,#0x1F
ORR R0,R0,#0x10
MSR CPSR,R0
MOV R0,#1
MOV R1,#2
SWI 0x11 @调用0x11号功能
B .
/*SWI第1级处理程序开始*/
SWI_Handler:
STMFD SP!,{R0-R12,LR} @保存用到的寄存器
LDR R0,[LR,#-4] @获取该SWI指令的地址
BIC R0,R0,#0xFF000000 @得到SWI指令中的24位正整数
MOV R1,SP
BL C_SWI_Handler
SWI_END:
LDMFD SP!,{R0-R12,PC}^
/*SWI第1级处理程序结束*/
.end
void C_SWI_Handler(unsigned number,unsigned *pStack)
{
//功能额外参数的读取
value_in_reg_0 = pStack[0];
value_in_reg_1 = pStack[1];
value_in_reg_2 = pStack[2];
value_in_reg_3 = pStack[3];
/*各功能号实现*/
/*..........*/
/*各功能的返回结果*/
pStack[0] = updated_value0;
pStack[1] = updated_value1;
pStack[2] = updated_value2;
pStack[3] = updated_value3;
}
利用swi指令实现一个系统功能,该功能要求3个整数返回其中最大数,要求第二级swi处理用C语言实现
/*参考代码--汇编版*/
.text
.global _start
_start:
Vector_Init_Block:
B Reset_Handler
B .
B SWI_Handler
B .
B .
NOP
B .
B .
Reset_Handler:
LDR SP,=0x40002000
@切换为用户模式
MRS R0,CPSR
BIC R0,R0,#0x1F
ORR R0,R0,#0x10
MSR CPSR,R0
MOV R0,#11
MOV R1,#222
MOV R2,#33
SWI 0x11 @调用0x11号功能
B . @结果在R0中
/*SWI第1级处理程序开始*/
SWI_Handler:
STMFD SP!,{R0-R12,LR} @保存用到的寄存器
LDR R0,[LR,#-4] @获取该SWI指令的地址
BIC R0,R0,#0xFF000000 @得到SWI指令中的24位正整数
CMP R0,#0x11
BNE SWI_END
/*1. 从栈区读取系统功能所需参数*/
LDR R1,[SP]
LDR R2,[SP,#4]
LDR R3,[SP,#8]
/*2. 系统功能实现*/
CMP R1,R2
MOVLS R1,R2
CMP R1,R3
MOVLS R1,R3
/*3. 将系统功能产生的结果存放到栈顶位置(即swi指令前的R0入栈位置)*/
STR R1,[SP]
SWI_END:
LDMFD SP!,{R0-R12,PC}^
/*SWI第1级处理程序结束*/
.end