Inline assembler can't return 64-bit values in registers
Timur Tabi
ttabi@interactivesi.com
Wed Dec 6 15:58:00 GMT 2000
I'm trying to port some x86 assembly code from Windows to Linux, I think I've
come across a situation where gcc's inline assembler can't do something that the
Microsoft inline assembler can.
Those of you who have used non-gcc compilers might know that in order to return
a long integer, the compiler uses two registers to hold the value. For a 16-bit
compiler, a 32-bit integer is returned as dx:ax, where dx has the upper 16 bits,
and ax has the lower 16. On a 32-bit compiler, edx:eax is used to hold a 64-bit
integer.
The code I'm trying to port is:
_inline u64 readq(const volatile void * const pInput)
{
_asm
{
mov ebx, pInput;
movq mm0, [ebx];
movd eax, mm0;
punpckhdq mm0, mm0;
movd edx, mm0;
// return ( (u64)edx << 32 ) | (u64)eax;
}
}
which basically assumes that the compiler will use edx:eax as the return value.
Converting this to gcc appears to be impossible.
Here's some code which calls readq:
Array[i].u = readq( pStartBlock );
And my gcc version of the assembly code:
_inline u64 readq(const volatile void * const pInput)
{
register u64 temp1, temp2;
__asm__ __volatile__ (
"movq (%2), %%mm0 \n\t"
"movd %%mm0, %0 \n\t"
"punpckhdq %%mm0, %%mm0 \n\t"
"movd %%mm0, %1 \n\t"
: "=r" (temp1), "=r" (temp2)
: "r" (pInput)
);
return (temp2 << 32) | temp1;
}
It generates this code:
.LM321:
movl 12(%ebp),%esi
#APP
movq (%esi), %mm0
movd %mm0, %ebx
punpckhdq %mm0, %mm0
movd %mm0, %eax
#NO_APP
movl %ebx,-312(%ebp)
movl %esi,-308(%ebp)
^^^^
Why %esi and not %eax!?!?
.stabn 68,0,40,.LM322-phase4
.LM322:
movl %eax,%edx
xorl %eax,%eax
.stabs "init.c",132,0,0,.Ltext40
.Ltext40:
.stabn 68,0,903,.LM323-phase4
.LM323:
orl -312(%ebp),%eax
orl -308(%ebp),%edx
movl -296(%ebp),%ecx
movl %eax,(%ecx,%edi)
movl %edx,4(%ecx,%edi)
As you can see, even though it places the 64-bit value into eax:ebx, the code
isn't right. In fact, I'm not exactly certain what it's doing, but it's not
correct. For one thing, it shouldn't be writing any data to -312(%ebp) or
-308(%ebp). It should be keeping everything in registers. Second, why is it
writing %esi to -308(%ebp) and not %eax? And third, what is this code supposed
to accomplish?
movl %eax,%edx
xorl %eax,%eax
Could someone please help me get this working?
[ttabi@one ttabi]$ gcc -v
Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/specs
gcc version egcs-2.91.66 19990314/Linux (egcs-1.1.2 release)
--
Timur Tabi - ttabi@interactivesi.com
Interactive Silicon - http://www.interactivesi.com
When replying to a mailing-list message, please direct the reply to the mailing list only. Don't send another copy to me.
More information about the Gcc-bugs
mailing list