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