Trying to convert float to hexadecimal in nasm
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.