汇编语言实现
前言
对于树莓派系统的安装请见我之前写的博客安装过程
以下写的汇编代码都是arm64语言
实验一 查找最大数
编写汇编代码
我们要实现的功能是在一个数组中查找数组中的最大值,汇编代码如下:
.section .data
.align 3
my_data: ;my_data是一个数组
.quad 1 ; .quad为8字节大小的数
.quad 2
.quad 5
.quad 8
.quad 10
.quad 12
my_data_count: ;这个数组有6个数
.quad 6
.align 3
print_data: ;打印字符串
.string "big data: %d\n"
; 1-16行为数据段
.section .text ;代码段
.globl main ;定义main函数
main:
stp x29, x30, [sp, -16]! ; x29寄存器是FP栈帧寄存器 X30是链接寄存器
; 这行代码功能是把x292和x30寄存器保存到栈中
ldr x0, =my_data ;读取my_data标签
ldr x1, my_data_count ;读取my_data_count标签
add x4, x0, #40 ;读取数组最后一个数地址,因为从开始到结束差了8*5个位置所以为40
mov x3, xzr ;x3为临时寄存器 初始值为0
1:
ldr x2, [x0], #8 ;后变基加载模式 以x0为地址,加载这个地址的值到x2,x0+8
cmp x2, x3 ;比较x2 x3
csel x3, x2, x3, hi ;条件选择 如果x2大于x3 x3保留x2的值
cmp x0, x4 ;判断是否是最后一个数 不是跳转到1标签处
b.ls 1b
ldr x0, =print_data ;加载print_data的地址到x0
mov x1, x3 ;x3存放最大值
bl printf ;调用printf函数
ldp x29, x30, [sp], 16 ;恢复x29与x30寄存器
ret ;返回
注意这个;后面是注释
运行代码
调试代码
调试代码可以使用工具gdb,首先需要下载
sudo dnf install gdb
注意如果需要gdb调试在汇编汇编代码的时候要加 -g,gdb调试的是可执行文件,在这里我在main函数处加了断点,s(单步调试)可进入下一行代码,可使用info reg命令来查看寄存器的信息(地址和值),如果要指定,比如我要看寄存器x0的值可用命令info reg x0,可按q退出
实验二 通过C语言调用汇编
编写汇编代码
编写一个比较两个值的函数
.section .text ;这个段是代码段
.global compare_data ;定义一个函数
compare_data:
cmp x0,x1 ;比较x0与x1寄存器的值
csel x0,x0,x1,hi ;条件判断比较x0与x1(如x0>x1则将x0的值保存进x0寄存器,反之就是x1)
ret ;返回
编写C语言代码
#include<stdio.h>
extern int compare_date(int x,int y); //引入汇编函数
int main(int argc,char*argv[]){
int res=compare_data(6,8);
printf("The bigger data is %d\n",res);
}
运行代码
实验三 通过汇编语言调用C函数
编写C语言代码
#include<stdio.h>
int compare_data1(int a,int b){
return a>=b?a:b;
}
这一段没啥,学过C语言的都懂
编写汇编语言代码
.section .data ;数据段
.align 3
print_data: ;print_data打印字符串
.string "bigger data is: %d\n"
.section .text ;代码段
.globl main ;定义main函数
main:
stp x29, x30, [sp, -16]! ;将x29和x30寄存器保存到栈中
mov x0, #6 ;x0寄存器中的值为6
mov x1, #8 ;x1寄存器中的值为8
bl compare_data1 ;调用我们再C语言中的compare_data1函数
mov x1, x0 ;这里相当于将结果保存进x1
ldr x0, =print_data ;print_data置入x0寄存器中
bl printf ;调用printf函数
ldp x29, x30, [sp], 16 ;恢复x29与x30寄存器
ret ;返回
执行代码
实验四 gcc内联汇编
编写带有内联汇编的C语言代码
依然是实现比较两个值
#include<stdio.h>
int compare_data2(int a,int b){
int res;
//以下为内联汇编
asm volatile(
"cmp %1,%2\n\t" ;%1是指a %2是指%b
"csel %0,%1,%2,hi\n\t" ; %0是指res
:"+r"(res)
:"r"(a),"r"(b)
:"memory"
);
return res;
}
int main(int argc,char*argv[]){
int a=8,b=1;
printf("The bigger data is %d\n",compare_data2(a,b));
}
运行代码
总结
这次实验让我慢慢接触了arm64汇编,之前接触的都是x86架构,arm64使用了RISC架构,X86使用了CISC架构,RISC更适用于处理简单的任务,CISC更适合处理复杂任务,ARM64常用于手机上。通过这次学习知道了csel汇编指令的使用,真的很有实用性,其作用相当于如:(a>=b)?a:b这样的用法,以及stp汇编指令的使用,常常需要将x29和x30寄存器保存到栈中就需要这个命令。