C ++ ctor question (linux)

  • environment: linux, userpace app built with g ++ from multiple c ++ files (result is ELF)

  • there is a problem (SIGSEGV) when moving the list of constructors

    (__CTOR_LIST__)

(note: the code called through this list is kind of system initialization for each class, not the constructor code I wrote)

  • when I understand correctly each compilation unit (each .o created with .cpp) creates one entry in
    __CTOR_LIST__ 
  • the problem (SIGSEGV) doesn't exist when I go through GDB through the program

  • to debug this i am looking for a way to add my own code before . call

    "_do_global_ctors_aux"

any hints for this?

thank,

Uwe

+1


source to share


3 answers


There are many possible reasons for this. Ranges from what you are referring to objects that have not yet been created (since the order of creating objects in different translation units is undefined), which I think is quite likely in this case and ranges to a bug in your building environment.

To make your own function called before another constructor function, you have the attribute constructor (priority)

described here . GCC maintains precedence for the constructor input section of each file. And he links them in the order of these priorities. In the linker script of my Linux system, this code looks like this (output it with ld -verbose

):

  .ctors          :
  {
    /* gcc uses crtbegin.o to find the start of
       the constructors, so we make sure it is
       first.  Because this is a wildcard, it
       doesn't matter if the user does not
       actually link against crtbegin.o; the
       linker won't look for a file to match a
       wildcard.  The wildcard also means that it
       doesn't matter which directory crtbegin.o
       is in.  */
    KEEP (*crtbegin.o(.ctors))
    KEEP (*crtbegin?.o(.ctors))
    /* We don't want to include the .ctor section from
       the crtend.o file until after the sorted ctors.
       The .ctor section from the crtend file contains the
       end of ctors marker and it must be last */
    KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
    KEEP (*(SORT(.ctors.*)))
    KEEP (*(.ctors))
  }

      

You would like to give it a low priority so that it runs before any other registered ctor functions with a higher priority number. However, due to the look and feel, it seems that constructors without a number will be executed first. Not completely sure. Try it best. If you want your function to be called even before _do_global_ctors_aux, you need to free the original function _init

, which is normally executed when your program is loaded by the ELF loader (look at the parameter-init

for ld). It's been a while since I messed it up, but I remember that it has to do intimate initialization details, so I wouldn't replace it. Try using the constructor attribute I am attached to. However, be very careful. Your code can be executed before other important objects such as cout

.

Update . I did the test and actually does the ctor functions in reverse order. Thus, the ctor functions that are linked to each other are executed later. This code is in crtstuff.c of the gcc source code:

  func_ptr *p;
  for (p = __CTOR_END__ - 1; *p != (func_ptr) -1; p--)
    (*p) ();

      

I did a little test:



void dothat() { }
struct f {
    f() { dothat(); }
} f_;
void doit() __attribute__((constructor (0)));
void doit() { }
int main() { }

      

Linking to --print-map

gives, among other things, this output:

.ctors          0x080494f4       0x10
 *crtbegin.o(.ctors)                 
 .ctors         0x080494f4        0x4 /usr/lib/gcc/i686-pc-linux-gnu/4.3.2/crtbegin.o
 *crtbegin?.o(.ctors)                                                                
 *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)                                        
 .ctors         0x080494f8        0x4 /tmp/ccyzWBjs.o                                
 *(SORT(.ctors.*))                                                                   
 .ctors.65535   0x080494fc        0x4 /tmp/ccyzWBjs.o                                
 *(.ctors)                                                                           
 .ctors         0x08049500        0x4 /usr/lib/gcc/i686-pc-linux-gnu/4.3.2/crtend.o  

      

Note that .ctors.65535

- this is the section that we implicitly create with our attribute priority 0

. Now if you give this priority, gcc warns about it and is completely right: p

test.cpp: 7: warning: constructor priorities 0 to 100 are reserved for implementation

I tested it by breaking into doit

and dothat

and calling them in the expected order. Enjoy!

+7


source


You may have been bitten by a so-called "Fiasco Static Initialization Order".



Basically, when there is more than one translation unit (i.e. a C ++ source file) and each file defines a global object, it is not possible for the C ++ compiler / linker to set what to build first for. If x

depends on first y

, but accidental compilation / linking causes x

before y

, the program will usually crash. See article [10.12] C ++ FAQ Lite for details . Clause [10.13] contains a solution - the "construct on first use" idiom.

+1


source


Not the question you asked, but ...

In C ++ / g ++, you can have a class where the declared [header] methods are never defined in the [.cc] source files if those methods are never called.

As a consequence, you can copy your current code files to a temporary directory, do a hack and forward slash on it, run a binary search [manual], and isolate the problem pretty quickly.

Not elegant, but very efficient.


Besides the infamous "Static Initialization Order" question, there are also more esoteric cases, such as the one I recently mentioned here on SO by Charles Bailey (see comments).

   E.g Mixing:  int p [] = { 1,2,3 };
          And:  extern int * p;

      

Produces a similar core problem.

0


source







All Articles