打印在nasm中浮动而未绑定到C函数 [英] Print floats in nasm without binding to C functions

查看:77
本文介绍了打印在nasm中浮动而未绑定到C函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道如何在Linux中仅使用syscalls在nasm中打印浮点数.我有以下代码,但仅打印@

I'm wondering, how to print float numbers in nasm using only syscalls in linux. I have the following code, but it prints only @

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

谁做对了?

推荐答案

您可以使用FPU将浮点数转换为可写字符串.以下示例采用PI(具有很多位数的数字)和

You can use the FPU to convert a float into a writeable string. The following example takes PI (a number with quite a few digits) and

  • 将浮子分离为整数和小数部分,
  • 使用FBSTP
  • 部分转换为BCD编号,
  • 将BCD号码转换为ASCII字符串,
  • 通过重复乘以10并转换产生的整数部分,将小数部分附加为ASCII字符串.
  • 使用内核函数4(sys-write)写入字符串.

将整数部分转换为BCD编号并不能覆盖浮点数的整个范围.同样,希望在一定数量的步骤之后停止转换小数部分.而且没有错误检查.

Converting the integral part into a BCD number doesn't cover the whole range of a float. Also, it is desirable to stop converting the fractional part after a certain amount of steps. And there is no error check.

global _start

section .bss
    dec_str: resb 512

section .text

double2dec:                     ; Args: ST(0): FPU-register to convert, EDI: pointer to 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 and fractional part & convert integer part into ASCII
    fst
    frndint                     ; ST(0) to integer
    fsub st1, st0               ; Integral part in ST(0), fractional part in ST(1)
    call fpu2bcd2dec
    fabs                        ; Make fractional positive (not guaranteed by fsub)

    mov byte [edi], '.'         ; Decimal point
    add edi, 1

    ; Move 10 to st(1)
    mov TEN, 10
    fild TEN
    fxch

    ; isolate digits of fractional part and store ASCII
    .get_fractional:
    fmul st0, st1               ; Multiply by 10 (shift one decimal digit into integer part)
    fist word TEMP              ; Store digit
    fisub word TEMP             ; Clear integer part
    mov al, byte TEMP           ; Load digit
    or al, 0x30                 ; Convert digit to ASCII
    mov byte [edi], al          ; Append it to string
    add edi, 1                  ; Increment pointer to string
    fxam                        ; ST0 == 0.0?
    fstsw ax
    sahf
    jnz .get_fractional         ; No: once more
    mov byte [edi], 0           ; Null-termination for ASCIIZ

    ; clean up FPU
    ffree st0                   ; Empty ST(0)
    ffree st1                   ; Empty ST(1)
    fldcw CONTROL_WORD          ; Restore old rounding mode

    leave
    ret                             ; Return: EDI points to the null-termination of the string

fpu2bcd2dec:                    ; Args: ST(0): FPU-register to convert, EDI: target string

    push ebp
    mov ebp, esp
    sub esp, 10                 ; 10 bytes for local tbyte variable

    fbstp [ebp-10]

    mov ecx, 10                 ; Loop counter
    lea esi, [ebp - 1]          ; bcd + 9 (last byte)
    xor bl, bl                  ; Checker for leading zeros

    ; Handle sign
    btr word [ebp-2], 15        ; Move sign bit into carry flag and clear it
    jnc .L1                     ; Negative?
    mov byte [edi], '-'         ; Yes: store a minus character
    add edi, 1

    .L1:
        mov al, byte [esi]
        mov ah, al
        shr ah, 4               ; Isolate left nibble
        or bl, ah               ; Check for leading zero
        jz .1
        or ah, 30h              ; Convert digit to ASCII
        mov [edi], ah
        add edi, 1
        .1:
        and al, 0Fh             ; Isolate right nibble
        or bl, al               ; Check for leading zero
        jz .2
        or al, 30h              ; Convert digit to ASCII
        mov [edi], al
        add edi, 1
        .2:
        sub esi, 1
        loop .L1

    test bl, bl                 ; BL remains 0 if all digits were 0
    jnz .R1                     ; Skip next line if integral part > 0
    mov byte [edi], '0'
    add edi, 1

    .R1:
    mov byte [edi], 0           ; Null-termination for ASCIIZ
    leave
    ret                         ; Return: EDI points to the null-termination of the 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 to string
    mov edx, edi                ; EDI points to the null-termination of the string
    sub edx, dec_str            ; Length of the string
    int 0x80                    ; Call kernel

    mov eax,1                   ; Kernel function sys-exit
    mov ebx,0                   ; Exit code, 0=normal
    int 0x80                    ; Call kernel

您将看到该数字很快失去精度.这是IEEE-754编码的浮点数的特殊特性.

You will see that the number quickly lose precision. This is a special peculiarity of IEEE-754 coded floating point numbers.

这篇关于打印在nasm中浮动而未绑定到C函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆