Search code examples
linuxassemblynasmx86-64

Float point to display hexadecimal x86-64 nasm linux


Trying to convert float to hexadecimal in nasm


Solution

  • How to convert a DWORD (single precision floating point number) to hexadecimal

    The hexadecimal notation is just a simplification of the binary notation. Four bits at a time form one hexadecimal digit.

    With

    SA: dd 500.312
    

    NASM converts the decimal number 500.312 into the internal format "DWORD" - a bunch of 32 bits:

    01000011111110100010011111110000
    

    Group them to 4-bit groups (nibbles) and convert every group to decimal:

    0100 0011 1111 1010 0010 0111 1111 0000
       4    3   15   10    2    7   15    0
    

    The easiest way to get hexadecimal digits is a lookup table. A string is an appropriate way to form an array of 16 hexadecimal characters:

    hex db "0123456789ABCDEF"
    

    Interprete the numbers of each nibble as index of the array ([hex+index]) and store it in a string to be outputted.

    A challenge is to isolate the nibbles from left to right. You can us the ROL,4 instruction, mov the result to another register and isolate the nibble with AND 0x0F. Another way is to use SHLD. When you have isolated the nibble you have also the index of the hex array.

    Example:

    BITS 64
    DEFAULT rel
    GLOBAL _start
    
    SECTION .data
        SA dd 500.312               ; Single floating point number
        hex db "0123456789ABCDEF"   ; Array of 16 characters
        lf db 10                    ; New line
    
    SECTION .bss
        outstr resb 16              ; Array of 16 unitialized bytes
    
    SECTION .text
    
    DWORD_to_hex:                   ; ARG: EAX: DWORD value, ESI: Pointer to an array of at least 8 bytes
        xor esi, esi                ; RSI = 0 (access to ESI clears the upper DWORD of RSI)
        mov ecx, 8                  ; RCX = 8
        .LL3:
        xor sil, sil                ; Clear lowest byte of RSI
        shld esi, eax, 4            ; Copy 4 leftmost bits from EAX to ESI
        shl eax, 4                  ; Shift EAX accordingly
        mov dl, [hex + esi]         ; Get a hexadecimal character
        mov [edi], dl               ; Store the character
        add edi, 1                  ; Increment the pointer to outstr
        loop .LL3                   ; Loop RCX times
    
        ret
    
    _start:                         ; Entry point - here starts the program
    
        mov eax, [SA]               ; Single floating point number coded as DWORD
        mov rdi, outstr             ; OFFSET outstr
        call DWORD_to_hex
    
        ; Show hex (8 characters)
        mov eax, 1                  ; SYS_WRITE
        mov edi, 1                  ; STDOUT
        mov rsi, outstr             ; Message address
        mov edx, 8                  ; Number of bytes to display
        syscall                     ; Call Linux
    
        ; New line
        mov eax, 1                  ; SYS_WRITE
        mov rdi, 1                  ; STDOUT
        mov rsi, lf                 ; Message address
        mov edx, 1                  ; Number of bytes to display
        syscall                     ; Call Linux
    
        ; Exit (0)
        mov eax, 60                 ; SYS_EXIT
        mov edi, 0                  ; Exitcode
        syscall                     ; Call Linux / no return
    

    Adjust these steps to get the hexadecimal representation of a QWORD (64 bits) which represents a double precision flosting point number.