571
社区成员
发帖
与我相关
我的任务
分享将一个简单的C程序汇编成ARM64汇编代码,并逐步分析程序的执行过程,深入理解存储程序计算机和函数调用堆栈框架在执行过程中所起的作用。
1、安装RISC-V的交叉编译器
sudo apt-get install gcc-riscv64-linux-gnu
2、创建文件1.c
#include<stdio.h>
int f(int a,int b) {
return 3*a + b;
}
int main() {
int a = 1;
int b = 2;
int result=f(a,b);
return 0;
}
3、把1.c文件编译为1.s文件
riscv64-linux-gnu-gcc -S 1.c -o 1.S
4.查看汇编代码并分析
.file "1.c"
.option pic
.text
.align 1
.globl f
.type f, @function
f:
addi sp,sp,-32 //sp = sp - 32, sp为栈顶指针
sd s0,24(sp) // s0的值保存在sp+24的地址中, s0为栈底指针
addi s0,sp,32 //s0 = sp + 32
mv a5,a0 //a的值放入a5寄存器
mv a4,a1 //b的值放入a4寄存器
sw a5,-20(s0) //a的值保存在s0-20的地址中
mv a5,a4 //b的值放入a5寄存器
sw a5,-24(s0) //b的值保存在s0-24的地址中
lw a4,-20(s0) //将s0-20地址中的值保存在a4寄存器,a4寄存器保存a的值
mv a5,a4 //a5寄存器保存a的值
slliw a5,a5,1 //a5寄存器左移一位存入a5,即a5寄存器保存a*2的值
addw a5,a5,a4 //a4寄存器的值与a5寄存器值相加存入a5,即a5寄存器保存a*3的值
sext.w a5,a5 //a5寄存器的值扩展为64位
lw a4,-24(s0) //将s0-24地址中的值保存在a4寄存器,a4寄存器保存b的值
addw a5,a4,a5 //a4寄存器的值与a5寄存器值相加存入a5,即a5寄存器保存a*3+b的值
sext.w a5,a5 //a5寄存器的值扩展为64位
mv a0,a5 //a5寄存器的值存入a0,即a0的值为a*3+b
ld s0,24(sp) //将栈顶+24字节位置上的值存储到s0寄存器中,恢复s0的值
addi sp,sp,32 //释放32字节的栈空间,将sp指针向上移动
jr ra //跳转到ra寄存器的地址执行,返回调用者
.size f, .-f
.align 1
.globl main
.type main, @function
main:
addi sp,sp,-32 //将栈指针向下移动32个字节
sd ra,24(sp) //将ra寄存器的值保存到sp+24字节的位置
sd s0,16(sp) //将r0寄存器的值保存到sp+16字节的位置
addi s0,sp,32 //s0 = sp+32
li a5,1 //把a5寄存器的值设置为1,存入了变量a
sw a5,-28(s0) //把a5寄存器的值保存到s0-28的位置,即把变量a加入栈
li a5,2 //把a5寄存器的值设置为2,存入了变量b
sw a5,-24(s0) //把a5寄存器的值保存到s0-24的位置,即把变量b加入栈
lw a4,-24(s0) //将s0-24地址中的值保存在a4寄存器,即a4寄存器保存了变量b
lw a5,-28(s0) //将s0-28地址中的值保存在a5寄存器,即a5寄存器保存了变量a
mv a1,a4 //变量b存入a1寄存器
mv a0,a5 //变量a存入a0寄存器
call f //调用函数f
mv a5,a0 //将a0寄存器的值存储到a5寄存器中,函数调用结果存入a5
sw a5,-20(s0) //把a5寄存器的值保存到s0-20的位置
li a5,0 //a5寄存器值设置为0
mv a0,a5 //a0的值为1
ld ra,24(sp) //将栈顶+24字节位置上的值存储到ra寄存器中
ld s0,16(sp) //将栈顶+16字节位置上的值存储到s0寄存器中
addi sp,sp,32 //sp=sp+32,栈帧退回
jr ra //跳转到ra寄存器的地址执行,返回调用者
.size main, .-main
.ident "GCC: (Ubuntu 9.4.0-1ubuntu1~20.04) 9.4.0"
.section .note.GNU-stack,"",@progbits