简体   繁体   English

打印在nasm中浮动而未绑定到C函数

[英]Print floats in nasm without binding to C functions

I'm wondering, how to print float numbers in nasm using only syscalls in linux. 我想知道如何在Linux中仅使用syscalls在nasm中打印浮点数。 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

Who to make it right? 谁做对了?

You can use the FPU to convert a float into a writeable string. 您可以使用FPU将浮点数转换为可写字符串。 The following example takes PI (a number with quite a few digits) and 以下示例采用PI(具有很多位数的数字)和

  • separates the float into an integral and a fractional part, 将浮子分为整数部分和小数部分,
  • converts the integral part into a BCD number by using FBSTP , 通过使用FBSTP将整数部分转换为BCD编号,
  • converts the BCD number into an ASCII string, 将BCD号码转换为ASCII字符串,
  • appends the fractional part as ASCII string by repeatedly multiplying by 10 and converting the produced integral part, 通过重复乘以10并转换产生的整数部分,将小数部分附加为ASCII字符串,
  • writes the string with kernel function 4 (sys-write). 用内核函数4(sys-write)写入字符串。

Converting the integral part into a BCD number doesn't cover the whole range of a float. 将整数部分转换为BCD编号并不能覆盖浮点数的整个范围。 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

You will see that the number quickly lose precision. 您将看到该数字很快失去精度。 This is a special peculiarity of IEEE-754 coded floating point numbers. 这是IEEE-754编码的浮点数的特殊特性。

There is no syscall to print floats directly. 没有系统调用可直接打印浮点数。 Convert it to a string yourself then call write . 自己将其转换为字符串,然后调用write

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM