ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

【嵌入式学习笔记】ARM汇编语言

【嵌入式学习笔记】ARM汇编语言 ARM汇编语言简介ARM汇编语言程序是由机器指令、伪指令和伪操作组成的。汇编语言程序的基本架构.data count: .byte 30 ; 声明数据段定义一个字节单元名字叫 count初值 30 .text ; 声明代码段 .balign 4 ; 4 字节对齐ARM 指令要求 .arm ; 声明下面用 32 位 ARM 指令不是 Thumb .global main ; 把 main 声明为全局符号让链接器能找到 main: LDRB R0, count ; 把 count 的地址加载到 R0LDRB 表示按字节加载 MOV R1, #10 ; R1 10立即数寻址 ADD R0, R0, R1 ; R0 R0 R1寄存器寻址 B main ; 死循环跳回 main 重新执行 .end ; 汇编结束整体逻辑定义一个字节变量count 30。把它的地址取到 R0。把常数 10 放到 R1。R0 和 R1 相加。跳回开头无限循环。伪操作伪操作是ARM汇编语言程序里的一些特殊的指令助记符。助记符没有相应的操作码不会被编译成实际的执行代码伪操作主要是为完成汇编程序做一些准备工作在源程序汇编过程中起作用一旦汇编完成伪操作的使命就完成。宏是一段独立的程序代码通过伪操作定义在程序中使用宏指令即可调用宏。当程序被汇编时汇编程序校对每个宏调用进行展开用宏定义代替源程序中的宏指令。符号定义伪操作用于定义变量、赋值或给寄存器起别名让代码更易读。全局变量声明GBLA、GBLL、GBLS局部变量声明LCLA、LCLL、LCLS变量赋值SETA、SETL、SETS寄存器列表别名RLIST数据定义伪操作用于分配存储单元并用指定的数据初始化。分配字节/半字/字DCB、DCW、DCD分配浮点数DCFS、DCFD分配连续空间SPACE声明文字池LTORG其他伪操作定义段AREA、.text、.data对齐ALIGN声明全局/外部符号EXPORT/GLOBAL、IMPORT/EXTERN指定指令集CODE16、CODE32、ARM、THUMB文件包含与结束INCLUDE/GET、END伪指令长得像指令但不是真指令。汇编器会把它展开成一条或多条真实指令。伪操作伪指令给谁看汇编器汇编器作用控制汇编过程简化编程代替真实指令编译后不产生机器码展开成真实指令例子.data、.globalLDR R0, value、NOPARM汇编语言格式ARMThumb汇编语言的语句格式为[标号] 指令|条件|S 操作数 [;注释]。ARM指令、伪操作、伪指令、伪操作的助记符全部用大写字母或者全部用小写字母不能既有大写也有小写字母。所有标号在一行的顶格书写后面不要添加“”所有指令不能顶格书写。注释内容以“;”开头到本行结束。源程序中允许有空行如果单行太长可以用字符“\”将其分开“\”后不能有任何字符包括空格和制表符等。举例main: MOV R0, #10 ; R0 10 loop: SUBS R0, R0, #1 ; R0 减 1更新标志位 BNE loop ; 不为 0 就跳回 loopmain:和loop:是标号。MOV、SUBS、BNE是指令。R0, #10是操作数。分号后面是注释。汇编语言的程序结构段section是ARM汇编语言组织源文件的基本单位是独立的、具有特定名称的、不可分割的指令或数据序列。段分为代码段和数据段。代码段存放执行代码。数据段存放代码执行时需要的数据。一个ARM汇编程序至少需要一个代码段较大的程序可以包含多个代码段和数据段。ARM汇编语言源程序经过汇编后生成可执行的映像文件。格式有axm、bin、elf、hex等。可执行的映像文件通常包括三个部分。一个或多个代码段代码段的属性为只读。零个或多个包含初始化数据的数据段属性为可读可写。零个或多个不包含初始化数据的数据段属性为可读可写。连接器根据一定的规则将各个段安排到内存的相应位置。源程序中段之间的相对位置与可执行的映像文件中段的相对位置不一定相同。汇编语言和C语言混合编程ARM体系结构不仅支持汇编语言也支持C语言。在嵌入式开发中C语言是一种常见的程序设计语言。C语言程序可读性强易维护可移植性和可靠性高。C语言中内嵌汇编在C语言程序中嵌入汇编可以完成一些C语言不能完成的操作同时代码效率也比较高。在ARM C语言程序中使用关键词__asm来标识一段汇编指令代码格式__asm //asm前2个下划线 { instruction [; instruction] … [instruction] }如果一行有多条汇编指令指令间用“;”隔开如果一条指令占多行要使用续行符号“\”。举例使用内嵌汇编的加法实现乘3操作#include stdio.h int triple(int n) { asm(add %[value], %[value], %[value], LSL #1 : [value] r (n)); } int main(void) { int n; printf(\nTriple Program!\n); printf(\nEnter an integer: ); scanf(%d, n); printf(\nThree times %d is %d, n, triple(n)); }这比直接调用乘法指令MUL可能更快因为移位和加法通常只需 1 个时钟周期。汇编中访问C语言程序变量在C语言中声明的全局变量可以被汇编语言通过地址间接访问。例如在C语言程序中已经声明了一个全局变量glovbvar通过.global伪指令声明外部变量的方式访问.text .global glovbvar //声明外部变量glovbvar start: LDR R1, glovbvar //装载外部变量地址 LDR R0, [R1] //读出全局变量glovbvar数据 ADD R0, R0, #1 STR R0, [R1] //保存变量值 MOV PC, LR .endARM中的汇编和C语言相互调用ARM 汇编和 C 语言相互调用核心是遵循 AAPCSARM 架构过程调用标准。只要双方都遵守这套规则就能无缝对接。核心规则AAPCS参数传递前 4 个参数依次放入 R0、R1、R2、R3。超过 4 个的参数通过栈传递。返回值返回值放在 R0如果是 64 位用 R0:R1。寄存器保护R0-R3调用者保存Caller-saved。被调用函数可以随便用不用恢复。R4-R11被调用者保存Callee-saved。被调用函数如果用了必须压栈保存返回前恢复。R12IP调用者保存临时寄存器。R13SP栈指针必须保持 8 字节对齐。R14LR返回地址。R15PC程序计数器。C 调用汇编汇编函数用.global声明为全局符号。C 代码用extern声明函数原型。汇编函数遵守 AAPCS返回值放 R0用BX LR返回。汇编侧.text .global add_func add_func: ADD R0, R0, R1 ; 参数在 R0、R1结果放 R0 BX LR ; 返回C侧extern int add_func(int a, int b); int main(void) { int result add_func(3, 5); // 调用汇编函数 return 0; }汇编调用CC 函数用extern或直接定义编译后符号全局可见。汇编用BL指令调用。参数按 AAPCS 放入 R0-R3。C侧int c_func(int a, int b) { return a b; }汇编侧.text .global _start _start: MOV R0, #3 ; 第一个参数 MOV R1, #5 ; 第二个参数 BL c_func ; 调用 C 函数返回值在 R0 B .
返回列表