栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

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

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

汇编语言实现
  • 前言
  • 实验一 查找最大数
    • 编写汇编代码
    • 运行代码
    • 调试代码
  • 实验二 通过C语言调用汇编
    • 编写汇编代码
    • 编写C语言代码
    • 运行代码
  • 实验三 通过汇编语言调用C函数
    • 编写C语言代码
    • 编写汇编语言代码
    • 执行代码
  • 实验四 gcc内联汇编
    • 编写带有内联汇编的C语言代码
    • 运行代码
  • 总结

前言

对于树莓派系统的安装请见我之前写的博客安装过程
以下写的汇编代码都是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: %dn"
  ; 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
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 %dn",res);
}
运行代码

实验三 通过汇编语言调用C函数 编写C语言代码
#include

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: %dn"
.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

int compare_data2(int a,int b){
  int res;
  //以下为内联汇编
  asm volatile(
               "cmp %1,%2nt" ;%1是指a %2是指%b
               "csel %0,%1,%2,hint" ; %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 %dn",compare_data2(a,b));
}
运行代码


总结

这次实验让我慢慢接触了arm64汇编,之前接触的都是x86架构,arm64使用了RISC架构,X86使用了CISC架构,RISC更适用于处理简单的任务,CISC更适合处理复杂任务,ARM64常用于手机上。通过这次学习知道了csel汇编指令的使用,真的很有实用性,其作用相当于如:(a>=b)?a:b这样的用法,以及stp汇编指令的使用,常常需要将x29和x30寄存器保存到栈中就需要这个命令。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/384627.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号