【无标题】

Linux操作系统分析实验1

实验内容:将一个简单的C程序汇编成LoongArch或RISC-V汇编代码,并逐步分析程序的执行过程,深入理解存储程序计算机和函数调用堆栈框架在执行过程中所起的作用。

首先执行sudo apt-get install gcc-riscv64-linux-gnu安装RISC-V的交叉编译器
通过riscv64-linux-gnu-gcc -S -o test_riscv64.s test.c将以下test.c编译成risc-v代码

#include 

int add_test(int a,int b)
{
	return a+b;
}

int sub_test(int a,int b)
{
	return a-b;
}

int main()
{
    return add_test(2,sub_test(5,3));
}

汇编代码如下

.file "test.c"       ; 定义当前代码文件名

.option nopic       ; 不生成位置无关代码

.text               ; 代码段开始

.align 1            ; 对齐方式为2^1=2字节对齐

.globl add_test     ; 声明全局符号add_test

.type add_test, @function   ; 声明add_test为函数

add_test:           ; add_test函数开始
    add sp, sp, -32 ; 在栈上为局部变量分配32字节空间
    sd s0, 24(sp)   ; 将s0寄存器的值存入栈中
    add s0, sp, 32   ; 将s0寄存器的值设置为栈顶地址+32
    mv a5, a0       ; 将第一个参数移动到a5寄存器
    mv a4, a1       ; 将第二个参数移动到a4寄存器
    sw a5, -20(s0)  ; 将a5的值存入栈中
    mv a5, a4       ; 将a4的值移动到a5
    sw a5, -24(s0)  ; 将a5的值存入栈中
    lw a4, -20(s0)  ; 将栈中的第一个参数载入a4寄存器
    lw a5, -24(s0)  ; 将栈中的第二个参数载入a5寄存器
    addw a5, a4, a5 ; 将a4和a5寄存器中的值相加并存入a5寄存器
    sext.w a5, a5   ; 将a5寄存器的值进行符号扩展
    mv a0, a5       ; 将a5寄存器的值移动到a0寄存器
    ld s0, 24(sp)   ; 将栈中保存的s0寄存器的值恢复到s0寄存器中
    add sp, sp, 32   ; 释放栈空间
    jr ra           ; 返回调用者
.size add_test, .-add_test  ; 计算add_test函数的大小

.align 1            ; 对齐方式为2^1=2字节对齐

.globl sub_test     ; 声明全局符号sub_test

.type sub_test, @function   ; 声明sub_test为函数

sub_test:           ; sub_test函数开始
    add sp, sp, -32 ; 在栈上为局部变量分配32字节空间
    sd s0, 24(sp)   ; 将s0寄存器的值存入栈中
    add s0, sp, 32   ; 将s0寄存器的值设置为栈顶地址+32
    mv a5, a0       ; 将第一个参数移动到a5寄存器
    mv a4, a1       ; 将第二个参数移动到a4寄存器
	sw  a5, -20(s0)   ; 将a5的值存入地址s0-20的内存中
	mv  a5, a4        ; 将a4的值赋给a5
	sw  a5, -24(s0)   ; 将a5的值存入地址s0-24的内存中
	lw  a4, -20(s0)   ; 将地址s0-20的内存中的值加载到a4中
	lw  a5, -24(s0)   ; 将地址s0-24的内存中的值加载到a5中
	subw a5, a4, a5   ; 将a4的值减去a5的值,结果存入a5中
	sext.w a5, a5     ; 将a5的值符号扩展为32位
	mv  a0, a5        ; 将a5的值赋给a0
	ld s0, 24(sp)    ; 将地址sp+24的值加载到寄存器s0中
	add sp, sp, 32    ; 将sp加上32,回收栈空间
	jr ra            ; 从ra寄存器中取出返回地址,跳转到该地址
.align 1         ; 设置数据对齐方式为2的1次方,即2字节对齐
.globl main      ; 声明main函数是全局可见的
.type main, @function ; 声明main函数是一个函数
main:            ; main函数的入口
	add sp, sp, -16  ; 将栈指针减去16,开辟16个字节的栈空间
	sd ra, 8(sp)     ; 将ra寄存器的值存储到地址sp+8的内存中
	sd s0, 0(sp)     ; 将s0寄存器的值存储到地址sp的内存中
	add s0, sp, 16   ; 将s0的值设为sp+16,即指向当前栈帧的起始地址
	li a1, 3         ; 将立即数3存储到寄存器a1中
	li a0, 5         ; 将立即数5存储到寄存器a0中
	call sub_test    ; 调用sub_test函数
	mv a5, a0        ; 将sub_test函数的返回值存储到寄存器a5中
	mv a1, a5        ; 将a5的值赋给a1
	li a0, 2         ; 将立即数2存储到寄存器a0中
	call add_test    ; 调用add_test函数
	mv a5, a0        ; 将add_test函数的返回值存储到寄存器a5中
	mv a0, a5        ; 将a5的值赋给a0,作为main函数的返回值
	ld ra, 8(sp)     ; 将地址sp+8的内存中的值加载到ra寄存器中
	ld s0, 0(sp)     ; 将地址sp的内存中的值加载到s0寄存器中
	add sp, sp, 16   ; 将栈指针加上16,回收栈空间
	jr ra            ; 从ra寄存器中取出返回地址,跳转到该地址


你可能感兴趣的:(linux,运维,服务器)