This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: at exit alternative for AIX


On Aug 5, 2012, at 1:09 PM, David Edelsohn wrote:

> On Sun, Aug 5, 2012 at 9:56 AM, Perry Smith <pedzsan@gmail.com> wrote:
> 
>> I was planning on exploring when _GLOBAL__FD was called today.  I
>> need to figure out when gcc puts the call to the dtor in _GLOBAL__FD
>> path rather than in the atexit path.  The net implies that "static" uses
>> atexit while a global non-static uses _GLOBAL__FD
>> 
>> I'm also exploring what it would take to port a version of GNU's
>> __cxa_atexit to AIX.  I think after I figure out when various dtors
>> get called, I should be able to figure out if / how to do that.
>> 
>> Part of my confusion / concern is "why have two methods?"
>> Does the spec say that dtors much be called at different times?
> 
> Destructors are added to _GLOBAL__FD by collect2 at link time.  It
> scans the object files for destructor functions, sorts them by
> priority and creates a function connected to _GLOBAL__FD to call them.
> Collect2 performs the same grouping for constructors, creates a
> function and connects it to _GLOBAL__FI.  The uniquely named functions
> are added to the AIX linker command line as arguments to the
> -binitfini option to establish them as initializer/finalizer functions
> for the shared object.
> 
> AIX does not have a ctor/dtor or init/fini section in object files,
> nor _cxa_atexit.
> 
> AIX dlclose() should call AIX terminateAndUnload() service that will
> call the fini routine registered by -binitfini.  If something else in
> GCC is trying to register the termination function for systems without
> _cxa_atexit() using atexit(), it probably is conflicting and trying to
> run the destructors twice.
> 
> Another difference between AIX and SVR4 is AIX invokes init and fini
> functions for multiple, dependent shared objects breadth first, while
> SVR4 invokes them depth first based on library dependencies.  There is
> an old Bugzilla entry with a proposal to push init functions onto a
> stack as they are seen when libraries are loaded and then run them in
> SVR4 dependency order.

Thank you both for helping.

I understand when atexit is used.  I believe the _GLOBAL__FD method
could be used instead and would be more correct but it somehow needs to
be conditionalized.

To get the atexit to be used, you need a function that returns a static
that is declared inside the function.  In my code below, this is
"func".

The function registered with atexit is called tcf_0 (I'm sure that
would increment if there are more than one).  I mention that hoping it
might help in tracking down where it is being created.

There are other parts to this program that I left because, to me, it
was interesting when atexit is called and all the places where it is
not called.

I call the program x1.cpp.  x1 with no argument does not create
"func".  x1 with an argument does.  Note that if func is not created,
the dtor is not called (which seems obvoius but that is where the
difficulty is going to come from).

My thoughts on how to solve this would call tcf_0 from the _GLOBAL_FD
and have tcf_0 check a flag.  If not set, it does nothing.  In the
special ctor where atexit is now being called, just set that flag
instead of calling atexit.

Here is the program:

#include <iostream>
using namespace std;

class foo {
private:
    const char *name;
    void mess(const char *s) {
        cout << s << " " << name << endl;
    }

public:
    foo(const char *s) {
        name = s;
        mess("ctor");
    }

    ~foo() {
        mess("dtor");
    }
};

class bar {
    static foo surf;
};
foo bar::surf("bar");

foo g("global");
static foo s("static");

foo& func()
{
    static foo val("func");
    return val;
}

int main (int argc, char *argv[])
{
    cout << "Hello World!" << endl;
    foo a("auto");

    if (argc > 1)
        foo &f = func();

    cout << "Good Bye World!" << endl;
    return 0;
}

Output with x1 called with no argument:
ctor bar
ctor global
ctor static
Hello World!
ctor auto
Good Bye World!
dtor auto
dtor static
dtor global
dtor bar

Output with x1 called with an argument:
ctor bar
ctor global
ctor static
Hello World!
ctor auto
ctor func << atexit called just after this prints.
Good Bye World!
dtor auto
dtor func
dtor static
dtor global
dtor bar

I'm happy to create a bug report if anyone wants me to.

Thank you again,
Perry


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]