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

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

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

CPU上的通用寄存器:
eax, ebx, ecx, edx, esi, edi, ebp, esp等都是X86 汇编语言中CPU上的通用寄存器的名称,是32位的寄存器。如果用C语言来解释,可以把这些寄存器当作变量看待。
介绍些常用的通用寄存器名称:
EAX 是"累加器"(accumulator), 它是很多加法乘法指令的缺省寄存器。
EBX 是"基地址"(base)寄存器, 在内存寻址时存放基地址。
ECX 是计数器(counter), 是重复(REP)前缀指令和LOOP指令的内定计数器。
EDX 则总是被用来放整数除法产生的余数。

汇编中push/pop作用:
push 寄存器 ; 将寄存器的数据压入堆栈。
pop 寄存器 ; 出栈,恢复寄存器数据。
调用子程序前为了保存寄存器的数据不受到影响,返回时恢复原来的数据。
如果不用把寄存器里的数据临时保存一下,则可以省去上述操作。

LDR加载指令

格式为:LDR{条件}  目的寄存器,<存储器地址>

LDR指令用于从存储器中将一个32位的字数据传送到目的寄存器中。
寻址方式灵活多样,存储器地址可通过偏移量加减,移位,等运算。

STR传送指令

格式为:STR{条件}  源寄存器,<存储器地址>

STR指令用亍从源寄存器中将一个32位的字数据传送到存储器中。
寻址方式也灵活多样,存储器地址可通过偏移量加减,移位,等运算。

前序寻址:先对基址寄存器偏移,再进行数据操作。(地址变化相当于 ++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个字节。
;  Receives : ESI = 数组起始地址
;  ECX = 数组长度
;  Returns : EAX = 求和的结果
 AERA  ArraySum, CODE, READONLY  ; 首先,我们定义了一个函数 ArraySum。
            	ENTRY
  start   	 push esi      ; 然后,我们为了保存原先的esi和ecx的值,将其push进了堆栈中。
         	 push ecx
        	 mov eax,0     ; 将数组的和一直保存在eax寄存器中,所以用该语句将EAX寄存器初始化。
L1: 增加了一个L1的标号,用于循环,接着我们就开始了循环。
 			TEQ eas,#1  ;奇数判断,通过异或运算判断最后一位是否为1即可(TEQ eas,#0 ;偶数判断)
  		  	ADDEQ eax,eax,[esi] ; 对符合条件的元素进行求和。
         	ADD esi,esi,4 ; 然后将esi这个地址增加4(因为我们这里计算的是32位整数的和,32位整数,需要4个byte)
        	loop L1          ; 重复这个过程,ECX寄存器保留了数组中元素的个数。ECX寄存器保留循环的个数,并且在循环的时候每执行一次LOOP,会自减1,直至变为0循环结束。
        	pop ecx         ; 恢复ECX和ESI寄存器原先的数据,在堆栈中弹出ecx和esi。
        	pop esi
        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
        STR R3,R0;因为R0会作为函数返回值,恢复初始的char* strDest地址
        MOV PC,LR
        END

调用汇编函数

      extern char *strcat(char *dest, const char *src);
 int main(void)
 {
     
     …….
     strcat(dest, src);
     …….
 }

猜你喜欢

转载自blog.csdn.net/u010373790/article/details/83189171
今日推荐