(USTC-Linux内核2023spring)简单程序的RISCV汇编解读

Katzeee 2023-03-13 19:23:29

实验环境ubuntu18.04

准备工作,在x64平台编译RISCV汇编代码需要交叉编译链:

首先通过gcc -v获得当前gcc版本,再通过sudo apt search riscv查找riscv,找到一个包的描述为"GNU C compiler (cross compiler for riscv64 architecture)",并且其版本号和gcc的版本号相同,那就是他没错了

$ sudo apt install gcc-7-riscv64-linux-gnu

安装该包及其自动下载的依赖包之后就可以开始编译了。

对于以下程序

int g(int x) { return x + 3; }
int f(int x) { return g(x); }

int main() { return f(8) + 1; }

在x64平台进行RISCV交叉汇编汇编,采用刚刚下载的交叉编译器

$ riscv64-linux-gnu-gcc-7 -S main.c -o main-riscv64.s

根据网上的相关资料


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述

得到的汇编文件如下,三个函数做的事情基本相同,只解释了main中的语句。以及其中有些我认为无意义的语句

When you build without optimization the compilers priority is to generate code that's easy to debug and matches the original source code as closely as possible, not code that runs fast.

        .file   "main.c"
        .option nopic
        .text
        .align  1
        .globl  g
        .type   g, @function
g:
        add     sp,sp,-32
        sd      s0,24(sp)
        add     s0,sp,32
        mv      a5,a0
        sw      a5,-20(s0)
        lw      a5,-20(s0)
        addw    a5,a5,3
        sext.w  a5,a5
        mv      a0,a5
        ld      s0,24(sp)
        add     sp,sp,32
        jr      ra
        .size   g, .-g
        .align  1
        .globl  f
        .type   f, @function
f:
        add     sp,sp,-32
        sd      ra,24(sp)
        sd      s0,16(sp)
        add     s0,sp,32            以上同main,保存现场以及返回地址
        mv      a5,a0                以下四句推测是编译器在无优化状态下做的无意义操作
        sw      a5,-20(s0)            我尝试在O1 flag下进行编译,整个程序直接变成了返回立即数
        lw      a5,-20(s0)
        mv      a0,a5
        call    g
        mv      a5,a0
        mv      a0,a5
        ld      ra,24(sp)
        ld      s0,16(sp)
        add     sp,sp,32
        jr      ra
        .size   f, .-f
        .align  1
        .globl  main
        .type   main, @function
main:
        add     sp,sp,-16            扩展栈空间
        sd      ra,8(sp)            caller保存return address
        sd      s0,0(sp)            main函数作为callee保存frame pointer
        add     s0,sp,16            逻辑空栈
        li      a0,8                caller存入函数参数
        call    f                    调用f
        mv      a5,a0                将函数返回值存入a5
        addw    a5,a5,1                执行+1并存入a5
        sext.w  a5,a5                将其扩展到32位并进行符号扩展
        mv      a0,a5                存入a0等待返回
        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"

Reference:

https://zhuanlan.zhihu.com/p/295439950

https://lgl88911.github.io/2021/02/28/RISC-V%E6%B1%87%E7%BC%96%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8/

...全文
78 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

571

社区成员

发帖
与我相关
我的任务
社区描述
软件工程教学新范式,强化专项技能训练+基于项目的学习PBL。Git仓库:https://gitee.com/mengning997/se
软件工程 高校
社区管理员
  • 码农孟宁
加入社区
  • 近7日
  • 近30日
  • 至今

试试用AI创作助手写篇文章吧