汇编语言练习(在树莓派4b上实现)- 基于《奔跑吧,Linux内核第二版》

前言

对于树莓派系统的安装请见我之前写的博客安装过程
以下写的汇编代码都是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寄存器保存到栈中就需要这个命令。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值