LA32R汇编编程简介
LA32R汇编编程学习环境介绍
交叉工具链
在进行基于LA32R的应用程序或操作系统开发时,由于我们手边缺少真实的以LA32R为架构的CPU,我们可以借助交叉工具链进行代码的编译与程序的模拟运行。
在交叉开发的过程中,应区分宿主机和目标机。目标机的指令集架构是期望运行的架构,也就是本手册的LA32R架构;宿主机是执行编译、提供模拟运行环境的机器,如我们常用的x86架构机器。交叉编译要实现的目标是在宿主机上生成目标机架构的代码,模拟运行实现的目标是在宿主机上运行目标机架构的程序。
下表中的工具为LA32R汇编编程环境所需的工具与软件环境,请选择对应版本下载好,下一小节将介绍它们的使用方法。
| 工具 | 用途 | 下载地址 |
|---|---|---|
| loongarch32r-linux-gnusf-{gcc/objdump/gdb/...} | 交叉编译器、反汇编器、调试器…… | 工具发行版地址 |
| la32r-QEMU | LA32R模拟器 | 源码仓库地址 |
| la32r-Linux | LA32R内核 | 源码仓库地址 |
环境搭建与工具使用方法介绍
loongarch32r-linux-gnusf-*
交叉工具链目前仅支持宿主机为x86架构和LA64架构的版本。下载后可以通过
将其添加至环境变量中并使其生效。可以在命令行中输入loong后按<TAB>键查看是否能够自动联想出loongarch32r-linux-gnusf-,来检查路径配置是否正确。
工具的使用方法与不带交叉前缀的使用方法一致。最常使用的两个工具为gcc和objdump。前者用于编译.c或.S源文件生成目标机可执行程序;后者用于生成反汇编文件,常用于debug,查看指令地址PC和指令inst的关系,查看变量的内存地址等等,它的不同参数会输出不同的内容,可以查阅GNU工具手册的objdump部分了解更多。
# compile source
$ loongarch32r-linux-gnusf-gcc <file_name>.S -o <file_name>
# dump disassembly file
$ loongarch32r-linux-gnusf-objdump -D <file_name> > <file_name>.s
la32r-QEMU
通过qemu(Quick Emulator),我们可以在宿主机上运行目标机架构程序,能够运行我们编写的LA32R汇编程序。
qemu编译 因为提供的是qemu源码,因此可以在各自宿主机上进行编译运行。编译qemu前请阅读仓库的wiki,安装好编译时的依赖。编写编译脚本<your qemu path>/build.sh,建议添加--static编译选项生成静态可执行qemu。生成的qemu为<your qemu path>/build/qemu-system-loongarch32。
| build.sh | |
|---|---|
qemu运行
QEMU的两种运行模式:
User Mode(使用者模式):用户只需要将目标机架构程序放在QEMU中运行即可,其他的事情全部由QEMU虚拟机来完成,不需要用户自定义内核和虚拟磁盘等文件。
System Mode(系统模式):用户需要为QEMU指定运行的内核或者虚拟硬盘等文件。
目前la32r的qemu仅支持system模式,因此在使用时我们需要通过-kernel选项为其指定内核文件,下一小节对内核文件进行详细介绍。其他参数配置详见qemu仓库的wiki。类似地,我们可以编写运行脚本<your qemu path>/system_run.sh。
如果在qemu上运行出错,需要debug,我们可以利用loongarch32r-linux-gnusf-gdb通过端口连接后进行交叉调试。此时需要添加-gdb tcp::1234配置端口号,以及-S让qemu不自动运行,与gdb连接后再运行。
la32r-Linux
由于目前la32r的qemu仅支持system模式,我们需要指定内核文件,即为由该源码编译完成的内存镜像文件。
initrd内存文件系统 由于目前la32r的linux尚不支持文件系统,仅支持initrd内存文件系统,我们需要把由gcc编译好的可执行程序放入initrd文件夹中,编译内核,从而运行qemu后可以在同一路径中找到可执行程序并进行执行。每次对initrd中的文件修改后都必须重新编译内核。la32r的linux提供一个基础的initrd包,下载后解压可直接使用。
可以看到initrd的目录结构就是我们平常所见的根目录下的文件系统的结构。我们可以将写好的应用程序放置于initrd_d/home目录下,并修改initrd_d/etc/profile使得每次启动linux后直接进入可执行程序所在路径。
linux编译 因为提供的是linux源码,我们需要在宿主机上进行交叉编译。编译linux前请阅读仓库的README。修改编译脚本<your linux path>/la_build.sh,注意修改CROSS_COMPILE变量,因为前面我们已将其添加到环境变量中,可以不指明交叉编译器路径。生成的linux为<your linux path>/la_build/vmlinux。
编译linux时,我们需要在配置文件中指明initrd_d的路径。一个办法是通过menuconfig图形界面完成配置,注意路径按照个人配置来设置。



另一个办法是与menuconfig具有相同功能的非图形化配置,修改la_build/.config文件中的如下参数即可。
loongarch32r-linux-gnusf-gdb
如果在qemu上程序运行出错,此时我们可以利用gdb进行debug。前面提到,可以在qemu运行时添加-gdb tcp::1234和-S参数,等待gdb通过端口1234来连接。连接后,像调试普通宿主机程序一样调试即可。
qemu与gdb的连接过程
| 宿主机 terminal 1: qemu | 宿主机 terminal 2: gdb |
|---|---|
|
|
|
|
|
gdb常用命令
| 命令 | 例子 | 用法 |
|---|---|---|
c |
- | 继续执行,直到遇到断点 |
si |
- | 执行下一条指令,如果有函数调用,则进入函数内部 |
ni |
- | 执行下一条指令,即使有函数调用,也不会进入函数内部 |
i r( info registers) |
- | 查看全部通用寄存器值 |
b <symbol> |
b main |
在标号处设断点 |
b *<addr> |
b *0x10518 |
在某地址处设断点 |
p /<basic_format> <symbol> |
p /x $sp |
以某种格式打印某个标号(寄存器或变量)的值<basic_format>:c->chard->decimalo->octalx->hex |
x /<format> <symbol> |
x /10x 0x10580x /20i 0x10580x /20i $pc |
以某种格式打印内存地址的值<format> = <num><basic_format><basic_format>:c->chard->decimalo->octalx->hexi->instruction |
disassemble |
- | 查看当前PC所在地址的一段汇编指令 |