linux - Print floats in nasm without binding to C functions -


i'm wondering, how print float numbers in nasm using syscalls in linux. have following code, prints @

section .data   num dq 2.0   len equ $ - num  section .text global _start _start:   mov edx, len   mov ecx, num   mov ebx, 1   mov eax, 4   int 80h    mov eax, 1   int 80h 

who make right?

you can use fpu convert float writeable string. following example takes pi (a number quite few digits) and

  • separates float integral , fractional part,
  • converts integral part bcd number using fbstp,
  • converts bcd number ascii string,
  • appends fractional part ascii string repeatedly multiplying 10 , converting produced integral part,
  • writes string kernel function 4 (sys-write).

converting integral part bcd number doesn't cover whole range of float. also, desirable stop converting fractional part after amount of steps. , there no error check.

global _start  section .bss     dec_str: resb 512  section .text  double2dec:                     ; args: st(0): fpu-register convert, edi: pointer string %define control_word    word [ebp-2] %define ten             word [ebp-4] %define temp            word [ebp-4] %define integer         qword [ebp-12]      push ebp     mov ebp, esp     sub esp, 12      ; modifying rounding mode     fstcw control_word     mov ax, control_word     or ah, 0b00001100           ; set rc=11: truncating rounding mode     mov temp, ax     fldcw temp                  ; load new rounding mode      ; separate integer , fractional part & convert integer part ascii     fst     frndint                     ; st(0) integer     fsub st1, st0               ; integral part in st(0), fractional part in st(1)     call fpu2bcd2dec     fabs                        ; make fractional positive (not guaranteed fsub)      mov byte [edi], '.'         ; decimal point     add edi, 1      ; move 10 st(1)     mov ten, 10     fild ten     fxch      ; isolate digits of fractional part , store ascii     .get_fractional:     fmul st0, st1               ; multiply 10 (shift 1 decimal digit integer part)     fist word temp              ; store digit     fisub word temp             ; clear integer part     mov al, byte temp           ; load digit     or al, 0x30                 ; convert digit ascii     mov byte [edi], al          ; append string     add edi, 1                  ; increment pointer string     fxam                        ; st0 == 0.0?     fstsw ax     sahf     jnz .get_fractional         ; no: once more     mov byte [edi], 0           ; null-termination asciiz      ; clean fpu     ffree st0                   ; empty st(0)     ffree st1                   ; empty st(1)     fldcw control_word          ; restore old rounding mode      leave     ret                             ; return: edi points null-termination of string  fpu2bcd2dec:                    ; args: st(0): fpu-register convert, edi: target string      push ebp     mov ebp, esp     sub esp, 10                 ; 10 bytes local tbyte variable      fbstp [ebp-10]      mov ecx, 10                 ; loop counter     lea esi, [ebp - 1]          ; bcd + 9 (last byte)     xor bl, bl                  ; checker leading zeros      ; handle sign     btr word [ebp-2], 15        ; move sign bit carry flag , clear     jnc .l1                     ; negative?     mov byte [edi], '-'         ; yes: store minus character     add edi, 1      .l1:         mov al, byte [esi]         mov ah, al         shr ah, 4               ; isolate left nibble         or bl, ah               ; check leading 0         jz .1         or ah, 30h              ; convert digit ascii         mov [edi], ah         add edi, 1         .1:         , al, 0fh             ; isolate right nibble         or bl, al               ; check leading 0         jz .2         or al, 30h              ; convert digit ascii         mov [edi], al         add edi, 1         .2:         sub esi, 1         loop .l1      test bl, bl                 ; bl remains 0 if digits 0     jnz .r1                     ; skip next line if integral part > 0     mov byte [edi], '0'     add edi, 1      .r1:     mov byte [edi], 0           ; null-termination asciiz     leave     ret                         ; return: edi points null-termination of string  _start:      fldpi                       ; load pi     fchs                        ; change sign      mov edi, dec_str     call double2dec      mov eax,4                   ; kernel function sys-out     mov ebx,1                   ; stdout     mov ecx,dec_str             ; pointer string     mov edx, edi                ; edi points null-termination of string     sub edx, dec_str            ; length of string     int 0x80                    ; call kernel      mov eax,1                   ; kernel function sys-exit     mov ebx,0                   ; exit code, 0=normal     int 0x80                    ; call kernel 

you see number lose precision. special peculiarity of ieee-754 coded floating point numbers.


Comments