Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories

Welcome to the new platform of Programmer's Heaven! We apologize for the inconvenience caused, if you visited us from a broken link of the previous version. The main reason to move to a new platform is to provide more effective and collaborative experience to you all. Please feel free to experience the new platform and use its exciting features. Contact us for any issue that you need to get clarified. We are more than happy to help you.

x86 FPU

shaolin007shaolin007 Posts: 1,018Member
I have never used FPU instructions so I am starting from scratch. I am aware that there are 8 registers 80bit wide and they are ordered like a stack. That is about it. I have been trying to add 2 decimal numbers together but not getting the correct result.

My FASM code:

[code]format PE
entry start

Include 'win32a.inc'

section '.text' code readable executable

start:

finit
fld [num1]
fadd [num2]
fst [num3]
cinvoke printf, decimalnum, num3

cinvoke getchar
invoke ExitProcess, 0


section '.data' data readable writable

decimalnum db "%.4E",0

num1 dq 2.345
num2 dq 5.678
num3 rq 1
section '.idata' import data readable writeable

library msvcrt, 'msvcrt.dll',
kernel32, 'kernel32.dll'

import msvcrt,
printf, 'printf',
getchar, 'getchar'

import kernel32,
ExitProcess, 'ExitProcess'[/code]

What am I doing wrong?

Comments

  • AsmGuru62AsmGuru62 Posts: 6,519Member
    [color=Blue]Welcome to the FPU coders club!
    I just wrote huge program with FPU (STAR TREK clone from PDP-11).

    Few things I want to ask:
    1. When you store the result you use FST - that's good, however ST0 register still has the value in it, when you proceed with printf() and that may cause exceptions down the road (probably because printf for sure also use the FPU stack). I suggest trying FSTP instead of FST.

    2. Are you sure about "%.4E" format? Try to test it in C code to be sure. The result may be correct, but format may be an issue.

    3. When you pass num3 to printf() - you pass an address, correct? If you remember C - how exactly printf "knows" that float point value is passed or int value is passed. I am not sure if it passed by address. Also, I believe it is PUSH-ed onto stack (see cinvoke macro code) and how exactly 10-byte value can be PUSH-ed? I suggest disassembling the C example of printing a double value and check what happens.

    4. You have PE format generated by FASM and PE file should not have a CONSOLE attached by default. Do you see anything actually printed on a console window? If you do, than printf() probably checks for console and if not there - attaches it. I just want to check.
    [/color]
  • shaolin007shaolin007 Posts: 1,018Member
    1. Ok makes sense to pop the value off the fpu. Thanks for the tip.

    2. Not sure about it. Are you talking about the precision or the engineering notation?

    3. Hmmm, I guess printf wouldn't know. I don't have a C compiler installed but could you recommend a free compiler to use?

    4. I didn't know I had to specify Console. All of my programs seemed to function ok though without specifying it.

    When I run the program, I always get this result no matter what:

    1.4424E+257

    Could you show me an example of how you add two reals using the FPU? Something simple.
  • AsmGuru62AsmGuru62 Posts: 6,519Member
    [color=Blue]You adding them properly - I am sure of that. The issue is in formatting it - the argument is 10 bytes long and it has to be properly passed.

    When I was doing it - I have written a small function of my own to print any value with 2 digits of precision (after a decimal period), because that is what was needed in a game.

    It is 8:20 AM, so I need to get to work, but I'll experiment with printf (there is also wsprintf - from Win32 API) and see if I can get you a solution.

    Did you try a Visual Studio Express?
    It should be free. If not, then get Dev C++ - it is not perfect, but you can disassemble a call to printf with double value and check that out.[/color]
  • shaolin007shaolin007 Posts: 1,018Member
    I think I figured it out. I saw a single precision example on the FASM forums:

    [code]
    sub esp, 4
    fstp dword[esp]
    [/code]

    So I figured, since I want double precision, I just sub esp, 8 then fstp [esp]. The program works but do you see any potential problems in it still?

    By the way, I specified CONSOLE this time and changed the printf specifier to %4.3lf, per your inquiries.

    [code]
    format PE CONSOLE
    entry start

    Include 'win32a.inc'

    section '.text' code readable executable

    start:

    finit
    fld [num1]
    fadd [num2]
    sub esp, 8
    fstp qword [esp]

    cinvoke printf, decimalnum
    cinvoke getchar
    invoke ExitProcess, 0


    section '.data' data readable writable

    decimalnum db "%4.3lf",0

    num1 dq 2.345
    num2 dq 5.678

    section '.idata' import data readable writeable

    library msvcrt, 'msvcrt.dll',
    kernel32, 'kernel32.dll'

    import msvcrt,
    printf, 'printf',
    getchar, 'getchar'

    import kernel32,
    ExitProcess, 'ExitProcess'
    [/code]
  • AsmGuru62AsmGuru62 Posts: 6,519Member
    [color=Blue]Compiler does the same - I just checked. However, AFTER the call to printf - the compiler cleans stack as:[/color]
    [code]
    ADD ESP, 0Ch
    [/code]
    [color=Blue]So, if you look at the code:[/color]
    [code]
    printf (format, dblValue);
    [/code]
    [color=Blue]It is obvious, that format is an address to text = 4 bytes and double takes 8 bytes - that is how it cleans out 12 bytes. I am not sure how, cinvoke works in FASM - I do not use the high-level stuff. Does it clean whatever passed to printf? If it does then you simply need to return ESP to the location it was before the whole thing:[/color]
    [code]
    ADD ESP, 8
    [/code]
  • shaolin007shaolin007 Posts: 1,018Member
    Ran it through OllyDebug and it doesn't clean the stack up properly. It adds only 4 to esp. Cinvoke cleans the stack for you if the parameters are followed directly after the function declaration. Uses the __cdecl convention.


    I need to clean the stack as you pointed out:

    [code]
    add esp, 8
    [/code]


    Thanks for catching that. Corrupting the stack could of made trouble for me later on.
Sign In or Register to comment.