NASM - The Netwide Assembler
NASM Forum => Programming with NASM => Topic started by: andyz74 on October 24, 2023, 03:08:48 PM
-
Hello people,
my question is, is there any (convenient) possibility to print floating point values, DESPITE printf() ?
I have problem with printf, because using gcc as linker, what I have to do in this case, produces alway error saying the "no-PIE"-stuff. Do I really have to recompile GCC with the -np-PIE flag to work for me, or is there another possibility to print-out floating point-values?
My system is Debian 12, 64 bit.
Greetings, Andy
-
Hi Andy,
Welcome to the forum!
I think there should be a way to get gcc to do what you want. Not really a "Nasm question" but you need to know the answer ! , You can print floats without the C library, too but it may not be the best use of your time.
I hope someone can cone up with the right command line to gcc.
Best,
Frank
-
Hello Frank, and thanks for the welcome-wishes! :-)
As I think all over it, i just need the printf for "seeing" my values. In fact I do not really need this written out.
But the printf-function seems to be cabaple of interpreting and displaying the packed BCD-Values.
For example I wrote a piece of code, which calculates different squareroots, which are at least partly even, without floating point. These are moved to registers, where I want to see them with a debugger. Nevertheless, I can't see my values in the register; I assume, they are BCD-packed, which I assume, printf could write them OR I find another solution. (For unpacking the packed BCD ?)
; calculates square root
; nasm -f elf64 fpu_sq_root.asm
; ld -s -o fpu_sq_root fpu_sq_root.o
[bits 64]
global _start
section .data
_msg db ' ',0ah
len_msg equ $-_msg
val1: dq 16 ;declare quad word (double precision)
val2: dq 9 ;declare quad word (double precision)
val3: dq 4 ;declare quad word (double precision)
val4: dq 1 ;declare quad word (double precision)
val5: dq 0 ;declare quad word (double precision)
val6: dq 0.25 ;declare quad word (double precision)
val7: dq 2.25 ;declare quad word (double precision)
val8: dq 6.25 ;declare quad word (double precision)
val9: dq 12.25 ;declare quad word (double precision)
section .bss
res: resq 1 ;reserve 1 quad word for result
section .text
_start:
nop
nop
nop
nop
nop
fld qword [val1] ;load value into st0
fsqrt ;compute square root of st0 and store in st0
fst qword [res] ;store st0 in result
mov rbx, [res]
nop
fld qword [val2] ;load value into st0
fsqrt ;compute square root of st0 and store in st0
fst qword [res] ;store st0 in result
mov rbx, [res]
nop
fld qword [val3] ;load value into st0
fsqrt ;compute square root of st0 and store in st0
fst qword [res] ;store st0 in result
mov rbx, [res]
nop
fld qword [val4] ;load value into st0
fsqrt ;compute square root of st0 and store in st0
fst qword [res] ;store st0 in result
mov rbx, [res]
nop
fld qword [val5] ;load value into st0
fsqrt ;compute square root of st0 and store in st0
fst qword [res] ;store st0 in result
mov rbx, [res]
nop
fld qword [val6] ;load value into st0
fsqrt ;compute square root of st0 and store in st0
fst qword [res] ;store st0 in result
mov rbx, [res]
nop
fld qword [val7] ;load value into st0
fsqrt ;compute square root of st0 and store in st0
fst qword [res] ;store st0 in result
mov rbx, [res]
nop
fld qword [val8] ;load value into st0
fsqrt ;compute square root of st0 and store in st0
fst qword [res] ;store st0 in result
mov rbx, [res]
nop
fld qword [val9] ;load value into st0
fsqrt ;compute square root of st0 and store in st0
fst qword [res] ;store st0 in result
mov rbx, [res]
nop
nop
nop
nop
mov rax,1
int 80h
;end program
=> Squareroots of the val's are computed and one after each stored in RBX.
If I debug the program with radare2, I see senseless numbers in RBX.
Are they packed BCD? If yes, how to unpack ?
Greetz and thanks, Andy
PS : the many "nop" are for me to be able to get orientation while debugging...
-
You can separate the integer part from the fractional part with cvttss2si or cvttsd2si, and subtract the original values to get the fractional part (remember to obtain the absolute values). Then, for integer part, you can obtain the # of decimal algarisms using log10, and divide the integer value by 10, in sequence, util you get a zero quotient - getting the actual algarisms... For the fractional part, you just need to multiply them by 10 (until get 0.0 or the # of algarisms you want).
There are faster ways...
-
You can separate the integer part from the fractional part with cvttss2si or cvttsd2si, and subtract the original values to get the fractional part (remember to obtain the absolute values). Then, for integer part, you can obtain the # of decimal algarisms using log10, and divide the integer value by 10, in sequence, util you get a zero quotient - getting the actual algarisms... For the fractional part, you just need to multiply them by 10 (until get 0.0 or the # of algarisms you want).
There are faster ways...
Ah, many thanks, this is a good way to start! :-)
-
OK, so I read a lot, and I try a lot, but unfortunately without much success. I would be very pleased, if someone could help me further here.
I give a float variable "para_f" with the value 12.34
Then I get the integer part with
print_float:
cvttsd2si rdx, [para_f] ; rdx ist jetzt ganzzahlteil
ret
...and with my own print-routine, I can print out the integer part 12.
Then I have a second part, where I try to multiply the "para_f" by 100 and afterwards print out, but I get a "0"
print_floatmul100:
movsd xmm0, [para_f] ; single-prec-float nach xmm0
mov dword [varq], 100 ; 100 nach varq und dann nach xmm1
movsd xmm1, [varq]
mulsd xmm0, xmm1
movsd [varq], xmm0 ;
cvttsd2si rdx, [varq]
ret
I see in debugger, that xmm0 is at last point 4d2 hexadecimal, what is 1234 in decimal. This is correct.
But then I get output zero, with my print-routine.
Does anyone see, what is my failure, please?
-
Does anyone see, what is my failure, please?
Yep... Will be 0...
Let's take a look at 12.34 in bynary:
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main( void )
{
double d = 12.34;
uint64_t *p = (uint64_t *)&d;
printf( "%#" PRIx64 "\n", *p );
}
So, compiling, linking and running:
$ cc -O2 -o test test.c
$ ./test
0x4028ae147ae147ae
A floating point value is encoded as described here: https://en.wikipedia.org/wiki/Double-precision_floating-point_format
So, 100 (integer) is a double encoded as ~4.94066e-322 (almost 0). What you meant do to is:
; Input xmm0
; Ouput rax
fmult100_trunc:
mulsd xmm0,[.m100]
cvttsd2si rax,xmm0
ret
.m100:
dq 100.0 ; ".0" is necessary here.
PS: Try to avoid using "memory" variables since you have 16 integer registers and 16 xmm registers available.
PS2: This kind of code works only if the floating point value is in 'integer' range. But notice that a single precision floating point value has a range way larger than that. Take a look at this paper: https://legacy.cs.indiana.edu/~dyb/pubs/FP-Printing-PLDI96.pdf
-
Many thanks, I corrected my code now, and it does, what I want. :-)