NASM中无法存入单个寄存器的数值的十进制表示方法问询
处理寄存器中超大数值的十进制转换问题
当寄存器中存储普通数值时,转换为十进制数位的操作很简单——反复除以10并保存余数即可,比如32位寄存器的示例代码:
lp: cmp eax, 0 ; 判断是否处理完成 je print inc ecx div dword [divider] ; divider为值10的双字变量 mov [result + ecx - 1], dl xor edx, edx jmp lp
但如果数值大到单个寄存器无法容纳,比如执行mul ebx后结果超出32位范围,存储在edx:eax的64位组合寄存器中,该如何完成十进制转换?
核心思路:利用div指令的多寄存器除法特性
x86架构的div指令本身就支持把edx:eax作为64位被除数,除以32位源操作数,商存入eax、余数存入edx。我们可以直接利用这个特性实现超大数值的十进制转换,步骤如下:
- 初始化计数器、结果缓冲区等变量
- 循环执行除法操作,直到
edx和eax同时为0:- 执行
div dword [divider](divider值为10),此时edx即为当前十进制数位的余数(0-9) - 将余数转换为ASCII字符(加0x30),存入结果缓冲区
- 重置
edx为0,继续下一次循环
- 执行
- 由于存储时是从低位到高位逆序存入,最后需要反转缓冲区得到正确顺序
示例代码实现
section .data divider dd 10 result times 20 db 0 ; 64位十进制数最多20位,预留足够缓冲区 count dd 0 section .text global _start _start: ; 假设edx:eax已存储待转换的64位数值 xor ecx, ecx ; 初始化数位计数器 convert_loop: cmp eax, 0 cmp edx, 0 je reverse_output ; edx和eax全为0时结束转换 div dword [divider] ; edx:eax / 10,商在eax,余数在edx add dl, 0x30 ; 余数转ASCII字符 mov [result + ecx], dl inc ecx xor edx, edx ; 重置edx,为下一次除法做准备 jmp convert_loop reverse_output: mov [count], ecx ; 保存总位数 mov esi, result mov edi, result + ecx - 1 shr ecx, 1 ; 反转循环次数为位数的一半 reverse_loop: cmp ecx, 0 je print_result mov al, [esi] mov bl, [edi] mov [esi], bl mov [edi], al inc esi dec edi dec ecx jmp reverse_loop print_result: ; Linux x86系统调用输出结果 mov eax, 4 mov ebx, 1 mov ecx, result mov edx, [count] int 0x80 exit: mov eax, 1 xor ebx, ebx int 0x80
关键细节说明
div指令的原生支持:无需额外实现多位数除法,直接利用指令特性处理edx:eax的64位被除数- ASCII转换:余数范围0-9,加上0x30即可对应'0'-'9'的ASCII码
- 缓冲区反转:因为每次获取的是最低位,存储顺序为逆序,必须反转才能得到正常的十进制字符串
内容的提问来源于stack exchange,提问作者Fyodor
相关产品推荐
相关产品推荐

