College of Computer Science & Technology 第三章 ARM9汇编编程 College of Computer Science & Technology
第三章 ARM9汇编编程 ARM汇编程序结构 ARM指令寻址方式 ARM9指令集 ARM汇编语言伪操作与伪指令 鲁东大学 LUDONG UNIVERSITY ARM汇编程序结构 ARM指令寻址方式 ARM9指令集 ARM汇编语言伪操作与伪指令
汇编语言优点 直接操作底层硬件,有利于底层控制 代码效率高 汇编语言缺点 与硬件联系紧密,移植性差 非结构化,代码不易理解,可维护性差 鲁东大学 LUDONG UNIVERSITY 汇编语言优点 直接操作底层硬件,有利于底层控制 代码效率高 汇编语言缺点 与硬件联系紧密,移植性差 非结构化,代码不易理解,可维护性差 改善 高级语言
应用程序 实时操作系统RTOS Kernel BSP板极支持包/HAL硬件抽象层 鲁东大学 LUDONG UNIVERSITY 应用程序 C,C++,Java API 用户图形接口 文件系统 TCP/IP协议 高级语言C 实时操作系统RTOS Kernel BSP板极支持包/HAL硬件抽象层 汇编语言 硬件
第三章 ARM9汇编编程 ARM汇编程序结构 ARM指令寻址方式 ARM9指令集 ARM汇编语言伪操作与伪指令 鲁东大学 LUDONG UNIVERSITY ARM汇编程序结构 ARM指令寻址方式 ARM9指令集 ARM汇编语言伪操作与伪指令 ARM汇编语言与C语言混编程序
ARM汇编语言与C/C++语言混合编程 C语言程序内嵌汇编语句 C语言中调用汇编函数 汇编语言中调用C函数 鲁东大学 LUDONG UNIVERSITY C语言程序内嵌汇编语句 C语言中调用汇编函数 汇编语言中调用C函数
内嵌式汇编语句 函数-实现结果为64位的乘法 C语言函数 内嵌汇编函数 long long smull(int x, int y) { 鲁东大学 LUDONG UNIVERSITY 函数-实现结果为64位的乘法 long long smull(int x, int y) { return (long long) x * y; } C语言函数 内嵌汇编函数 long long smull(int x, int y) { long long res; __asm { SMULL ((int*)&res)[0], ((int*)&res)[1], x, y } return res; }
内嵌汇编(Inline-assembler) I.C语言程序中内嵌汇编指令 鲁东大学 LUDONG UNIVERSITY 内嵌汇编(Inline-assembler) 通过嵌入汇编语句,实现高级语言相同的功能 可以优化编程,提高编程效率。 ①怎样嵌入汇编语句 汇编语言 高级语言C 内嵌汇编 内嵌汇编 汇编语言 高级语言C 内嵌汇编: C/C++编译器编译 汇编:汇编器直接汇编 突出的不同: 1)汇编语言-大量通过直接通过寄存器名使用寄存器,内嵌汇编- 使用C定义的变量,由编译器分配寄存器,不直接指定物理寄存器号 2)汇编伪指令不好用了,因为不是使用汇编器汇编 3)SWI/BL,需要保存现场,恢复现场,比较麻烦,需要查资料准确确定调用格式 ②内嵌汇编与汇编不同 硬核
1.怎样在C中内嵌汇编语句(1) 方法一 内嵌语句形式——C++编译器支持形式 鲁东大学 LUDONG UNIVERSITY 方法一 内嵌语句形式——C++编译器支持形式 asm(“instruction[;instrunction]”); 分隔多条语句 long long smull(int x, int y) { long long res; asm ( “SMULL ((int*)&res)[0], ((int*)&res)[1], x, y” ); return res; } C++编译器要求源文件后缀为*.cpp 分号用于分隔语句,故不能加注释
怎样在C中内嵌汇编语句(2) 方法二 内嵌程序段形式-C编译器支持 __asm{ instruction [;instruction] … 鲁东大学 LUDONG UNIVERSITY 常用 方法二 内嵌程序段形式-C编译器支持 __asm{ instruction [;instruction] … instruction } C语法习惯 两条下划线 long long smull(int x, int y) { long long res; __asm { SMULL ((int*)&res)[0], ((int*)&res)[1], x, y } return res; }
示例-内嵌汇编实现strcopy函数 void my_strcpy(const char *src, char *dst) { 鲁东大学 LUDONG UNIVERSITY void my_strcpy(const char *src, char *dst) { int ch; __asm loop: LDRB ch, [src], #1 STRB ch, [dst], #1 CMP ch, #0 BNE loop } 内嵌汇编标号与C相同 ARMASM语句 STRB r2,[r1],#1
2.内嵌汇编与汇编语言之间的差异 鲁东大学 LUDONG UNIVERSITY 内嵌汇编语句中操作数尽量不要使用物理寄存器,应使用C常量/局部变量,变量在编译时由编译器分配寄存器,所以相当于操作寄存器; 以免造成冲突 __asm { MOV r0, x ADD y, r0, x / y } X=10 Y=2 Y最后应该=? 编译器在运算表达式时,使用了r0
使用物理寄存器务必谨慎 因为: 计算C表达式的值,将使用R0~R3作为临时寄存器 鲁东大学 LUDONG UNIVERSITY 使用物理寄存器务必谨慎 因为: 计算C表达式的值,将使用R0~R3作为临时寄存器 过程调用,将利用R0~R3传递参数 (APCS规则),使用R12(ip)作为临时寄存器,修改R14(lr),存放返回地址 以上操作都有可能更改CPSR 并且不允许直接操作PC(达到转移的效果)
既然参数由r0~r3传递,所以直接对r0~r3操 作,认为是对实参进行操作。 鲁东大学 LUDONG UNIVERSITY 误区 既然参数由r0~r3传递,所以直接对r0~r3操 作,认为是对实参进行操作。 int bad_f(int x) { __asm ADD r0, r0, #1 } return x; } 传参使用r0,r0=x 编译器认为此处使用的r0并不是实参x 改为:ADD x,x,#1 调用后,X=?
内嵌汇编另一作用-直接控制底层硬件 典型应用-使用内嵌汇编开/关中断 inline void enable_IRQ(void) ;开中断函数 鲁东大学 LUDONG UNIVERSITY 典型应用-使用内嵌汇编开/关中断 inline void enable_IRQ(void) { int tmp; __asm MRS tmp, CPSR BIC tmp, tmp, #0x80 MSR CPSR_c, tmp } ;开中断函数 ;CPSR-I位清零,开中断
__inline void disable_IRQ(void) { int tmp; __asm MRS tmp, CPSR 鲁东大学 LUDONG UNIVERSITY __inline void disable_IRQ(void) { int tmp; __asm MRS tmp, CPSR ORR tmp, tmp, #0x80 MSR CPSR_c, tmp } ;关中断函数 ;CPSR-I位置位,关中断
② ① II . C语言程序中调用汇编函数 C源文件 调用 ASM源文件 调用汇编函数strcpy 内嵌汇编指令到C语言源文件 鲁东大学 LUDONG UNIVERSITY C源文件 调用汇编函数strcpy 内嵌汇编指令到C语言源文件 调用 ② C源文件内调用C函数strcpy strcpy内嵌汇编实现拷贝 ASM源文件 内嵌汇编指令与ARM汇编相比: 发生了很多更改 有了很多限制 效率比ARMASM差 汇编函数strcpy ①
汇编函数的编写 标号 -函数名,函数的入口 MOV pc,lr -从函数返回 strcpy strcpy(){ } 鲁东大学 LUDONG UNIVERSITY 汇编函数的编写 标号 -函数名,函数的入口 MOV pc,lr -从函数返回 strcpy LDRB r2, [r1],#1 ; 取出一个字符,修改地址 STRB r2, [r0],#1 ; 向字符串2存入该字符,修改地址 CMP r2, #0 ; 测试字符是不是\0 BNE strcopy ; 如果不是,继续传送 MOV pc,lr ;返回 strcpy(){ }
死循环! ? start LDR r1,=str2 LDR r2,=str1 BL strcpy 运行结果为: 返回BL下一条 strcpy 鲁东大学 LUDONG UNIVERSITY start LDR r1,=str2 LDR r2,=str1 BL strcpy 运行结果为: 死循环! ? 返回BL下一条 strcpy LDRB r2, [r1],#1 STRB r2, [r0],#1 CMP r2, #0 BNE strcopy MOV pc,lr ;返回 汇编函数应写在主程序之后,以免造成不应该的调用。 stop MOV r0,0x18 LDR r1,=0x20026 SWI 0x123456 strcpy LDRB r2, [r1],#1 STRB r2, [r0],#1 CMP r2, #0 BNE strcopy MOV pc,lr ;返回 stop MOV r0,0x18 LDR r1,=0x20026 SWI 0x123456
必须在汇编中用export声明将函数导出 而在C程序中使用extern声明函数原形 II . C语言程序中调用汇编函数 鲁东大学 LUDONG UNIVERSITY 调用问题1: 汇编函数和C程序位于不同的源文件中 要进行函数调用 必须在汇编中用export声明将函数导出 而在C程序中使用extern声明函数原形 AREA SCopy, CODE EXPORT strcopy strcopy …. MOV pc,lr END #include <stdio.h> extern void strcopy(char *d, char *s); int main(){ … }
C调用函数使用的实参,根据APCS规则,编译器将按照顺序通过R0~R3寄存器传递给汇编函数。 鲁东大学 LUDONG UNIVERSITY 调用问题2: 参数传递 C调用函数使用的实参,根据APCS规则,编译器将按照顺序通过R0~R3寄存器传递给汇编函数。 汇编函数 C调用 func func(arg1,arg2,arg3,arg4) r0 r1 r2 r3
#include <stdio.h> extern void strcopy(char *d, char *s); 鲁东大学 LUDONG UNIVERSITY #include <stdio.h> extern void strcopy(char *d, char *s); int main() { char srcstr[] = "First string - source "; char dststr[] = "Second -destination "; strcopy(dststr,srcstr); } AREA SCopy, CODE EXPORT strcopy strcopy LDRB r2, [r1],#1 STRB r2, [r0],#1 CMP r2, #0 BNE strcopy MOV pc,lr END
第二种参数传递方法 使用C全局变量进行参数传递 通过内存传递参数,速度慢 汇编函数 C程序 鲁东大学 LUDONG UNIVERSITY 第二种参数传递方法 使用C全局变量进行参数传递 通过内存传递参数,速度慢 汇编函数 C程序 import globalvar 定义全局变量globalvar func extern func(void) ldr r0,=globalvar int main() ldr r1,[r0] { … func() } ;声明无形参 ;调用无实参 R1为globalvar的值
III.汇编程序中调用C函数 #include <stdio.h> 鲁东大学 LUDONG UNIVERSITY #include <stdio.h> char srcstr[] = "First string - source "; char dststr[] = "Second -destination "; extern void strcopy(void); int main() { strcopy(); } char型8位 int型16位 AREA SCopy, CODE EXPORT strcopy IMPORT srcstr IMPORT dststr strcopy LDR r0,=dststr LDR r1,=srcstr LDRB r2, [r1],#1 STRB r2, [r0],#1 CMP r2, #0 BNE strcopy MOV pc,lr END
III.汇编语言中调用C函数 系统启动过程: 系统启动->0x00000000地址 0x00000000单元 B reset 鲁东大学 LUDONG UNIVERSITY 系统启动过程: 系统启动->0x00000000地址 0x00000000单元 B reset 复位异常处理程序为汇编语言程序对系统部分初始化 将控制权交给C语言编写的启动程序,继续对包括RAM,Cache在内的系统器件进行初始化
III.汇编语言中调用C函数 调用方法: IMPORT函数名,BL函数名 C函数 汇编程序 IMPORT 函数名 … 鲁东大学 LUDONG UNIVERSITY 调用方法: IMPORT函数名,BL函数名 C函数 汇编程序 IMPORT 函数名 … r0 r1 r2 r3 BL 函数名 func(arg1,arg2,arg3,arg4) 传参 调用
int sum(int a, int b, int c) { return a + b + c; } 鲁东大学 LUDONG UNIVERSITY AREA f, CODE, READONLY IMPORT sum ENTRY start MOV r1,#1 MOV r2,#2 MOV r3,#3 BL sum END int sum(int a, int b, int c) { return a + b + c; }