首先我们了解一些基础知识。
char类型的大小:在32位RAM处理器的C语言中,char类型变量占一个字节。
int类型的大小:在32位RAM处理器的C语言中,int代表4个字节(32位)。
异或:如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。
掩码:掩码是一串二进制代码对目标字段进行位与运算。
TEQ — 测试位: TST{条件} {P} <op1>, <op2>
TEQ不会修改操作数。对2个数,进行EOR。
符号:
汇编分号;的作用:分号后是注释,类似于c语言的//
汇编中括号[]的作用:一般说来,加中括号 [ ] 表示一种间接的取操作数方式,有点类似于C语言中的指针解引用的概念.,类似于c语言的*p
汇编语言中判断奇偶数怎么判断:
二进制的第1位为0,则是偶数;为1相反。
所以偶数的特点是换算成二进制的话最后一位必定是0(2的倍数),所以检测最后一位是否是0就能判断出是否是偶数,检测最后一位是否是1就能判断出是否是奇数。
标号: 在汇编语言中用来表示地址的符号就叫做标号。
子程序的调用与返回:
为进行识别,子程序的第1条指令之前必须赋予一个标号,以便其他程序可以用这个标号调用子程序。
在调用子程序的同时,也可以使用R0~R3 来进行参数的传递和从子程序返回运算结果。
在 ARM 汇编语言程序中,主程序一般通过 BL 指令来调用子程序。该指令在执行时完成如下操作:将子程序的返回地址存放在连接寄存器LR中,同时将程序计数器PC指向子程序的入口点。
子程序结尾一般通过指令MOV PC,LR 返回主程序。
外部可引用符号声明伪指令EXPORT
用伪指令EXPORT可以声明一个其他源文件可引用的符号,这种符号也叫做外部可引用符号。
EXPORT 符号
讯享网
引用外部符号声明伪指令IMPORT
当在一个源文件中需要使用另外一个源文件的外部可引用符号时,在被引用的符号前面必须使用伪指令 IMPORT 对其进行声明。
讯享网IMPORT 符号
段定义伪指令
格式:AREA <段名> {<属性>}{,<属性>}…
ENTRY伪指令用于指定汇编程序的入口点。
END伪指令用于通知编译器汇编工作到此结束,不再往下汇编了。
AREA 段名, CODE, 属性 ENTRY; ......(内容) END
LDR加载指令
讯享网格式为:LDR{条件} 目的寄存器,<存储器地址>
STR传送指令
格式为:STR{条件} 源寄存器,<存储器地址>
MOV指令和LDR/STR指令的区别:
ARM是RISC结构,数据从内存到CPU之间的移动只能通过L/S指令来完成,也就是ldr/str指令。
比如想把数据从内存中某处读取到寄存器中,只能使用ldr;把寄存器中的数据存放到内存的某处地址中,只能使用str。
而mov不能干这个活,mov只能在寄存器之间移动数据,或者把立即数移动到寄存器中。
前序寻址:先对基址寄存器偏移,再进行数据操作。(地址变化相当于 ++i)
格式:LDR/STR 寄存器1,[寄存器2,#立即数(偏移量)]
后序寻址:先进行数据操作,再对基址寄存器偏移。(地址变化相当于i++)
格式:LDR/STR 寄存器1,[寄存器2],#立即数(偏移量)
变量数据类型 对应的LDR/STR指令

汇编主函数格式:
讯享网 AREA 段名, CODE, READONLY ;只读的代码段 段名 ENTRY ;程序入口点 start ……. 代码段 ……. END ;段结束
汇编子函数格式:
AERA 段名, CODE, READONLY ENTRY 段名 ...... 代码段 ...... MOV PC,LR END
下面是博主对这两题的理解和答案,不保证100%的正确率。

好的,现在我们开始分析例题。
- 例题4
讯享网; 整数数组求和 一个数占4个字节。 ; R1 = 数组起始地址 ; R2= 数组长度 ; Returns : R0 = 求和的结果 AERA ArraySum, CODE, READONLY ; 首先,我们定义了一个函数 ArraySum。 ENTRY start MOV R0,#0 ; 将数组的和一直保存在R0寄存器中,所以用该语句将寄存器初始化。 L1 ; 增加了一个L1的标号,用于循环,接着我们就开始了循环。 TEQ [R1],#1 ;奇数判断,通过异或运算判断最后一位是否为1即可(TEQ eas,#0 ;偶数判断) ADDEQ R0,R0,[R1] ; 对符合条件的元素进行求和。 ADD R1,R1,4 ; 然后将R1这个地址增加4(因为我们这里计算的是32位整数的和,32位整数,需要4个byte) SUBS R2,R2,#1 BNE L1 ; 重复这个过程,R2寄存器保留了数组中元素的个数,并且在循环的时候每执行一次减1,直至变为0循环结束。 END
- 例题5
c函数原型:char *strcat(char *dest, const char *src);
汇编实现strcat函数(需要参考strcat函数原型)
Strcat函数原型:
char* strcat(char* strDest , const char* strSrc) { char* address=strDest; assert( (strDest!=NULL)&&(strSrc!=NULL) );//对源地址和目的地址加非0断言,即如果字符串为空,程序会终止运行。 while(*address)//是while(*strDest!=’\0’)的简化形式 { //若使用while(*strDest++),则会出错,因为循环结束后strDest还会执行一次++, //那么strDest将指向'\0'的下一个位置。/所以要在循环体内++;因为要使*strDest最后指 //向该字符串的结束标志’\0’。 address++; } while(*address++=*strSrc++); //此处可以加语句*strDest=’\0’;无必要,因为是字符串,系统会自动补\0。 return strDest;//将目的地址返回 }
ATPCS关于堆栈和寄存器的使用规则
ATPCS 标准规定,对于参数个数不多于 4 的函数,编译器必须按参数在列表中的顺序,自左向右 为它们分配寄存器 R0~R3。其中函数返回时,R0 还被用来存放函数的返回值。
汇编实现strcat函数
char* strcat(char* strDest , const char* strSrc)
r0对应形参char* strDest,r1对应形参 const char* strSrc
r0还是返回值char*
讯享网 AREA strcat,CODE,READONLY EXPORT strcat strcat LDR R3,R0;备份初始的char* strDest地址 L1 ; 相当于原型strcat函数中的第一个循环体,让R2寄存器指向第一个字符串的‘\0’。 LDRB R2,[R0],#1 ;后续寻址 CMP R2,#0 ;相当于取的内容和'\0'进行比较 BNE L1 L2 ; 相当于原型strcat函数中的第二个循环体。第二个字符串接在第一个字符串后面,直到遇到第二个字符串的'\0'结束循环。 LDRB R2,[R1],#1 STRB R2,[R0],#1 CMP R2,#0 BNE L2 MOV R0,R3;因为R0会作为函数返回值,恢复初始的char* strDest地址 MOV PC,LR END
调用汇编函数
extern char *strcat(char *dest, const char *src); int main(void) { ……. strcat(dest, src); ……. }

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/53722.html