I'm wondering, how to print float numbers in nasm using only syscalls in linux. I have the following code, but it prints only @
我想知道,如何在linux中使用syscalls在nasm中打印浮点数。我有以下代码,但它只打印@
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?
谁做对了?
2 个解决方案
#1
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
您可以使用FPU将float转换为可写字符串。以下示例采用PI(具有相当多位数的数字)和
- separates the float into an integral and a fractional part,
- converts the integral part into a BCD number by using
FBSTP
, - converts the BCD number into an ASCII string,
- appends the fractional part as ASCII string by repeatedly multiplying by 10 and converting the produced integral part,
- writes the string with kernel function 4 (sys-write).
将浮子分成一个整体和一个分数部分,
使用FBSTP将积分部分转换为BCD编号,
将BCD编号转换为ASCII字符串,
通过重复乘以10并转换生成的整数部分,将小数部分作为ASCII字符串附加,
用内核函数4(sys-write)写入字符串。
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.
将积分部分转换为BCD编号不会覆盖整个浮动范围。而且,希望在一定量的步骤之后停止转换分数部分。而且没有错误检查。
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编码浮点数的特殊特性。
#2
There is no syscall to print floats directly. Convert it to a string yourself then call write
.
没有系统调用直接打印浮动。自己将其转换为字符串然后调用write。
#1
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
您可以使用FPU将float转换为可写字符串。以下示例采用PI(具有相当多位数的数字)和
- separates the float into an integral and a fractional part,
- converts the integral part into a BCD number by using
FBSTP
, - converts the BCD number into an ASCII string,
- appends the fractional part as ASCII string by repeatedly multiplying by 10 and converting the produced integral part,
- writes the string with kernel function 4 (sys-write).
将浮子分成一个整体和一个分数部分,
使用FBSTP将积分部分转换为BCD编号,
将BCD编号转换为ASCII字符串,
通过重复乘以10并转换生成的整数部分,将小数部分作为ASCII字符串附加,
用内核函数4(sys-write)写入字符串。
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.
将积分部分转换为BCD编号不会覆盖整个浮动范围。而且,希望在一定量的步骤之后停止转换分数部分。而且没有错误检查。
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编码浮点数的特殊特性。
#2
There is no syscall to print floats directly. Convert it to a string yourself then call write
.
没有系统调用直接打印浮动。自己将其转换为字符串然后调用write。