实验要求
将一个简单的C程序汇编成LoongArch或RISC-V汇编代码,并逐步分析程序的执行过程,深入理解存储程序计算机和函数调用堆栈框架在执行过程中所起的作用。
实验步骤
1.安装RISC-V交叉编译器
sudo apt-get install gcc-riscv64-linux-gnu
2.编写测试程序lab1.c
vim /tmp/lab1.c
3.生成RISC-V汇编代码
riscv64-linux-gnu-gcc -S -o lab1.s lab1.c
4.分析汇编代码
.file "lab1.c" #源文件名
.option nopic #生成位置无关代码
.text
.align 1 #指定对齐方式
.globl g #指定g为全局可调用
.type g, @function #指定g为函数
g:
add sp,sp,-32 # sp = sp - 32, sp为栈顶指针
sd s0,24(sp) # s0的值保存在sp+24的地址中, s0为栈底指针
add s0,sp,32 # s0 = sp + 32
mv a5,a0 # a5 = a0
sw a5,-20(s0) # a5的值保存在s0-20的地址中
lw a5,-20(s0) # 将s0-20地址中的值保存在a5
addw a5,a5,3 # a5 = a5 + 3
sext.w a5,a5
mv a0,a5 # g函数的返回a5保存在a0中用于返回
ld s0,24(sp) # s0 = sp + 24,恢复栈底指针原值
add sp,sp,32 # 恢复栈顶指针原值
jr ra # 跳转,函数返回
.size g, .-g
.align 1
.globl f # f为全局符号
.type f, @function # f定义为函数
f:
add sp,sp,-32 # sp = sp - 32, sp为栈顶指针
sd ra,24(sp) # ra的值(返回地址)保存在sp+24的地址中
sd s0,16(sp) # s0的值保存在sp+16的地址中,s0为栈底指针
add s0,sp,32 # s0 = sp + 32
mv a5,a0 # a5 = a0,保存函数传入进来的的参数
sw a5,-20(s0) # a5的值存放到s0-20指向的地址中
lw a5,-20(s0) # 将s0-20地址中的值存放到a5中
mv a0,a5 # a0 = a5保存调用g函数的待传的参数
call g # 调用g函数
mv a5,a0 # a5 = a0
mv a0,a5 # a0 = a5, f函数的返回值保存在a0中
ld ra,24(sp) # ra = sp + 24, 得到返回地址
ld s0,16(sp) # s0 = sp + 16, 将sp+16的值重新存储到s0栈底指针中,指向main函数的栈空间
add sp,sp,32 # sp = sp + 32, 指向main函数栈空间栈顶
jr ra # 函数返回,回到mian函数
.size f, .-f
.align 1
.globl main
.type main, @function
main:
add sp,sp,-16 # sp = sp - 16
sd ra,8(sp) # Mem[sp+8]=ra
sd s0,0(sp) # Mem[sp]=s0,s0为栈底指针
add s0,sp,16 # s0=sp+16,main函数栈空间
li a0,8 # 保存函数调用的待传参数
call f # 调用f函数
mv a5,a0 # a5 = a0, f函数返回值保存到a5中
addw a5,a5,1 # a5 = a5 + 1
sext.w a5,a5
mv a0,a5 # a0 = a5, 保存main函数的返回值
ld ra,8(sp) # 得到返回地址
ld s0,0(sp) # 恢复栈底指针
add sp,sp,16 # 恢复栈顶指针
jr ra # 函数返回
.size main, .-main
.ident "GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0"