汇编:将数字转换为32位

时间:2013-12-04 11:42:50

标签: assembly input floating-point hex 32-bit

我遇到一个程序集任务问题 - 我需要将简单数字(带逗号)输入转换为32位浮点表示并将其打印为四位十六进制数字。

感谢。

1 个答案:

答案 0 :(得分:4)

以下是NASM语法的快速示例。

  • 从stdin中读取一个数字
  • 遍历角色
  • 分别构建整数(特征)和分数(尾数)
    • 使用naive算法,其中乘以10或除以小数点的10次幂
  • 然后使用位移和查找表将结果转换为十六进制字符

我使用了SSE XMMx寄存器和函数,因为它们比x87 FPU指令更清晰,更现代。你还提到处理器是64位,所以它应该是兼容/兼容的。

您可以在ideone.com上在线阅读该程序

http://ideone.com/Q3naVN

阅读评论并尝试学习。

global _start

section .data
    ten     dq  10.0
    one     dq  1.0
    zero    dq  0.0
    negate  dq  8000000000000000h
    result  dd  0.0
    hex     db  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
    length  dd  0
    buffer  db  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

section .text

_start:
    ;;
    ;; read the fp number from stdin
    ;;
    mov     ecx, buffer
    mov     edx, 32
    call    read
    mov     dword [length], eax
    movq    xmm0, qword [zero]
    movq    xmm1, qword [zero]
    movq    xmm2, qword [ten]
    movq    xmm4, qword [ten]
    ;;
    ;; loop through 1 character at a time
    ;;
    mov     ebx, dword [length]
    test    ebx, ebx
    jz      quit        ;; there's no input
    mov     ecx, 0      ;; offset counter
    mov     edx, 0      ;; 0 for before decimal, 1 for after decimal
    mov     edi, 0      ;; 0 for positive, 1 for negative
    mov     esi, buffer
    cmp     byte [esi], '-'
    jne     process
    mov     edi, 1      ;; the number is negative
    inc     ecx
process:
    movzx   eax, byte [esi + ecx]
    cmp     al, '.'     ;; does al contain a decimal point '.'
    jne     next_check
    test    edx, edx    ;; more than 1 decimal error
    jnz     quit
    mov     edx, 1
    jmp     continue_process
next_check:
    sub     eax, '0'    ;; ascii digit to binary
    js      end_process ;; not a digit since eax is negative
    cmp     eax, 10
    jge     end_process ;; not a digit since eax is >= 10
    test    edx, edx    ;; before or after decimal
    jnz     mantissa_process
    mulsd   xmm0, xmm2  ;; result characteristic * 10
   cvtsi2sd xmm3, eax
    addsd   xmm0, xmm3  ;; result characteristic + next digit
    jmp     continue_process
mantissa_process:
    cvtsi2sd    xmm3, eax
    divsd   xmm3, xmm2  ;; next digit / current mantissa power of 10
    addsd   xmm1, xmm3  ;; result mantissa + next fraction
    mulsd   xmm2, xmm4  ;; mantissa power * 10
continue_process:
    inc     ecx
    cmp     ecx, ebx
    jl      process
end_process:
    addsd   xmm0, xmm1  ;; characteristic + mantissa
    test    edi, edi    ;; is the number supposed to be negative ?
    jz      store_result
    movq    xmm3, qword [negate]
    por     xmm0, xmm3  ;; toggle the sign bit
 store_result:
   cvtsd2ss xmm0, xmm0  ;; double (64bit) to single (32) fp
    movd    eax, xmm0
    mov     dword[result], eax
    ;;
    ;; convert result to hex
    ;;
to_hex:
    mov edi, buffer
    mov esi, hex
    mov ebx, 0
    mov eax, dword [result]
    mov bl, al
    and bl, 0fh
    mov bl, byte [esi + ebx]
    mov byte [edi + 7], bl
    shr eax, 4
    mov bl, al
    and bl, 0fh
    mov bl, byte [esi + ebx]
    mov byte [edi + 6], bl
    shr eax, 4
    mov bl, al
    and bl, 0fh
    mov bl, byte [esi + ebx]
    mov byte [edi + 5], bl
    shr eax, 4
    mov bl, al
    and bl, 0fh
    mov bl, byte [esi + ebx]
    mov byte [edi + 4], bl
    shr eax, 4
    mov bl, al
    and bl, 0fh
    mov bl, byte [esi + ebx]
    mov byte [edi + 3], bl
    shr eax, 4
    mov bl, al
    and bl, 0fh
    mov bl, byte [esi + ebx]
    mov byte [edi + 2], bl
    shr eax, 4
    mov bl, al
    and bl, 0fh
    mov bl, byte [esi + ebx]
    mov byte [edi + 1], bl
    shr eax, 4
    mov bl, al
    and bl, 0fh
    mov bl, byte [esi + ebx]
    mov byte [edi + 0], bl
    ;;
    ;; print result
    ;;
print_dword:
    mov     ecx, buffer
    mov     edx, 8
    call    write
    ;;
    ;; quit
    ;;
quit:
    call    exit

exit:
    mov     eax, 01h    ; exit()
    xor     ebx, ebx    ; errno
    int     80h
read:
    mov     eax, 03h    ; read()
    mov     ebx, 00h    ; stdin
    int     80h
    ret
write:
    mov     eax, 04h    ; write()
    mov     ebx, 01h    ; stdout
    int     80h
    ret