arm第十一天(汇编与C混调、异常处理)
来源:互联网 发布:剑三脸型非法数据 编辑:程序博客网 时间:2024/06/14 04:01
汇编程序与C程序混合调用
- 在C语言中如何调用汇编语言实现的函数
- 在C语言中如何使用汇编语言定义的变量
- 汇编语言中如何调用C语言的函数
汇编语言中如何调用C语言定义的变量
在C语言中如何调用汇编语言实现的函数
例如用汇编比较两个字符串是否相等的函数的代码片段:
.text .code32 .global my_strcmpmy_strcmp: ldrb r2,[r1],#1 //"ledon" 首地址 ldrb r3,[r0],#1 //buf从键盘输入的命令字符 cmp r2,#0 beq cmp_end ..... cmp_end: sub r0,r2,r3 bx lr
C语言调用函数的过程的代码片段:
main.c
//要在C代码中得到声明适合于C函数原型extern void my_strcmp(char *d,const char*s);int main(void){ char buf[256]; uart0_gets(buf);//获取键盘输入的命令 my_strcmp(buf,"ledon");//汇编实现的函数 //传参数默认传递 r0,r1,r2,r3,... 这里有两个参数,因此为r0,r1 //汇编使用寄存器的时候,如果要混调,要按顺序使用}
遵循的原则:
- 汇编函数的名字声明为全局标号 “.global my_strcmp”
- C程序中如要调用这个汇编函数,需要声明该函数的函数原型
extern void my_strcmp(char *d,const char*s);
- 按照C语言的方式去调用该函数
C语言中如何使用汇编语言定义的变量
.data .global yy yy: .word 0x100 //定义了一个整形变量,变量名称为yy
1,在汇编中将变量声明为全局变量
2,在C语言中声明该变量为外部变量
extern int yy;
3,按照C的方式去使用该变量
汇编语言中如何调用C语言的函数
int add(int a,int b,int c,int d){ return (a+b+c+d);}
1,在C程序中该函数要定义为全局,即函数前面不能加static
2,汇编程序中将该函数声明为外部标号
.extern add //伪操作,意味着该函数在C中实现
3,按照汇编的方式调用
//准备参数,参数不能随便放,要按照顺序mov r0,#0 mov r1,#1mov r2,#2mov r3,#3//调用bl addcmp r0,#0 //C函数的时候,将返回值放在了r0
关键是:参数的传递规则
int add(int a,int b,int c,int d)
r0, r1 r2 r3
汇编语言中如何调用C语言定义的变量
int a ;
1,C中声明为全局变量
2,汇编程序中声明该变量为外部变量
.extern a;
3,按照汇编的方式使用
ldr r0,=a //a的地址ldr r1,[r0]
总结:
被调用方循环的原则:
将被调用的函数或变量都要定义为全局
调用方:
声明被调用函数的函数原型或者变量为外部标号
参数传递:
r0,r1,r2,r3
r0作为返回值
案例:
在C程序中调用汇编实现的函数
将用汇编实现的字符串比较函数替换掉用C实现的字符串比较函数
1,汇编函数(字符串比较函数)定义为全局标号
2,在C程序中将该汇编函数声明函数原型
3,替换掉C的字符吕比较函数,用汇编函数
astrcmp.s
.text .code 32 .global a_strmcmpa_strmcmp: @不用获取地址,因为C函数调用时,会通过r0,r1将比较的字符串的地址传递过来 @r0 str1 对应键盘输入的命令 @r1 str2 定义好的命令的名字 @r2 r0,r3 r1 @比较 @返回,通过r0返回;通过r0保存比较的结果 @ 当r0为0,相同 @ 当r0非0,不同 @bx lr 返回 cmp_loop://循环比较 ldrb r2,[r0],#1 ldrb r3,[r1],#1 cmp r2,#0 beq cmp_end cmp r2,r3 beq cmp_loop cmp_end: @返回 sub r0,r2,r3 bx lr .end
.h声明函数原型
//a_strmcmp是汇编实现的字符串比较函数 //返回值为0表示比较成功,非0比较失败 extern int a_strmcmp(const char *str1,const char *str2);
修改makefile
在C中调用
start.s
.text .code 32 .gloal start @调用C实现的main .extern main .extern __bss_start @ r0 bss的起始地址 .extern __endstart: stmfd sp!,{lr} @lr入栈 ldr r0,=__bss_start ldr r1,__end mov r2,#0clear_bss: @清除bss段 str,r2,[r0],#4 @字的存储指令,清完一个字,+4表示字对齐 cmp r0,r1 @循环清0 bcc clear_bss bl main @跳转到C语言中的main中执行 ldmfd sp!,{pc} @出栈 .end
异常处理
1,复位异常,进入管理SVC模式
2,未定义指令异常,不能识别指令,进入未定义模式
3,软中断异常,指行swi指令,进入SVC模式
4,预取指令异常,没有取到指定的指令,进入中止模式
5,数据中止异常,没有取到指定的数据,进入中止模式
6,中断,进入中断模式
7,快速中断,进入快速中断模式
工作模式:
异常模式
管理
快速中断
中断
中止
非异常模式
当发生异常时,如保处理?
CPU做:
1,拷贝CPSR到相应异常模式的CPSR,SPSR_mode = CPSR (备份)
2,设置适当的CPSR的位:
1. 将处理器的状态改为ARM状态,CPSR的bit[5] = 0
2. 改变处理器的工作模式,进入到对应的异常工作模式,改CPSR的bit[4:0]到对应的异常模式
3. 设置中断禁止位,
3,保存返回地址到LR_mode = PC -4(PC -2),异常返回的问题
4,设置PC为相应异常处理程序的入口(异常向量表)
5,处理异常,执行异常处理
6,异常返回,CPSR = SPSR_mode (MOVS PC ,LR)
异常向量表:
软中断
系统执行代码,执行到SWI 0x01指令,在该指令的执行阶段,发生软件中断异常
CPU:
1,备份CSPR,SPSR_SVC = CPSR
2,修改CPSR
1.改状态,ARM状态,CPSR的bit[i]=0
2,改模式,SVC管理模式,CPSR的bit[4:0] = 10011
3. 改中断禁止位
3,保存返加地趣为LR_SVC
4,修改PC为异常向量表中对应的入口地址,PC = 0x8
对应指令:ldr pc,swi_hdl
再次修改PC = swi_hdl函数地址
5,swi_hdl,软中断异常处理程序 ,在此程序中调用C语言缩写的较为复杂的处理程序 (汇编调用C函数的混合调用)
6,当C函数处理异常完毕之后,返回汇编swi_hdl,再做最后的异常返回.
7,movs pc,ls CPSR = SPSR_SVC
8,接下来继续执行swi指令的下一条指令
.text .code 32 .global vector_start .extern resetvector_start: @异常向量表 b reset ldr pc,_und_hdl ldr pc,_swi_hdl ldr pc,_pabt_hdl ldr pc,dabt_hdl b . ldr pc,irq_hdl ldr pc,fiq_hdlund_hdl: .word _und_handler_swi_hdl: .word _swi_handler..._swi_handler: stmfd sp!,{r0-r12,lr} @r0到r12入栈 bl c_swi_handler @软中断处理函数,C函数 ldmfd sp!,{r0-r12,pc}^ @出栈 .global swi_test1 swi_test1: stmfd sp!,{lr} stmfd sp!,{pc}
reset.s
.text .global vector_start .extern resetreset: msr cpsr_c,#0xd3 ldr sp,0xd0036000 .....
reset.s
1,将模式改为SVC管理模式,并且屏蔽中断,初始化栈顶指针SP
2,安装MMU的地址转换表,之后CPU给的地址都是虚拟地址
3,初始化IRQ和FIQ模式下栈顶指针
4,清空BSS段
5,跳转到main执行主函数(shell,汇编调用C的混合调用)
提取swi指令中中断号:
swi指令格式:
1,在ARM状态下,执行ARM指令,SWI指令,低24bit为中断号
2,在thumb状态下,执行thumb指令,swi指令,低8bit为中断号
ARM指令格式(32bit):
Thumb指令格式:
1,确定执行swi指令时,CPU所片的状态,ARM? thumb?
由于发生异常时,SPSR_SVC = CPSR
判断SPSR的bit[5] = 0,ARM状态,swi指令是指令(32)
bit[5] = 1,thumb状态,swi指令是thumb指令(16)
1,读SPSR寄存器到R0,MRS指令
2,用位运算bit[5] ANDS EQ(ARM) NE(thumb)
2,获取swi指令的编码
由于发生异常时,保存返回地址 lr = pc -4 ARM
= pc - 2 thumb
ARM 状态: swi指令码的地址,lr - 4
Thumb状态,swi指令码的地址,lr-2
ldreq 加载ARM指令 r0,[lr-4] ldrneh 加载thumb指令 r0,[lr - 2]
3,使用位运算获取到swi指令码中中断号,将中断号存在R0
ARM指令:提取低24bit
Thumb:提取低8bit
通过位运算,中断号保存在r0
1,biceq r0 24bit , 清除24bit
2,andne r0 8bit,
4,R0中断号做为参数,传递给C函数
5,进入c_swi_handler(unsigned int num),伪代码如下:
c_swi_handler(unsigned int num){ switch(num){ case 1: ... break; case 2: .... break; ... } }
取指,解码,执行,在swit指令的第三个阶段,执行阶段,发生异常
1,SPSR= CPSR
2,改CSPR ,ARM状态,SVC模式,中断禁止位
3,保存返回地址 LR= PC -4 add指令地址
= PC -2
- arm第十一天(汇编与C混调、异常处理)
- 汇编 C混调 异常处理
- C与ARM汇编之一
- arm第十天(汇编指令下)
- 嵌入式Linux ARM汇编(二)——ARM异常处理
- 嵌入式Linux ARM汇编(二)——ARM异常处理
- Arm汇编-第一天
- 嵌入式Linux ARM汇编(七)——C语言与ARM汇编混合编程
- 嵌入式Linux ARM汇编(七)——C语言与ARM汇编混合编程
- ARM上的异常处理和简单汇编
- ARM汇编与C语言对照
- ARM汇编与C混合编程
- tiny6410裸机实验第1章--------------ARM汇编和编程基础(C与ARM汇编混合编程)
- ARM指令集与异常处理
- C第十一天
- c/c++第十一天
- java基础第十一天 异常
- arm 汇编调用c函数与c函数调用arm汇编
- 【设计模式 - 5】之适配器模式(Adapter)
- [shell]采用shc工具加密Shell脚本
- 【设计模式 - 6】之桥接模式(Bridge)
- 一幅图看懂Python编程
- 【设计模式 - 7】之过滤器模式(Filter)
- arm第十一天(汇编与C混调、异常处理)
- 【设计模式 - 8】之组合模式(Composite)
- permutation and its variations
- 项目范围定义与创建工作结构分解
- 10013---使用VMware搭建3台一模一样的Linux虚拟机
- js的setInterval()每隔指定的时间就执行对应的函数
- 几个电影网站
- Reservoir sampling
- [李景山php]每天TP5-20170113|thinkphp5-Model.php-6