Wrong calling convention?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
15 messages Options
Reply | Threaded
Open this post in threaded view
|

Wrong calling convention?

Óscar Fuentes
When my llvm code calls certain function, either it receives a wrong
result or the application ends on what it seems a corrupt stack.

The function is a C++ static method that returns a class with just a
`double' data member:

class Foo {
  double data;
};

My compiler abstracts this as a [8 x i8] array. This is the llvm code:

define internal i1 @Addr_045442A0() {
        alloca [8 x i8], align 4 ; <[8 x i8]*>:1 [#uses=2]
        alloca i1, align 4 ; <i1*>:2 [#uses=2]
        tail call void @F95478DA5_FFI_FN( [8 x i8]* %1 sret  )
        bitcast [8 x i8]* %1 to i8* ; <i8*>:3 [#uses=1]
        tail call void @Addr_004DDA18( i8* inttoptr (i32 14545104 to i8*), i8* %3 )
        store i1 true, i1* %2
        load i1* %2 ; <i1>:4 [#uses=1]
        ret i1 %4
}

It is a function that just calls the above mentioned C++ static method,
calls another external function which is known to be "safe" (as it does
nothing and is called thousands of times everywhere without problems)
and returns bool.

This is the generated machine code, obtained with gdb:

0x0e8d9370:     push   %esi
0x0e8d9371:     sub    $0x18,%esp
0x0e8d9374:     lea    0x10(%esp),%esi
0x0e8d9378:     mov    %esi,(%esp)
0x0e8d937b:     call   0x5053b0 <_ZN3lp04OpF0IN5IncDB9TDateTimeEXadL_ZNS2_3NowEvEEE1wEv>
0x0e8d9380:     sub    $0x4,%esp
0x0e8d9383:     mov    %esi,0x4(%esp)
0x0e8d9387:     movl   $0x8def210,(%esp)
0x0e8d938e:     call   0x4b3ca0 <_ZN3lp015BasicDestructorIN5IncDB9TDateTimeEEEvRNS_8TipoInfoEPv>
0x0e8d9393:     movb   $0x1,0x8(%esp)
0x0e8d9398:     movzbl 0x8(%esp),%eax
0x0e8d939d:     add    $0x18,%esp
0x0e8d93a0:     pop    %esi
0x0e8d93a1:     ret

I'm using setCallingConv(CallingConv::C). After hours and hours of
debugging, I'm lost. Do you see something wrong here?

My setup is llvm 2.1 on Windows XPSP2. Everything is compiled with MinGW
g++.exe (GCC) 4.2.1-dw2 (mingw32-2)

--
Oscar

_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Wrong calling convention?

Duncan Sands
Hi,

> define internal i1 @Addr_045442A0() {
> alloca [8 x i8], align 4 ; <[8 x i8]*>:1 [#uses=2]
> alloca i1, align 4 ; <i1*>:2 [#uses=2]
> tail call void @F95478DA5_FFI_FN( [8 x i8]* %1 sret  )

this call uses the "struct-return" convention (due to the sret attribute).
On x86 this means that the caller is responsible for adjusting the stack
pointer after the call for the sret parameter.  If the callee is not following
the sret convention then the stack pointer will be adjusted wrongly and your
program will die horribly.

> 0x0e8d937b:     call   0x5053b0 <_ZN3lp04OpF0IN5IncDB9TDateTimeEXadL_ZNS2_3NowEvEEE1wEv>
> 0x0e8d9380:     sub    $0x4,%esp

Here you see the sret stack adjustment.

Ciao,

Duncan.
_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Wrong calling convention?

Óscar Fuentes

Hi Duncan.

Duncan Sands <[hidden email]> writes:

>> define internal i1 @Addr_045442A0() {
>> alloca [8 x i8], align 4 ; <[8 x i8]*>:1 [#uses=2]
>> alloca i1, align 4 ; <i1*>:2 [#uses=2]
>> tail call void @F95478DA5_FFI_FN( [8 x i8]* %1 sret  )
>
> this call uses the "struct-return" convention (due to the sret attribute).
> On x86 this means that the caller is responsible for adjusting the stack
> pointer after the call for the sret parameter.  If the callee is not following
> the sret convention then the stack pointer will be adjusted wrongly and your
> program will die horribly.
>
>> 0x0e8d937b:     call   0x5053b0 <_ZN3lp04OpF0IN5IncDB9TDateTimeEXadL_ZNS2_3NowEvEEE1wEv>
>> 0x0e8d9380:     sub    $0x4,%esp
>
> Here you see the sret stack adjustment.

This looks like the opposite: it is making room for passing a parameter
to the next call (the stack grows downwards).

But you put me on the right track. The problem is that the class is
returned on the stack.

This is the class:

class Foo {
public:
  Foo() : data(113.5) {}
  static Foo GetFoo() { return Foo(); }
private:
  double data;
};

This is the assembler code for Foo::GetFoo:

Dump of assembler code for function _ZN3Foo6GetFooEv:
0x6e08b5a4 <_ZN3Foo6GetFooEv+0>:        push   %ebp
0x6e08b5a5 <_ZN3Foo6GetFooEv+1>:        mov    %esp,%ebp
0x6e08b5a7 <_ZN3Foo6GetFooEv+3>:        sub    $0x14,%esp
0x6e08b5aa <_ZN3Foo6GetFooEv+6>:        lea    -0x8(%ebp),%eax
0x6e08b5ad <_ZN3Foo6GetFooEv+9>:        mov    %eax,(%esp)
0x6e08b5b0 <_ZN3Foo6GetFooEv+12>:       call   0x6e08b5bc <Foo>
0x6e08b5b5 <_ZN3Foo6GetFooEv+17>:       fldl   -0x8(%ebp)
0x6e08b5b8 <_ZN3Foo6GetFooEv+20>:       leave
0x6e08b5b9 <_ZN3Foo6GetFooEv+21>:       ret
End of assembler dump.

I guess that g++ exploits its knowledge of Foo's internals for deciding
how to return the class. But my compiler knows nothing about Foo, so I
must disable this "feature" of g++. Suggestions welcome.

--
Oscar

_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Wrong calling convention?

Duncan Sands
Hi Óscar,

> >> define internal i1 @Addr_045442A0() {
> >> alloca [8 x i8], align 4 ; <[8 x i8]*>:1 [#uses=2]
> >> alloca i1, align 4 ; <i1*>:2 [#uses=2]
> >> tail call void @F95478DA5_FFI_FN( [8 x i8]* %1 sret  )
> >
> > this call uses the "struct-return" convention (due to the sret attribute).
> > On x86 this means that the caller is responsible for adjusting the stack
> > pointer after the call for the sret parameter.  If the callee is not following
> > the sret convention then the stack pointer will be adjusted wrongly and your
> > program will die horribly.
> >
> >> 0x0e8d937b:     call   0x5053b0 <_ZN3lp04OpF0IN5IncDB9TDateTimeEXadL_ZNS2_3NowEvEEE1wEv>
> >> 0x0e8d9380:     sub    $0x4,%esp
> >
> > Here you see the sret stack adjustment.
>
> This looks like the opposite: it is making room for passing a parameter
> to the next call (the stack grows downwards).

yes I said it the wrong way round: with sret the callee pops the sret parameter,
so the caller needs to correct for that.  I'm pretty sure that's exactly what this
sub is doing.

> But you put me on the right track. The problem is that the class is
> returned on the stack.
>
> This is the class:
>
> class Foo {
> public:
>   Foo() : data(113.5) {}
>   static Foo GetFoo() { return Foo(); }
> private:
>   double data;
> };
>
> This is the assembler code for Foo::GetFoo:
>
> Dump of assembler code for function _ZN3Foo6GetFooEv:
> 0x6e08b5a4 <_ZN3Foo6GetFooEv+0>:        push   %ebp
> 0x6e08b5a5 <_ZN3Foo6GetFooEv+1>:        mov    %esp,%ebp
> 0x6e08b5a7 <_ZN3Foo6GetFooEv+3>:        sub    $0x14,%esp
> 0x6e08b5aa <_ZN3Foo6GetFooEv+6>:        lea    -0x8(%ebp),%eax
> 0x6e08b5ad <_ZN3Foo6GetFooEv+9>:        mov    %eax,(%esp)
> 0x6e08b5b0 <_ZN3Foo6GetFooEv+12>:       call   0x6e08b5bc <Foo>
> 0x6e08b5b5 <_ZN3Foo6GetFooEv+17>:       fldl   -0x8(%ebp)
> 0x6e08b5b8 <_ZN3Foo6GetFooEv+20>:       leave
> 0x6e08b5b9 <_ZN3Foo6GetFooEv+21>:       ret
> End of assembler dump.
>
> I guess that g++ exploits its knowledge of Foo's internals for deciding
> how to return the class.

How Foo is returned is specified by the platform ABI.  It is not really a
feature of g++.

> But my compiler knows nothing about Foo, so I  
> must disable this "feature" of g++. Suggestions welcome.

It is not possible to correctly codegen parameter passing/result returning
without knowing the type (though not all details of the type are relevant).
Your compiler needs to know something about Foo.

Ciao,

Duncan.

_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Wrong calling convention?

Óscar Fuentes
Duncan Sands <[hidden email]> writes:

>> But you put me on the right track. The problem is that the class is
>> returned on the stack.

Correction: The class is returned on the FP stack:

>> 0x6e08b5b5 <_ZN3Foo6GetFooEv+17>:       fldl   -0x8(%ebp)
>> 0x6e08b5b8 <_ZN3Foo6GetFooEv+20>:       leave
>> 0x6e08b5b9 <_ZN3Foo6GetFooEv+21>:       ret
>> End of assembler dump.
>>
>> I guess that g++ exploits its knowledge of Foo's internals for deciding
>> how to return the class.
>
> How Foo is returned is specified by the platform ABI.  It is not really a
> feature of g++.

This is C++ land, so there is no "platform ABI", although static methods
usually follow C calling convention. I've checked that wrapping the
class definition with extern "C" changes nothing, so maybe it is
following the platform ABI, after all.

BTW, -fpcc-struct-return solves the case that motivated this thread.

>> But my compiler knows nothing about Foo, so I  
>> must disable this "feature" of g++. Suggestions welcome.
>
> It is not possible to correctly codegen parameter passing/result returning
> without knowing the type (though not all details of the type are relevant).
> Your compiler needs to know something about Foo.

I'm afraid you are right. Current available information includes the
specific type (if it is fundamental), and type size (if it is
derived). It also knows the default constructor, copier and destructor
of each type. I hope that this, together with -fpcc-struct-return, is
enough to complete my C++ <-> LLVM interface, which only has to deal
with static methods.

--
Oscar

_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Wrong calling convention?

Anton Korobeynikov
In reply to this post by Duncan Sands
Hello, Oscar

> This is C++ land, so there is no "platform ABI",
Well, here is g++ ABI :)

> following the platform ABI, after all.
>
> BTW, -fpcc-struct-return solves the case that motivated this thread.
Usually, special rules are applied for returning struct, if its size is
small enough. So you can definitely find something small returned via
registers. This is frontend job to select how to pass such object.

--
With best regards, Anton Korobeynikov.

Faculty of Mathematics & Mechanics, Saint Petersburg State University.


_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Wrong calling convention?

Óscar Fuentes
In reply to this post by Óscar Fuentes
Óscar Fuentes <[hidden email]> writes:

> BTW, -fpcc-struct-return solves the case that motivated this thread.

-fpcc-struct-return is an ABI change, hence it requires "compiling the
world". Not acceptable.

I'll be interested on hearing ideas about how to determine how a
function returns a small struct, without knowing the internals of the
struct.

--
Oscar

_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Wrong calling convention?

Óscar Fuentes
In reply to this post by Óscar Fuentes
Óscar Fuentes <[hidden email]> writes:

> BTW, -fpcc-struct-return solves the case that motivated this thread.

-fpcc-struct-return is an ABI change, hence it requires "compiling the
world". Not acceptable.

I'll be interested on hearing ideas about how to determine how a
function returns a small struct, without knowing the internals of the
struct.

--
Oscar

_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Wrong calling convention?

David Vandevoorde

On Mar 26, 2008, at 1:31 PM, Óscar Fuentes wrote:

> Óscar Fuentes <[hidden email]> writes:
>
>> BTW, -fpcc-struct-return solves the case that motivated this thread.
>
> -fpcc-struct-return is an ABI change, hence it requires "compiling the
> world". Not acceptable.
>
> I'll be interested on hearing ideas about how to determine how a
> function returns a small struct, without knowing the internals of the
> struct.

You need to know _something_ about the internals.  GCC approximately  
implements the IA-64 C++ ABI; which is fairly conventional in this  
particular aspect of a C++ ABI.  See
        http://www.codesourcery.com/cxx-abi/abi.html#calls

In that ABI, if there is a "nontrivial" (that's a precise term) copy-
constructor or destructor, the caller is responsible for allocation.

        Daveed


_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Wrong calling convention?

Evan Cheng-2
In reply to this post by Óscar Fuentes
Take a look at llvm-gcc. Look for HandleAggregateShadowArgument.

Evan

On Mar 26, 2008, at 10:31 AM, Óscar Fuentes wrote:

> Óscar Fuentes <[hidden email]> writes:
>
>> BTW, -fpcc-struct-return solves the case that motivated this thread.
>
> -fpcc-struct-return is an ABI change, hence it requires "compiling the
> world". Not acceptable.
>
> I'll be interested on hearing ideas about how to determine how a
> function returns a small struct, without knowing the internals of the
> struct.
>
> --
> Oscar
>
> _______________________________________________
> LLVM Developers mailing list
> [hidden email]         http://llvm.cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev


_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Wrong calling convention?

Evan Cheng-2
I should note this how we do it today but it may not be the solution  
long term.

In an ideal world the llvm frontend will not need to know anything  
about the target since llvm is intended as a virtual instruction set.

Evan

On Mar 26, 2008, at 11:42 AM, Evan Cheng wrote:

> Take a look at llvm-gcc. Look for HandleAggregateShadowArgument.
>
> Evan
>
> On Mar 26, 2008, at 10:31 AM, Óscar Fuentes wrote:
>
>> Óscar Fuentes <[hidden email]> writes:
>>
>>> BTW, -fpcc-struct-return solves the case that motivated this thread.
>>
>> -fpcc-struct-return is an ABI change, hence it requires "compiling  
>> the
>> world". Not acceptable.
>>
>> I'll be interested on hearing ideas about how to determine how a
>> function returns a small struct, without knowing the internals of the
>> struct.
>>
>> --
>> Oscar
>>
>> _______________________________________________
>> LLVM Developers mailing list
>> [hidden email]         http://llvm.cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
>


_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Wrong calling convention?

Jonathan S. Shapiro-2
In reply to this post by Anton Korobeynikov
On Wed, 2008-03-26 at 19:56 +0300, Anton Korobeynikov wrote:
> Usually, special rules are applied for returning struct, if its size is
> small enough. So you can definitely find something small returned via
> registers. This is frontend job to select how to pass such object.

It is true that many calling conventions optimize small structure
return. It is the front end's job to *implement* this. It is the
responsibility of the calling convention to *specify* this. The front
end must comply with the calling convention, or separate compilation is
compromised.


shap

_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Wrong calling convention?

Óscar Fuentes
In reply to this post by Evan Cheng-2
Evan Cheng <[hidden email]> writes:

>> I'll be interested on hearing ideas about how to determine how a
>> function returns a small struct, without knowing the internals of the
>> struct.

> Take a look at llvm-gcc. Look for HandleAggregateShadowArgument.

This does not qualify as "without knowing the internals of the struct"
:-)

DefaultABI::HandleReturnType made an interesting reading, although it
uses information which is unaccessible to my compiler.

--
Oscar

_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Wrong calling convention?

Dale Johannesen

On Mar 26, 2008, at 3:09 PM, Óscar Fuentes wrote:

> Evan Cheng <[hidden email]> writes:
>
>>> I'll be interested on hearing ideas about how to determine how a
>>> function returns a small struct, without knowing the internals of  
>>> the
>>> struct.
>
>> Take a look at llvm-gcc. Look for HandleAggregateShadowArgument.
>
> This does not qualify as "without knowing the internals of the struct"
> :-)
>
> DefaultABI::HandleReturnType made an interesting reading, although it
> uses information which is unaccessible to my compiler.

Which calling convention to use depends on the contents of the  
struct.  You cannot make all cases work without that information.


_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Wrong calling convention?

Óscar Fuentes
In reply to this post by David Vandevoorde
David Vandevoorde <[hidden email]> writes:

>> I'll be interested on hearing ideas about how to determine how a
>> function returns a small struct, without knowing the internals of the
>> struct.
>
> You need to know _something_ about the internals.
[snip]

Well, as AFAIK there is no way of gathering that information, putting
some checks to ensure that the manually provided type info is correct
would be nice, but I'm afraid that there is no way to achieve that
either (except for the most simple checks, like the struct size not
being large than `double', etc). Boost type_traits does not mention g++
on the list of compilers that has the necessary intrinsics for
supporting has_trivial_copier et al.

I guess this is off-topic, so thank you all guys for your suggestions.

--
Oscar

_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev