- 前言
- 实验一 查找最大数
- 编写汇编代码
- 运行代码
- 调试代码
- 实验二 通过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退出
编写一个比较两个值的函数
.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运行代码 实验三 通过汇编语言调用C函数 编写C语言代码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); }
#includeint 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 ;返回执行代码
依然是实现比较两个值
#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寄存器保存到栈中就需要这个命令。



