如何打印CPU寄存器r10到屏幕?汇编代码问题排查及疑问解答
你的x86汇编代码问题分析
核心错误点
1. 系统调用参数与寄存器位数不兼容
你使用的是32位Linux系统调用int 0x80,却混用了r10、rcx这类64位寄存器,这完全不符合32位调用规范:
- 32位系统调用要求用32位寄存器:
eax存调用号,ebx、ecx、edx传递参数,不能用64位寄存器。 sys_write(调用号4)需要ecx指向可打印的ASCII字节序列地址,edx指定打印长度,但你注释掉了edx的赋值;同时r10中是二进制数字,直接存入内存不是可打印的ASCII字符——数字必须转换为ASCII字符串才能被屏幕正确显示,直接存二进制值会输出乱码或不可见字符。
2. 变量赋值语法错误
mov know, r10不符合x86汇编规则,目的操作数必须在前,源操作数在后,正确写法是mov [know], r10;另外know是resd 16定义的32位双字数组,r10是64位寄存器,直接存储会截断高位,建议用mov [know], r10d只存32位部分。
3. 比较操作数语法错误
cmp rax, ffff中的ffff是未定义符号,汇编器无法识别,十六进制数必须加0x前缀,写成0xffff。
对问题的逐个解答
是否必须将r10存入变量再放入rcx才能打印?
不是必须,但要明确:sys_write要求传入的是内存中可打印ASCII数据的地址。如果r10中是数字,你需要先把它转换为ASCII字符串存入内存(比如know),再将地址传给ecx;直接传递寄存器的二进制值不行,因为二进制数字不是ASCII字符,屏幕只能识别ASCII对应的字符。je指令是否表示当rax等于ffff时跳转?
je是相等则跳转,它会检查上一条cmp指令设置的标志位,只要rax与比较操作数相等,就会跳转到END,逻辑是对的,但前提是cmp的操作数语法正确(加0x前缀)。ffff是否需要添加后缀x?
必须加,汇编器中十六进制数的标准写法是0x开头,比如0xffff,否则会被当成未定义的标签,导致汇编报错。
修正后的简易示例(32位模式)
如果要实现循环递增并打印数字,需要补充ASCII转换逻辑,以下是简化的32位版本:
section .data newline db 0xA ; 换行符 len_newline equ $ - newline section .bss buffer resb 10 ; 存储转换后的ASCII字符串 section .text global _start _start: mov ecx, 0 ; 用32位寄存器ecx替代r10 REDO: inc ecx ; 将ecx中的数字转换为ASCII字符串 mov esi, buffer + 9 ; 从缓冲区末尾开始填充 mov ebx, 10 ; 十进制进制 convert: xor edx, edx div ebx add dl, '0' ; 余数转ASCII字符 mov [esi], dl dec esi test eax, eax jnz convert ; 打印转换后的字符串 mov eax, 4 mov ebx, 1 mov ecx, esi + 1 ; 字符串起始地址 mov edx, buffer + 10 - (esi + 1) ; 字符串长度 int 0x80 ; 打印换行 mov eax,4 mov ebx,1 mov ecx,newline mov edx,len_newline int 0x80 ; 判断是否达到0xffff cmp ecx, 0xffff je END jmp REDO END: ; 退出程序(必须添加,否则会崩溃) mov eax, 1 xor ebx, ebx int 0x80
内容的提问来源于stack exchange,提问作者NanoNebulas
相关产品推荐
相关产品推荐

