求助:修复x86架构NASM汇编程序的十六进制数输出问题
x86汇编实现32位十六进制数打印问题排查
需求:编写x86架构的NASM汇编程序,通过write系统调用在标准输出打印32位十六进制数,效果等价于C语言的printf("%x\n",123456)。自己编写的代码无法正常运行,附上代码求助,本人是汇编新手,缺乏调试思路。
原代码:
section .data message db '0x',0 number dq 123456 section .text global _start _start: ; Print "0x" mov eax, 4 mov ebx, 1 mov ecx, message mov edx, 2 int 0x80 ; Print number in hex mov eax, number push eax call print_hex add esp, 4 ; Exit mov eax, 1 xor ebx, ebx int 0x80 ; Function to print number in hex print_hex: push ebx push edx mov ebx, 16 mov edx, 0 mov ecx, 0 print_hex_loop: xor edx, edx div ebx add edx, '0' cmp edx, '9' jg print_hex_digit push edx inc ecx test eax, eax jne print_hex_loop print_hex_done: mov eax, 4 mov ebx, 1 mov edx, ecx int 0x80 print_hex_pop_loop: pop edx mov [esp], edx inc esp dec ecx jne print_hex_pop_loop pop edx pop ebx ret print_hex_digit: add edx, 'A' - '9' - 1 jmp print_hex_done
代码中的关键错误
- 变量取值错误:
number定义为dq(8字节),但mov eax, number取的是变量的内存地址而非数值,正确写法应为mov eax, [number]。另外因为需求是32位数,number用dd(4字节)更合适。 - 字母转换流程错误:当数字大于9需要转换为字母时,
print_hex_digit直接跳转到print_hex_done,导致后续循环中断,转换后的字符没有入栈计数,直接进入输出逻辑,完全跳过了剩余数字的处理。 - 输出逻辑错误:
print_hex_done中的write调用未设置ecx指向有效输出缓冲区(当前ecx是字符计数器),后续的print_hex_pop_loop直接操作esp修改栈内容,不仅破坏栈结构,还没有把字符正确传递给write系统调用。
修正后的代码
section .data prefix db '0x' hex_chars db '0123456789abcdef' ; 小写十六进制字符集,要大写换ABCDEF newline db 0xa number dd 123456 ; 32位变量 section .bss hex_buf resb 8 ; 32位十六进制最多8位字符 section .text global _start _start: ; 打印前缀"0x" mov eax, 4 mov ebx, 1 mov ecx, prefix mov edx, 2 int 0x80 ; 打印十六进制数 mov eax, [number] call print_hex ; 打印换行 mov eax, 4 mov ebx, 1 mov ecx, newline mov edx, 1 int 0x80 ; 退出程序 mov eax, 1 xor ebx, ebx int 0x80 ; 功能:打印eax中的32位十六进制数 print_hex: push ebx push ecx push edx push esi mov esi, hex_buf + 7 ; 从缓冲区末尾开始填充(十六进制高位在左,低位在右) mov ecx, 8 ; 32位固定8位十六进制字符 print_hex_loop: xor edx, edx mov ebx, 16 div ebx ; eax = eax/16,edx = 余数 mov bl, [hex_chars + edx] ; 取对应字符 mov [esi], bl dec esi dec ecx jnz print_hex_loop ; 输出缓冲区内容 mov eax, 4 mov ebx, 1 mov ecx, hex_buf mov edx, 8 int 0x80 pop esi pop edx pop ecx pop ebx ret
修正说明
- 使用固定大小的缓冲区存储十六进制字符,从高位到低位填充,避免栈操作的混乱
- 直接通过字符集数组索引获取十六进制字符,逻辑更简洁不易出错
- 保留了换行输出,和
printf("%x\n", ...)的行为一致 - 严格维护栈平衡,避免寄存器污染
内容的提问来源于stack exchange,提问作者suchypisarz
相关产品推荐
相关产品推荐

