CRT Initialization

CRT Initialization

  • Comments 13

Hi, I’m George Mileka and I work on the Visual C++ libraries team. My team owns the CRT, ATL, MFC and STL…

One subject I have always been interested in is the startup code and initialization. The subject got even more challenging as we started supporting mixing native and managed code in our binaries.

Today I will talk about how the CRT initializes global states in the native world…

By default, the linker includes the CRT library which provides its own startup code. The CRT startup code initializes the CRT library, calls global initializers, and finally calls user-provided “main()” function (for console applications).

Now, consider the following code:


          int func(void)

          {

                        return 3;

          }


          int gi = func();
 
          int main()

          {

                        return gi;

          }

According to the C/C++ standard, func() must be called before main() is executed. But who calls it?

An easy way to know, is to set a breakpoint in func(), start debugging the application and look at the stack! Luckily, the CRT code ships with VS!

Browsing the functions on the stack, you will find that the CRT is simply looping through a list of function pointers, calling each one as it goes through them. Those functions are either ones like func() or constructors for class instances…

So, where does the CRT get that list from?

There is a contract between the CRT and VC++ Compiler:

  • When the VC++ compiler sees a global initializer, it generates a dynamic initializer in the .CRT$XCU section (note that the CRT is the section name and XCU is the group name). You can look at those dynamic initializers by running “dumpbin /all main.obj”, and then looking at the .CRT$XCU section (when main.cpp is compiled as a cpp file, not a c file). It will have something like this:

SECTION HEADER #C

.CRT$XCU name

.

.

RELOCATIONS #C

                                                Symbol    Symbol

 Offset    Type              Applied To         Index     Name

 --------  ----------------  -----------------  --------  ------

 00000000  DIR32                      00000000        26  ??__Egi@@YAXXZ (void __cdecl `dynamic initializer for 'gi''(void))

 

-          CRT defines two pointers;

o        __xc_a in .CRT$XCA

o        __xc_z in .CRT$XCZ

Both groups do not have any other symbols defined except __xc_a and __xc_z.

Now – when the linker reads various .CRT groups, it combines them in one section and orders them alphabetically. This means that the user-defined global initializers (which the VC++ compiler puts in .CRT$XCU) will always come after .CRT$XCA and before .CRT$XCZ. So, it should look something like:

.CRT$XCA

            __xc_a

.CRT$XCU

            Pointer to Global Initializer 1

            Pointer to Global Initializer 2

.CRT$XCZ

            __xc_z

So, the CRT library can use both __xc_a and __xc_z to determine the start and end of the global initializers list (array) because of how they are laid out in memory once the image is loaded.

Please, send any questions, comments or feedback our way! We’ll be happy to address them!

George Mileka
Visual C++ Libraries Team

 

  • Great - this is just the kind of post that I like to read! More of this 'under the hood' stuff please!

    Thanks,

    /Tompa

  • Great - it is so amusing to really know something about this 'under the hood' kind of stuff. With Tompa, I would voice that we get something to read of such stuff (behind the scenes subjects).

    Thanks,

    Emmanuel

  • it would be nice to talk about what happens if an exception is thrown at the initializers

  • Hi,I am still not be able to understand what you talked.But i am veri interested and also require some help on CRT Startup code.

  • Hi,

    I don't have basic concepts of CRT and i m very much interested to have some reference material on that.

  • Thanks for the positive feedback!

    cpizano,

    Throwing an exception during the execution of initializers is indeed very important to understand... I'll see if I have some handy material on that subject...

  • Forgot to sign my last entry :)

    George Mileka

    Visual C++ Libraries Team

  • Bhavesh and Vipul,

    Unfortunately, I'm not aware of any books that discuss the internal implementation of the Microsoft CRT.

    However, one very good book about CRT is:

    The Standard C Library - by P. J. Plauger

    George Mileka

    Visual C++ Libraries Team

  • Great work!

    [url=http://wskyqzfn.com/javv/yeqt.html]My homepage[/url] | [url=http://ysleefsp.com/pozl/wgzx.html]Cool site[/url]

  • Hi, My name is Andreea Isac and I’ve been a member of the Visual C++ Libraries team for one year and

  • One question and one request please.

    Let's say that we want to ensure the availabilty of some resource before main gets called.  For example:

    /* globals */

    Logger l("log.txt");

    As per your article, the CRT initilization will construct l before calling main.

    My question is: what happens if l's constructor throws an exception?  Is this bad practice?

    Also, at what point will l's destructor be executed?

    And, on a somewhat related / unrelated subject, can someone direct me to documentation on the __ImageBase construct that the MS C compiler / linker automagically installs into binaries.  What other utterly useful fields are available?

    Thanks - great blog.

  • Albert - it is indeed bad practice to create a global variable using a constructor which may throw an exception since you have no way of catching it.  I believe the default behavior if an exception is thrown at that point is to terminate, but I'd have to check the standard to be sure.

    However, there is a solution to this problem, which is to construct such an object inside the initializer of a global object and surround the construction in a try/catch block.  The pseudocode is something like:

    int InitFunc();

    Logger *l;

    int gDummy = InitFunc();

    int InitFunc()

    {

       try {

           l = new Logger("log.txt");

       } catch (...) {

           // error handling

           ...

       }

    }

    void Cleanup()

    {

       delete l;

    }

    int main()

    {

       ...

       Cleanup();

    }

    The alternative of course would be to not allow the constructor of Logger which is being called to throw an exception.  This could be achieved by either not calling throwing code in the constructor, or try/catching and doing error handling inside the constructor.  If you are using the logger class elsewhere in your code where you would like it to throw you can always create an overload that doesn't by adding a dummy parmeter like so:

    // nonthrowing constructor

    Logger::Logger(const string& filename, int dummyNoThrow)

    {

       try {

           InitHelp(filename);

       } catch (...) {

            ...

            // error handling

       }

    }

    // could throw

    Logger::Logger(const string& filename)

    {

       InitHelp(filename);

    }

  • What is the best pratice for the initialization of a large structure of elements, usually the sturcture is not modified, (communication message structures), with portions needing to be filled in during run time.

Page 1 of 1 (13 items)