Skip to main content
GameDev.net gamedev.net
🔒 Locked

x86 FPU code

Started by Shannon Barber May 21, 2002 at 10:04 PM 10 replies 400+ views
Original Post
Shannon Barber
Shannon Barber
It''s a long painful story: I''m writing some C++ code that needs to call some exported functions from Delphi - only the rat bastards _didn''t_ give the exports a stdcall convetion - they left them the Delphi default, __register. I have almost everything working, except when I load a double and go to push it on the stack (not the FPU stack, the progam stack) it always emits the op code to push float. Is there a way I can tell it to push a qword, not a dword? I looked at some of the Delphi disass, and it''s a slightly different op code - very similar to how mov translates into a dozen or so op codes.
The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
ggs
ggs
You might what to keep in mind that the register calling conversion :

Parameter order : Left-to-right
Clean-up : Routine
Passes parameters in registers:Yes

They get put in the ''eax'',''ebx'',''ecx'' registers, only if the parameter fits.
DrPizza
DrPizza
You don''t push quadwords, you can''t. You push a pair of doublewords instead.

Take a look at what VC++ generates for functions taking doubles and you will see for yourself.
char a[99999],*p=a;int main(int c,char**V){char*v=c>0?1[V]:(char*)V;if(c>=0)for(;*v&&93!=*v;){62==*v&&++p||60==*v&&--p||43==*v&&++*p||45==*v&&--*p||44==*v&&(*p=getchar())||46==*v&&putchar(*p)||91==*v&&(*p&&main(0,(char**)(--v+2))||(v=(char*)main(-1,(char**)++v)-1));++v;}else for(c=1;c;c+=(91==*v)-(93==*v),++v);return(int)v;} /*** drpizza@battleaxe.net ***/
sjelkjd
sjelkjd
hmm, i don''t suppose you can write a delphi function (using stdcall) which can call this other delphi function, could you?
Shannon Barber
Shannon Barber
sjelkjd, I thought about that and almost made another dll, but I only need a couple of functions, and have them about about working.

I think you can push qwords, unless this pushes a pointer to a qword.

sub esp, 8
;fstp [esp] //-> fstp dword ptr [esp], I need qword
_emit 0xDD
_emit 0x1C
_emit 0x24

D9 1C 24 fstp dword ptr [esp]
DD 1C 24 fstp qword ptr [esp]


If I emit the correct op code it works, but I was curious how you tell the assembler which one you want though.

eh, I wish I know more about x86 :/
Are there any primer books for modern x86?


quote:

They get put in the 'eax','ebx','ecx' registers, only if the parameter fits.


Yeah, I know, I went over all that hoping that __fastcall would be close - it's not. I rearanged the order of the parameters so that the first three are the three that go in the registers.


[edited by - Magmai Kai Holmlor on May 22, 2002 11:00:28 AM]
The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
jenova
jenova
assembly at it's best....


      

int main(void)
{
double d;
void *p = dll_func;
double *ptr_to_double = &d

__asm {
mov esi, ptr_to_double
; push registers.
push dword ptr [esi]
push dword ptr [esi + 4]
; call ".dll" function.
call p
; pop registers.
pop eax
pop eax
}
return (0);
}



To the vast majority of mankind, nothing is more agreeable than to escape the need for mental exertion... To most people, nothing is more troublesome than the effort of thinking.

[edited by - jenova on May 22, 2002 1:37:54 PM]
To the vast majority of mankind, nothing is more agreeable than to escape the need for mental exertion... To most people, nothing is more troublesome than the effort of thinking.
DrPizza
DrPizza
quote:
Original post by Magmai Kai Holmlor
sjelkjd, I thought about that and almost made another dll, but I only need a couple of functions, and have them about about working.

If the variables are in memory or literals, they get pushed as two dwords. If they're in the FP stack, they can be popped into memory, but AFAIK there's no opcode to pop from the FP stack and push into the regular stack.

quote:
I think you can push qwords, unless this pushes a pointer to a qword.

It treats esp as a pointer to a qword and pops a qword from the FP stack to that location. It's not really pushing anything, though, as esp doesn't get decremented to continue to point to the 'top' of the stack.


[edited by - DrPizza on May 22, 2002 1:07:56 PM]
char a[99999],*p=a;int main(int c,char**V){char*v=c>0?1[V]:(char*)V;if(c>=0)for(;*v&&93!=*v;){62==*v&&++p||60==*v&&--p||43==*v&&++*p||45==*v&&--*p||44==*v&&(*p=getchar())||46==*v&&putchar(*p)||91==*v&&(*p&&main(0,(char**)(--v+2))||(v=(char*)main(-1,(char**)++v)-1));++v;}else for(c=1;c;c+=(91==*v)-(93==*v),++v);return(int)v;} /*** drpizza@battleaxe.net ***/
Shannon Barber
Shannon Barber
I sub esp myself - so no it's not a micro-code push, but 8 bytes are stuffed into RAM from one op code (the fstp).

I just don't know how to tell the Microcost inline assembler that I want double precision results (i.e. IEEE 64bit instead), instead of single (IEEE 32bit).

The next thing I need to do is stuck a double off the stack onto the FPU stack, and I have the same issue. It just seems so krude to emit the op codes manually...

Thanks Jenova, that'll help for moving stuff from main memory to the stack.

[edited by - Magmai Kai Holmlor on May 22, 2002 7:39:54 PM]
The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
jenova
jenova
Intel Pentium III Instruction Set



    
void func(void)
{
fld qword ptr [esp] ; load the 64-bit float (double) to fpu stack.
}



To the vast majority of mankind, nothing is more agreeable than to escape the need for mental exertion... To most people, nothing is more troublesome than the effort of thinking.

[edited by - jenova on May 22, 2002 10:05:01 PM]
To the vast majority of mankind, nothing is more agreeable than to escape the need for mental exertion... To most people, nothing is more troublesome than the effort of thinking.
Shannon Barber
Shannon Barber
now wait a minute, that was the first thing I tried and MSVC charfed on it

well I'll be damned... it, of course, works perfectly

I just dl'ed the P4 ISR, thanks for the link anyway

[edited by - Magmai Kai Holmlor on May 22, 2002 12:11:50 AM]
The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
DrPizza
DrPizza
quote:
Original post by Magmai Kai Holmlor
I sub esp myself - so no it's not a micro-code push, but 8 bytes are stuffed into RAM from one op code (the fstp).

I just don't know how to tell the Microcost inline assembler that I want double precision results (i.e. IEEE 64bit instead), instead of single (IEEE 32bit).

Tell it that it's a pointer to qword, not a pointer to dword.

i.e.


void func(double a)
{
cout << a << endl;
return;
}

...

double d = 1.0;
__asm
{
fld d // put d on FP stack as if it were used in a calculation
sub esp, 8 // make room on stack
fstp qword ptr[esp] // pop a double from the FP stack and store it at esp
call func // call the function
add esp, 8 // tidy stack, assuming it's the caller's job
}


[edited by - DrPizza on May 22, 2002 12:50:25 AM]
char a[99999],*p=a;int main(int c,char**V){char*v=c>0?1[V]:(char*)V;if(c>=0)for(;*v&&93!=*v;){62==*v&&++p||60==*v&&--p||43==*v&&++*p||45==*v&&--*p||44==*v&&(*p=getchar())||46==*v&&putchar(*p)||91==*v&&(*p&&main(0,(char**)(--v+2))||(v=(char*)main(-1,(char**)++v)-1));++v;}else for(c=1;c;c+=(91==*v)-(93==*v),++v);return(int)v;} /*** drpizza@battleaxe.net ***/

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.