GHC FFI Return Type Bug

Carl R. Witty cwitty@newtonlabs.com
07 Aug 2001 11:13:43 -0700


"Sigbjorn Finne" <sof@galconn.com> writes:

> "Julian Seward (Intl Vendor)" <v-julsew@microsoft.com> writes:
> > 
> > Hmm, we're looking at this.  However, I don't really know what
> > C is or is not supposed to do here.  Given
> > 
> > char fooble ( ... )
> > {
> >    return 'z';
> > }
> > 
> > on an x86, 'z' will be returned at the lowest 8 bits in %eax.
> > What I don't know is, is the C compiler obliged to clear the
> > upper 24 bits of %eax, or does that onus fall on the callee?
> 
> Yes, the callee is required to narrow <expr> in 'return <expr>;' to
> fit that of the specified return type -- see 9.8 of Harbison and
> Steele. So, a C compiler that cause f() to return 0x7fffffff for
> the following,
> 
> unsigned char g()
> {
>     return 0x7fffffff;
> }
> 
> unsigned int f()
> {
>     return g();
> }
> 
> is in the wrong. [Notice that narrowing for signed integral types
> is undefined in ISO C, but most current-day compilers implement
> such narrowing ops the same way, i.e., by masking off excess bits.]

It's certainly true that an ISO C compiler on a typical machine must
return 255 from f() (on an atypical machine, it's possible to have
unsigned char be a 32-bit type).  However, this is essentially
unrelated to the question of whether the x86 ABI allows g() to return
a value in %eax that has the upper 3 bytes non-zero.

When I compile the following file:
-------------------- abitest.c --------------------
unsigned int g_val;

unsigned char g()
{
    return g_val;
}

unsigned int f()
{
    return g();
}
---------------------------------------------------

with the command
	gcc -Wall -O2 -fomit-frame-pointer -S abitest.c

I get the output:
-------------------- abitest.S --------------------
	.file	"abitest.c"
	.version	"01.01"
gcc2_compiled.:
.text
	.align 16
.globl g
	.type	 g,@function
g:
	movzbl g_val,%eax
	ret
.Lfe1:
	.size	 g,.Lfe1-g
	.align 16
.globl f
	.type	 f,@function
f:
	call g
	andl $255,%eax
	ret
.Lfe2:
	.size	 f,.Lfe2-f
	.comm	g_val,4,4
	.ident	"GCC: (GNU) 2.7.2.3"
---------------------------------------------------

You can see that the code for f is:
	call g
	andl $255,%eax
	ret
So gcc believes that a function which returns a value of type unsigned
char is not responsible for clearing the high 3 bytes of %eax.

Carl Witty