【ARM扩展资料】汇编语言开发
文章目录
一、指令格式
遵循精简指令集计算机RISC的思想,ARM处理器固定使用二进制32位长度为ARM指令编码(指令代码),称为ARM指令集。1995年推出16位编码的指令集,Thumb指令集,后改进为支持16位和32位指令编码的Thumb-2指令集。这样,既简化了软件开发,又易于提高代码密度、效率和性能。
ARMv8推出了全新的64位指令集,称为A64,运行于64位执行状态AArch64,仍采用32位指令编码。原ARM指令集和Thumb指令集分别改称为A32和T32,运行于32位执行状态AArch32。
ARM汇编语言中,指令助记符、寄存器名可以全是大写、或者全是小写,但不能大小写混用。
1.典型的A64指令格式
opcode Rd, Rn {,operand2}
-
opcode
——指令操作码,使用助记符表达。 -
Rd
——目的寄存器。 -
Rn
——源操作数寄存器1。 -
operand2
——第2个源操作数,可以是立即数、寄存器、存储单元,具有多种寻址方式。
2.加减法的简单指令示例:
ADD X0, X1, X2 // 64位加法:X0 = X1 + X2
ADD W5, W3, W4 // 32位加法:W5 = W3 + W4
SUB X6, X7, X8 // 64位减法:X6 = X7 - X8
SUBS W9, W11, W12 // 32位减法:W9 = W11 - W12,更新NZCV标志
二、语句格式
主要有两种ARM汇编语言语法,一是ARM公司的汇编程序(armasm)使用的统一汇编语言UAL语法(ARMASM语法),另一个GNU汇编程序(AS)的GNU ARM汇编语言语法。AS属于GCC编译器套件。
1.汇编语言语句的通用格式:
标号: 指令|指示符|伪指令 // 注释
其中垂直短线“|”表达“或者”、即多个之一。
-
(1)标号:标号以冒号结尾。
-
(2)汇编语言语句有两种,一是处理器指令语句,一是汇编程序指示符。指示符均以小数点“.”开头,其助记符不能大小写混用,只能全为大写或全为小写。在ARM处理器的汇编语言中,伪指令形式上像指令,但可能产生处理器指令,也可能生成汇编程序指示符。
-
(3)注释(Comments):AArch64汇编语言以双斜线“//”开始,也可以采用斜线加星号(/* */)形式括起注释(与C语言一样)。
三、显示程序
1.信息显示程序(使用C语言函数)
64位ARM汇编语言程序,文件名假设为hello.s。
.data // 数据区
msg: .string "Hello, ARMv8!\n" // 定义字符串(以0结尾)
.text // 代码区
.global main
main: stp x29, x30, [sp, -16]! // 保护寄存器x29和x30
adr x0, msg // 获取字符串地址
bl printf // 调用C语言函数printf显示
mov x0, 0 // 返回值
ldp x29, x30, [sp], 16 // 恢复寄存器x29和x30
ret // 返回
汇编语言程序使用main作为入口函数,main函数开始就是程序执行的第一条指令。函数最后执行“RET”返回指令,程序流程返回到调用程序。入口主函数执行完成,也就意味着程序终止执行,将控制权返回操作系统。
可以使用“.END”汇编结束指示符。不用的话,源程序文件结束于一个新行。
因为使用了C函数,本程序需要使用GCC汇编和连接,命令如下:
gcc -o hello hello.s
生成可执行文件,hello,程序执行输入:
./hello
2.信息显示程序(使用Linux系统功能)
64位ARM汇编语言程序,文件名假设为hello.s。
.data // 数据区
msg: .ascii "Hello, ARMv8!\n" // 定义字符串
len=.-msg // 计算字符串长度,等价给len符号
.text // 代码区
.global _start
_start: mov x0,0 // X0 = 第1个参数(输出设备,0表示标准输出、即显示器)
adr x1,msg // X2 = 第2个参数(字符串首地址)
mov x2,len // X3 = 第3个参数(字符串长度)
mov x8,64 // Linux系统功能(write)的调用号(64)
svc 0 // 调用Linux系统功能
mov x0,0 // X0 = 第1个参数(返回值)
mov x8,93 // Linux系统功能(exit)的调用号(93)
svc 0 // 调用Linux系统
本程序可以采用AS汇编和LD连接:
as -o hello.o hello.s
ld -o hello hello.o
采用GCC进行汇编和连接,起始标号“_start”要更改为“main”:
gcc -o hello hello.s
如果改为“main”后,还要用LD连接,加上“-e main”参数即可。
生成可执行文件,hello,程序执行输入:
./hello
四、C语言程序的开发过程
假设C语言程序的文件名:hello.c
使用GCC开发C语言程序,命令很简单:
gcc -o hello hello.c
选项参数“-o”(小写字母)给出生成的文件名。
实际上,GCC开发过程需要经过预处理、编译、汇编和连接4个步骤(阶段)。这些步骤虽然都可以通过其编译程序GCC实现,但实际上用到了多个程序文件。
1.预处理(预编译,Preprocessing)
使用CPP文件,处理源程序文件(* .c)中以#开头的语句,生成预处理后的文本文件(* .i)。
gcc –E –o hello.i hello.c
参数“-E”(大写字母)表示仅预处理、生成文本文件,不进行编译、汇编和连接。
2.编译(Compilation)
使用CC文件,将预处理后的文本文件(* .i)翻译成汇编语言程序(* .s)。
gcc –S hello.i
参数“-S”(大写字母)表示进行编译,生成汇编语言程序,但不进行汇编和连接。
可以直接针对源程序文件,将预处理和编译步骤一并进行:
gcc –S hello.c
默认生成与源程序文件名相同的汇编语言程序文件,加参数“-o”可另指定一个。
3.汇编(Assembly)
使用AS文件,将汇编语言程序(* .s)翻译为目标代码文件(* .o)。
gcc –c hello.s
也可以针对预处理文件或者源程序文件进行汇编:
gcc –c hello.i
gcc –c hello.c
参数“-c”(小写字母)表示(预处理、)编译和汇编,生成目标代码文件,不连接。默认生成的目标代码主文件名与源程序主文件名相同(扩展名不同)。
4.连接(Linking)
使用LD文件,组合目标代码文件(*.o)以及需要的库文件代码等生成可执行文件。
gcc –o hello hello.o
可以直接对汇编语言程序、预处理文件和源程序文件进行,分别是:
gcc –o hello hello.s
gcc –o hello hello.i
gcc –o hello hello.c
生成可执行文件后,在Linux平台输入文件名就可以执行,命令如下:
./hello