News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Floating point arguments

Started by mabdelouahab, July 30, 2019, 06:10:07 AM

Previous topic - Next topic

mabdelouahab

UASM 2.49 (Linux 64bit)    


.data
    _r8  real8   3.141592653589793115997963468544185161590576171875
    form_ db "[%.48f]",0
.code
    invoke printf,addr form_, _r8
    lea rdi, form_
    movq xmm0,_r8
    call printf


the result:
[0.000000000000000000000000000000000000000000000000][3.141592653589793115997963468544185161590576171875]

Because _r8  must pass through  XMM0

  40132a:   48 8d 3d b8 2d 00 00    lea    0x2db8(%rip),%rdi        # 4040e9 <form_>
  401331:   48 8b 35 a9 2d 00 00    mov    0x2da9(%rip),%rsi        # 4040e1 <_r8>
  401338:   33 c0                   xor    %eax,%eax
  40133a:   e8 01 fd ff ff          callq  401040 <printf@plt>
  40133f:   48 8d 3d a3 2d 00 00    lea    0x2da3(%rip),%rdi        # 4040e9 <form_>
  401346:   f3 0f 7e 05 93 2d 00    movq   0x2d93(%rip),%xmm0        # 4040e1 <_r8>
  40134d:   00
  40134e:   e8 ed fc ff ff          callq  401040 <printf@plt>



aw27

This is a good point, and for printf it would work in Windows simply because "For vararg or unprototyped functions, any floating point values must be duplicated in the corresponding general-purpose register". Linux does not bother with that duplication. This means that the bug may be in Windows as well, although the redundancy made it unnoticeable.

There are also differences between Windows and System V about how SSE registers are used in calling convention.

raymond

QuoteCode: [Select]
.data
    _r8  real8   3.141592653589793115997963468544185161590576171875
    form_ db "[%.48f]",0
.code
    invoke printf,addr form_, _r8
    lea rdi, form_
    movq xmm0,_r8
    call printf

the result:
Code: [Select]
[0.000000000000000000000000000000000000000000000000][3.141592653589793115997963468544185161590576171875]

Even though I risk being wrong at least half the time, I have to assume that "_r8" would be a memory variable where a double precision 64-bit floating point value (i.e. a "real8") will be stored as provided in the .data segment. That value will then have a precision of 53 bits, approximately equivalent to 15 decimal digits.

That assembler must be outstanding to remember (and store) all those other additional digits provided in the source code and later retrieve them when called upon to print that "real8". :undecided:
Whenever you assume something, you risk being wrong half the time.
http://www.ray.masmcode.com

aw27

 :biggrin:

This is how VS will handle it it C, so we can see the redundancy in action:


#include <stdlib.h>
#include <stdio.h>
int main()
{
00007FF7C5B21000  sub         rsp,28h 
printf("[%.48lf]", 3.141592653589793115997963468544185161590576171875);
00007FF7C5B21004  movsd       xmm1,mmword ptr [__real@400921fb54442d18 (07FF7C5B22170h)] 
00007FF7C5B2100C  lea         rcx,[string "[%.48lf]" (07FF7C5B22160h)] 
00007FF7C5B21013  movq        rdx,xmm1 
00007FF7C5B21018  call        qword ptr [__imp_printf (07FF7C5B220F0h)] 
return 0;
00007FF7C5B2101E  xor         eax,eax 
}
00007FF7C5B21020  add         rsp,28h 
00007FF7C5B21024  ret 


Output:
[3.141592653589793100000000000000000000000000000000]

Functions from the Runtime, like printf, appear to expect floating point arguments in the general purpose registers and will not bother with what the value in the SSE registers are..

mabdelouahab


#include<stdio.h>
int main()
{
printf("[%.48lf]", 3.141592653589793115997963468544185161590576171875);
return 0;
}
$ gcc -o tt.exe  testcpp.cpp -m64

[3.141592653589793115997963468544185161590576171875]

0000000000001135 <main>:
    1135:   55                      push   %rbp
    1136:   48 89 e5                mov    %rsp,%rbp
    1139:   f2 0f 10 05 d7 0e 00    movsd  0xed7(%rip),%xmm0        # 2018 <_IO_stdin_used+0x18>
    1140:   00
    1141:   48 8d 3d c0 0e 00 00    lea    0xec0(%rip),%rdi        # 2008 <_IO_stdin_used+0x8>
    1148:   b8 01 00 00 00          mov    $0x1,%eax
    114d:   e8 de fe ff ff          callq  1030 <printf@plt>
    1152:   b8 00 00 00 00          mov    $0x0,%eax
    1157:   5d                      pop    %rbp
    1158:   c3                      retq   
    1159:   0f 1f 80 00 00 00 00    nopl   0x0(%rax)


aw27

 :skrewy:

First 48 digits of PI
3.141592653589793238462643383279502884197169399375
3.141592653589793115997963468544185161590576171875

aw27

How Linux's printf transforms PI to NO-PI:


jj2007

Quote from: raymond on July 30, 2019, 12:26:34 PMThat assembler must be outstanding to remember (and store) all those other additional digits provided in the source code and later retrieve them when called upon to print that "real8". :undecided:

Raymond, you are right, it's a bit ridiculous. The culprit here is the CRT, printf spits out as many digits as you want, and it doesn't bother if that is physically possible or if it's nonsense. The Internet is full of desperate programmers fighting with that feature :tongue:

aw27

Quote from: jj2007 on July 30, 2019, 08:16:43 PM
The culprit here is the CRT, printf spits out as many digits as you want, and it doesn't bother if that is physically possible or if it's nonsense.
Can you give a Windows example? I think it uses zeros, it is not the same thing as nonsense.

mabdelouahab

Quote from: AW on July 30, 2019, 08:02:38 PM
How Linux's printf transforms PI to NO-PI:
.data
    _r8  real8  0.02
    form_ db "[%.48f]",0
.code
   
    fldpi
    fstp _r8
    lea rdi, form_
    movsd xmm0,_r8
    call printf


[3.141592653589793115997963468544185161590576171875]

.data
    _r8  real8  0.1234567890123456789012345678901234567890
    form_ db "[%.48f]",0
.code
    lea rdi, form_
    movsd xmm0,_r8
    call printf


[0.123456789012345677369886232099815970286726951599