2025年嵌入式微处理器1-3章汇编知识总结

嵌入式微处理器1-3章汇编知识总结首先我们了解一些基础知识 char 类型的大小 在 32 位 RAM 处理器的 C 语言中 char 类型变量占一个字节 int 类型的大小 在 32 位 RAM 处理器的 C 语言中 int 代表 4 个字节 32 位 异或 如果 a b 两个值不相同 则异或结果为 1 如果 a

大家好,我是讯享网,很高兴认识大家。

首先我们了解一些基础知识

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); ……. } 
小讯
上一篇 2025-03-22 08:45
下一篇 2025-03-26 13:14

相关推荐

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