需求 有时候身边只有 x86 架构的硬件环境,却想学习和测试 arm、mips 等其他架构特性,此时怎么办呢?众所周知,VMware 只能模拟同架构不同操作系统,对此可以通过 qemu 实现跨架构模拟。
 
安装 qemu-user qemu 是一个支持跨平台虚拟化的虚拟机,有 user mode 和 system mode 两种配置方式。其中 qemu 在 system mode 配置下模拟出整个计算机,可以在 qemu 之上运行一个操作系统。qemu 的 system mode 与常见的 VMware 和 Virtualbox 等虚拟机比较相似,但是 qemu 的优势是可以跨指令集。例如,VMware 和 Virtualbox 之类的工具通常只能在 x86 计算机上虚拟出一个 x86 计算机,而 qemu 支持在 x86 上虚拟出一个 ARM 计算机。qemu 在 user mode 配置下,可以运行跟当前平台指令集不同的平台可执行程序。例如可以用 qemu 在 x86 上运行 ARM 的可执行程序,但是两个平台必须是同一种操作系统,比如 Linux。
1 sudo apt install qemu-user 
 
安装 gdb-multiarch gdb-multiarch 是一个经过交叉编译后的、支持多架构版本的 gdb。
1 sudo apt install gdb-multiarch 
 
安装 aarch64 编译工具链 1 sudo apt install gcc-aarch64-linux-gnu 
 
交叉编译测试用例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 lhx@ubuntu:~/test/qemu$ ls hello.c lhx@ubuntu:~/test/qemu$ cat hello.c  #include <stdio.h> void hello() {   printf("Hello World !\n"); } int main() {   hello();   return 0; } lhx@ubuntu:~/test/qemu$ aarch64-linux-gnu-gcc -g -static hello.c  lhx@ubuntu:~/test/qemu$ ls a.out  hello.c lhx@ubuntu:~/test/qemu$ file a.out  a.out: ELF 64-bit LSB executable, ARM aarch64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=e1fe3c59cad06eff9cab2729a00233bc10d763ce, for GNU/Linux 3.7.0, with debug_info, not stripped lhx@ubuntu:~/test/qemu$ qemu-aarch64 ./a.out  Hello World ! 
 
开始 qemu+gdb 跨架构调试 
窗口 1:启动 a.out 通过 qemu-aarch64 运行交叉编译的 a.out, 并指定 gdb 调试端口号为 1234,然后等待 gdb 远程连接。 
 
1 2 lhx@ubuntu:~/test/qemu$ qemu-aarch64 -g 1234 ./a.out Hello World ! 
 
-g port:该选项表示 QEMU_GDB 环境变量取值,即 等待 gdb 连接的端口号。
 
窗口 2:gdb 远程调试 通过 gdb-multiarch 启动 a.out,这里 a.out 用于读取和远程端一致的调试符号信息。连接上远程端口号后,便可以进行设断点、查看寄存器、反汇编等一系列调试操作。 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 lhx@ubuntu:~/test/qemu$ ls a.out  hello.c lhx@ubuntu:~/test/qemu$ gdb-multiarch -q a.out  Reading symbols from a.out... (gdb) target remote localhost:1234 Remote debugging using localhost:1234 0x0000000000400558 in _start () (gdb) b main Breakpoint 1 at 0x4006d4: file hello.c, line 10. (gdb) c Continuing. Breakpoint 1, main () at hello.c:10 10	  hello(); (gdb) s hello () at hello.c:5 5	  printf("Hello World !\n"); (gdb) n 6	} (gdb) info registers  x0             0xe                 14 x1             0x1                 1 x2             0x0                 0 x3             0x48bf00            4767488 x4             0xfbad2a84          4222429828 x5             0x21a               538 x6             0x10                16 x7             0x7f7f7f7f7f7f7f7f  9187201950435737471 x8             0x40                64 x9             0x3fffffff          1073741823 x10            0x20000000          536870912 x11            0x10000             65536 x12            0x48b000            4763648 x13            0x410               1040 x14            0x0                 0 x15            0x48c738            4769592 x16            0x40b998            4241816 x17            0x416fc0            4288448 x18            0x0                 0 x19            0x400db8            4197816 x20            0x400e80            4198016 x21            0x0                 0 x22            0x400280            4194944 x23            0x489030            4755504 x24            0x18                24 x25            0x48b000            4763648 x26            0x48b000            4763648 x27            0x451000            4526080 x28            0x0                 0 x29            0x4000800260        274886296160 x30            0x4006c0            4196032 sp             0x4000800260        0x4000800260 pc             0x4006c0            0x4006c0 <hello+20> cpsr           0x60000000          1610612736 fpsr           0x0                 0 fpcr           0x0                 0 (gdb) bt #0  hello () at hello.c:6 #1  0x00000000004006d8 in main () at hello.c:10 (gdb) disassemble hello Dump of assembler code for function hello:    0x00000000004006ac <+0>:	stp	x29, x30, [sp, #-16]!    0x00000000004006b0 <+4>:	mov	x29, sp    0x00000000004006b4 <+8>:	adrp	x0, 0x451000 <_nl_locale_subfreeres+552>    0x00000000004006b8 <+12>:	add	x0, x0, #0x3e8    0x00000000004006bc <+16>:	bl	0x407350 <puts>    0x00000000004006c0 <+20>:	nop    0x00000000004006c4 <+24>:	ldp	x29, x30, [sp], #16    0x00000000004006c8 <+28>:	ret End of assembler dump. (gdb) c Continuing. [Inferior 1 (process 1) exited normally] (gdb)