后端环境配置¶
本次实验需要安装龙芯的交叉编译工具链。这篇文档将帮助你安装好相关工具。
交叉编译¶
我们的后端面向的是龙芯架构,而虚拟机和宿主机都是 x86 架构,不能直接运行龙芯程序。
所谓的交叉编译,就是在一个平台上生成另一个平台上的可执行代码。
具体到我们的实验,我们将在虚拟机上安装龙芯 gcc、qemu 和 gdb,使得我们可以在虚拟机中生成龙芯的可执行文件、模拟运行并且调试。
安装¶
助教准备了龙芯交叉编译的相关工具,以便同学们在本地完成测试与调试。
具体来说有以下四项:
- loongarch64-clfs-3.0-cross-tools-gcc-glibc.tar.xz:生成龙芯汇编、可执行文件等
- qemu-6.2.50.loongarch64.tar.gz:模拟运行龙芯二进制文件
-
gdb.tar.gz:调试生成的龙芯程序
-
test-env.tar.gz:用于测试上述工具是否安装成功
点击上方链接,下载压缩包至虚拟机中。你可以根据自己的喜好选择存放的位置,比如 ~/Downloads
。
如何在宿主机和虚拟机之间传送文件?
如果你在 Windows 系统上阅读本文档,你大概将网盘中的文件下载到了 Windows 系统(宿主机)中。
如何将文件传递进虚拟机中呢?在 Lab0 中你已经配置了宿主机与虚拟机之间的 SSH 连接,现在你可以通过 scp 命令进行文件传输:
$ scp -P 端口号 源文件 目标文件
gdb.tar.gz
传送到虚拟机的 ~/Downloads
目录,具体步骤如下:
- 在 Windows 文件资源管理器中找到下载好的文件
- 在文件列表的空白处按住 Shift 点击鼠标右键,选择打开 PowerShell
- 在弹出的命令行窗口中键入:
scp -P 主机端口 gdb.tar.gz 虚拟机用户名@127.0.0.1:~/Downloads
现在进入虚拟机中你选择的目录,通过 ls
可以看到下载好的压缩包,执行以下解压命令,将交叉编译工具解压到 /opt
目录下:
$ sudo tar xaf loongarch64-clfs-3.0-cross-tools-gcc-glibc.tar.xz -C /opt
$ sudo tar xaf qemu-6.2.50.loongarch64.tar.gz -C /opt
$ sudo tar xaf gdb.tar.gz -C /opt
此时解压好的工具分别位于:
/opt/cross-tools.gcc_glibc/bin/loongarch64-unknown-linux-gnu-gcc
/opt/qemu/bin/qemu-loongarch64
/opt/gdb/bin/loongarch64-unknown-linux-gnu-gdb
需要使用绝对路径访问。为了使用方便和 Lab3 的顺利测评,我们将上述路径加入到PATH
中:
$ echo "export PATH=\$PATH:/opt/cross-tools.gcc_glibc/bin:/opt/gdb/bin:/opt/qemu/bin" >> ~/.bashrc && source ~/.bashrc
测试¶
经过上述步骤,你可以使用以下三个命令简单检查是否安装成功:
检查龙芯 gcc 版本
$ loongarch64-unknown-linux-gnu-gcc -v
Using built-in specs.
COLLECT_GCC=loongarch64-unknown-linux-gnu-gcc
COLLECT_LTO_WRAPPER=/opt/cross-tools.gcc_glibc/bin/../libexec/gcc/loongarch64-unknown-linux-gnu/12.0.1/lto-wrapper
Target: loongarch64-unknown-linux-gnu
Configured with: ../configure --prefix=/opt/cross-tools --build=x86_64-cross-linux-gnu --host=x86_64-cross-linux-gnu --target=loongarch64-unknown-linux-gnu --enable-__cxa_atexit --enable-threads=posix --enable-libstdcxx-time --enable-checking=release --with-sysroot=/opt/cross-tools/target --enable-default-pie --enable-languages=c,c++,fortran,objc,obj-c++,lto
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 12.0.1 20220210 (experimental) (GCC)
检查龙芯 qemu 版本
$ qemu-loongarch64 -version
qemu-loongarch64 version 6.2.50 (v6.0.0-7567-gac069a8ffb)
Copyright (c) 2003-2022 Fabrice Bellard and the QEMU Project developers
检查龙芯 gdb 版本
$ loongarch64-unknown-linux-gnu-gdb -v
GNU gdb (GDB) 12.0.50.20210713-git
Copyright (C) 2021 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.```
更进一步,我们提供了环境测试程序。
进入虚拟机中存放压缩包的目录,解压压缩包 test-env.tar.gz
:
$ tar xaf test-env.tar.gz
解压得到文件夹 test-env
,其结构及说明如下:
test-env
├── bubble-sort.S # 冒泡排序的汇编实现
├── hello-world.S # 输出 hello world 的汇编实现
├── inline-assembly.c # 内嵌汇编的 c 程序
└── Makefile # 使用 make 自动测试 gcc 和 qemu 是否安装成功
测试 gcc 与 qemu¶
进入上述 test-env
文件夹中,make
,三段源程序将被编译成面向龙芯的可执行文件,并用 qemu 模拟运行。
期望输出
loongarch64-unknown-linux-gnu-gcc -static hello-world.S -o hello-world loongarch64-unknown-linux-gnu-gcc -static bubble-sort.S -o bubble-sort loongarch64-unknown-linux-gnu-gcc -static inline-assembly.c -o inline-assembly loongarch64-unknown-linux-gnu-gcc -O2 -static inline-assembly.c -o inline-assembly-opt qemu-loongarch64 ./hello-world Hello World! qemu-loongarch64 ./bubble-sort 53461 13456 qemu-loongarch64 ./inline-assembly ret_1 ret 123 myadd_1 = 8 myadd_2 = 8 myadd_3 = 8 a = 2, b = 3, c = 2 a = 2, b = 3, c = 2 test5 ok test6 expected error qemu-loongarch64 ./inline-assembly-opt ret_1 ret 123 myadd_1 = 8 myadd_2 = 8 myadd_3 = 8 a = 2, b = 2, c = 1 a = 2, b = 3, c = 2 test5 ok test6 expected error如果得到以上输出,说明 gcc 和 qemu 被正确安装,你已经可以正常进行 Lab3 的评测。
测试 / 使用 gdb¶
Lazy Reading
这一小节是为了调试生成的汇编,你可以在需要调试时再回来查看。
我们接下来调试程序 test-env/bubble-sort.S
,你现在应该去扫一眼这个文件,注意文件最后,main
函数如下:
.global main
main:
bl display # 这是第一条汇编指令,率先被执行,表示将跳转进入 display 函数中
bl sort
bl display
li.w $a7, 93 # exit
li.w $a0, 0
syscall 0x0
在 测试 gcc 与 qemu 环节,已经利用龙芯 gcc 生成了可执行文件 bubble-sort
,我们将读取这个文件进行调试。
龙芯程序运行在 qemu 上,首先需要启动 qemu,再用 gdb 连接。在 test-env
目录下:
- 使用 qemu 模拟运行
bubble-sort
$ qemu-loongarch64 -g 1234 bubble-sort &
参数 -g 1234
表示不立即执行而是等待 gdb 连接端口 1234,结尾的 &
符号令 qemu 程序在后台运行。
- 启动 gdb 并连接 qemu
$ loongarch64-unknown-linux-gnu-gdb --quiet
(gdb)
我们使用 --quiet
参数避免 gdb 输出冗长的版本信息。出现提示符 (gdb)
,表示我们处于 gdb 的命令行环境中。
指定可执行文件:
(gdb) file bubble-sort
Reading symbols from bubble-sort...
连接 qemu:
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
warning: Can not parse XML target description; XML support was disabled at compile time
_start () at ../sysdeps/loongarch/start.S:45
45 ../sysdeps/loongarch/start.S: No such file or directory.
出现了一些 warning,对我们的调试没有影响,可以忽略之。
- 现在程序停止在
_start()
处,我们让程序停在main
函数的入口处:
(gdb) break main
Breakpoint 1 at 0x1200008f4
(gdb) continue
Continuing.
Breakpoint 1, 0x00000001200008f4 in main ()
现在,程序停止在 main
函数入口处。
- 将内存中的机器码程序反汇编出来:
(gdb) disassemble
Dump of assembler code for function main:
=> 0x00000001200008f4 <+0>: bl -204(0xfffff34) # 0x120000828 <display>
0x00000001200008f8 <+4>: bl -100(0xfffff9c) # 0x120000894 <sort>
0x00000001200008fc <+8>: bl -212(0xfffff2c) # 0x120000828 <display>
0x0000000120000900 <+12>: ori $a7, $zero, 0x5d
0x0000000120000904 <+16>: move $a0, $zero
0x0000000120000908 <+20>: syscall 0x0
End of assembler dump.
在这里有很多有用的信息,比如你看到了 main
函数入口处的全部汇编指令,还有当前正在执行的指令地址是 0x00000001200008f4
,这也是 main
函数的地址……
通过对比,你会发现反汇编得到的指令与 bubble-sort.S
中的手写指令基本一致。
- 查看当前寄存器状态:
(gdb) info registers
zero ra tp sp
R0 0000000000000000 00000001200009c4 00000001200947e0 00000040007ffb00
a0 a1 a2 a3
R4 0000000000000001 00000040007ffc58 00000040007ffc68 000000012008c030
a4 a5 a6 a7
R8 0000000000000001 000000012008d060 00000040007ffc50 fffffffffffff000
t0 t1 t2 t3
R12 00000001200008f4 00000040007ffb20 0000000000000000 00000001200932b8
t4 t5 t6 t7
R16 000000012008ee00 000000012008ee00 636a6b6c7c6a2f5b ffffffffffffffff
t8 x fp s0
R20 fffffffffefef000 0000000000000000 0000000000000000 0000000120088da8
s1 s2 s3 s4
R24 0000000000000001 00000040007ffc58 0000000000000001 00000001200008f4
s5 s6 s7 s8
R28 00000040007ffc68 0000000000000001 0000000120000468 0000000000000000
pc 0x1200008f4 0x1200008f4 <main>
badvaddr 0x0 0x0
你可以重点关注一下 pc 寄存器:其中的值与反汇编得到的 main
函数地址一致。
- 当前程序停止在
main
函数入口处,即将执行的是指令bl display
,我们执行这条指令,将进入display
函数:
(gdb) stepi
0x0000000120000828 in display ()
更多的实用指令,请善用搜索引擎自助查询,我们也欢迎同学们在群内或者论坛中进行讨论。