October 6th, 2021

Why is the main() function always at address 0x00401000 in a simple program?

If you compile a simple C or C++ program, and then load it into the debugger as a dump file (or if you execute the program with ASLR disabled), you’ll find that the main function is at offset 0x00401000. What is so special about this address?

It’s the result of multiple technical decisions that add together, literally.

Your simple C or C++ program has only one function: main. It is therefore the function at the start of your code section, and the address of the main function is the address of the code section.

Traditionally, the code section is the first section of a Windows Portable Executable file. There’s no technical reason for it, but somebody has to go first, and code seems to be the natural choice since it’s almost always the most important part of the module. (“Primary reason for existence” in most cases.)

Sections are page-aligned because each section specifies its protection, and memory protection is applied at the page level. Therefore, the offset of the code section must be a multiple of the page size, which for x86 is 4KB.

The page at offset zero contains the module header information.

Therefore the first page available for the code section is the page at offset 0x1000.

The last piece of the puzzle is that 0x00400000 is the default base address for executables on x86.

Put all of these decisions together (some technical, some arbitrary), and you find that the address of the main() function in a simple program is always 0x00401000.

Topics
History

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

4 comments

Discussion is closed. Login to edit/delete existing comments.

  • Piotr Siódmak

    Define “simple”. I thought that even a “simple” program in Visual Studio would be compiled with CRT, which comes before your main(). Also global initializers.

    • Raymond ChenMicrosoft employee Author

      main.obj is linked ahead of vcruntime.lib, so it gets the lowest address, and the CRT code comes after.

  • Brian Boorman

    Long gone are the days of using

    .org 100

    at the top of your DOS .com asm source code.

    • Georg Rottensteiner

      I do the

      * = $0801

      daily.