汇编调试方式之:通过串口转义输出寄存器的值(以riscv64为例)

前两天在调试DragonOS的riscv引导代码的时候,想在真机上获取寄存器的值,就找到了这篇帖子,非常有用,就把里面的代码提取出来,在此记录。

因为在汇编里面难以对字符串进行格式化操作,因此可以考虑把寄存器的值转义一下,然后输出到串口,再使用一个C程序把它转义回来。方法如下:

编码函数

首先在汇编里面定义这样一个函数:

// 要打的值输入到a0
__do_show_val:
	// todo: 为了保护寄存器,这里应当添加压栈操作,
	// 把函数使用到的寄存器都保存一下,在ret之前弹栈
	// 实际使用时,如果需要多次调用本函数,那么一定要补充
	// 压栈的代码。
	mv t0,a0
	li t1, 0x0F
	li t2, 16
	
2:	beqz t2, 3f
	and t3, t0, t1
	addi a0, t3, 0x41
	li   a7, 0x01
	ecall
	srli t0, t0, 4
	addi t2, t2, -1
	j 2b
3:	li a0, 0x0A	# 打一个回车, 方便查看
	li   a7, 0x01
	ecall
	
	ret

当要使用上述代码的时候,就把要打印的寄存器的值,移动到a0,然后call这个函数即可。

// 示例:打印t3

mv a0,t1
call __do_show_val

然后运行的时候,就会输出一个十六位的字符串。比如:“PAAAIFPDAAAAAAAA“

解码

接着我们需要写个C程序对上述输出的数据进行解码。程序如下:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>

void read_each()
{
    char a[17] = {};
    while (1)
    {
        printf("Enter:");
        scanf("%s", a);
        for (int i = 15; i >= 0; i--)
        {
            printf("%1X", a[i] - 'A');
        }
        printf("\n");
        printf("\n");
    }
}

int main(int argc, const char *argv[])
{
    read_each();
}

运行

把上述数据输入到C程序内,就能输出寄存器值了:

longjin@longjin-server:~/$ ./show
Enter:PAAAIFPDAAAAAAAA
000000003F58000F

Enter:

所以我们可以看到这个寄存器的值就是“3F58000F“。

1 个赞