Jump to content
  • Advertisement
Sign in to follow this  
Aghis

asm + float

This topic is 4896 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Greetings. I have a question about the low-level workings of the C language. Knowing that the size of the single-precision floating point type (i.e. float) in C is 4 bytes, I assumed that a function which accepts a float value as an argument must be written to access it in the 4 bytes preceding the return address, like so : Application stack chart (assume that each row in the stack is 4 bytes long) : | ................... | | ................... | | float argument | | return address | <- upon entrance to the function, ESP points here Setting myself to the task of optimizing a function by hand-coding it in assembly and calling it from C, I was proven wrong. I discovered that the caller code was providing my function with a 8-byte float value. The compiler I used is MSVC.NET 2003 and the asm listing for the function call was the following :
004173DF  fld         dword ptr [f]          ; pushes the float unto the fpu stack
004173E2  mov         esi,esp                ; saves esp for a later check
004173E4  sub         esp,8                  ; makes room for a 8-byte buffer on the application stack
004173E7  fstp        qword ptr [esp]        ; pops the fpu stack on the application stack
004173EA  call        dword ptr [pass_float] ; calls the function

where f is the float argument and pass_float is the function's name (i.e. in C : pass_float(f);) Can anyone explain why 8 bytes of stack space are used to pass a 4-byte variable ? Thanks.

Share this post


Link to post
Share on other sites
Advertisement
Well, a float is not guaranteed to be 4 bytes. It generally is but might not be.

Now as for the issue at hand, I would poke a wild guess that perhaps the CPU only operates on doubles (just switching the percision but not the actual data size for calculations) and the extra 4 bytes are just cut off when they are used?

Share this post


Link to post
Share on other sites
Quote:
Original post by SOS
Now as for the issue at hand, I would poke a wild guess that perhaps the CPU only operates on doubles (just switching the percision but not the actual data size for calculations) and the extra 4 bytes are just cut off when they are used?


It crossed my mind but how could this explain that the transition to 8-byte length occures only to pass variables through the stack?

This line
004173DF fld dword ptr [f]

shows that f was a normal 4-byte float variable in C.

Share this post


Link to post
Share on other sites
Hmm... true, that seems odder.

Perhaps the calling convention used for the function requires 8-byte floats? But that's unlikely... I've never heard of such a requirement. And if it's not an exported function, it should be optimized away without regard to the calling convention.

This is compiled in release mode, right?

Share this post


Link to post
Share on other sites
@_Madman_ : I have 32-bit CPU and compiler.

Actually, this might be of importance... the asm function has been exported to a DLL and is imported into C code through LoadLibrary and GetProcAddress. I am an ass for not having mentioned it earlier. Does it give you any clues?

Share this post


Link to post
Share on other sites
There are basically 2 calling conventions that appear in usual program. __fastcall and __stdcall, none of them has anything to do with float sizes...

EDIT: there are c and pascal conventions, but anyway they only tell stack order (front to back or opposite) and stack cleanup param.

Share this post


Link to post
Share on other sites
One more thing : MSVC forced me to use the _stdcall convention. The asm code returns with ret 8 to perform stack cleanup.

As for configurations : the C code is in debug mode and the assembly code was compiled through NASM with no optimization requests. I really don't know what effect this has (whether debug information is stored) but I COULD trace in from C, so I guess the asm code was in debug mode too.

Share this post


Link to post
Share on other sites
AFAIK, If it's debug mode, then you get allocated additional space after arrays and variables that is checked for buffer overrun later.
Try release, breakpoints and asm source should work... __stdcall is standart and best convention if you use stack, __fastcal is used when you use registers to pass parameters...

EDIT: you can try to write in those 'free' 4 bytes and I bet you'll get msg that stack around variable xxx is corrupted.

Share this post


Link to post
Share on other sites
Quote:
Original post by _Madman_
EDIT: you can try to write in those 'free' 4 bytes and I bet you'll get msg that stack around variable xxx is corrupted.


I wrote on all 8-bytes and got no message. It the extra 4 bytes are used for debugging, why are they not added to integers as well?

Looking for a way around the problem, I decided to call a C function from assembly and found out that the only way to successfully pass a float is by allocating 8 bytes on the stack.

For example, I called printf with a 4-byte argument and got 0.000000 on the screen, although the argument was not 0.0f. Interestingly enough, there was no error return value. The same call with an 8-byte argument of the same value printed the correct digits.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!