3

This example is with clang 15 using -O3.

Check it out on Godbolt: https://godbolt.org/z/Pd31fGKTe

#include <iostream>

int hello = printf("Hello World!\n");

int main() {
    printf("main()");
}

Output is as expected from the rules of C++ initialization.

Hello World!
main()

What is not expected to me is the assembly code:

main:                                   # @main
        push    rax
        lea     rdi, [rip + .L.str.2]
        xor     eax, eax
        call    printf@PLT
        xor     eax, eax
        pop     rcx
        ret
_GLOBAL__sub_I_example.cpp:             # @_GLOBAL__sub_I_example.cpp
        push    rbx
        lea     rbx, [rip + std::__ioinit]
        mov     rdi, rbx
        call    std::ios_base::Init::Init()@PLT
        mov     rdi, qword ptr [rip + std::ios_base::Init::~Init()@GOTPCREL]
        lea     rdx, [rip + __dso_handle]
        mov     rsi, rbx
        call    __cxa_atexit@PLT
        lea     rdi, [rip + .L.str]
        xor     eax, eax
        call    printf@PLT
        mov     dword ptr [rip + hello], eax
        pop     rbx
        ret
hello:
        .long   0                               # 0x0

.L.str:
        .asciz  "Hello World!\n"

.L.str.2:
        .asciz  "main()"

It seems to me that main: is not the entry point, but _GLOBAL__sub_I_example.cpp: instead. I believe this because if not I think the program would ouput main() first, but it doesn't. What confuses me is that I don't get how the code from the main: label gets called. If _GLOBAL__sub_I_example.cpp: is the entry point, then why does it return something and how does the program ever run the code with the main label.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Cedric Martens
  • 1,139
  • 10
  • 23
  • 12
    Because the initializer is not a compile-time constant. It's handled a lot like a static constructor; it gets called from libc startup code, which goes on to call `main` after that returns. Neither are the process entry point, that's `_start:` in one of the `crt*.o` files. (Or in a dynamically linked executable, actually `_start` in `/lib64/ld-linux-x86-64.so.2` – Peter Cordes Jan 03 '23 at 04:06
  • 1
    To add to Peter's comment, my clang (inside Visual Studio) adds this for the `hello` variable: *warning : declaration requires a global constructor [-Wglobal-constructors]* – Adrian Mole Jan 03 '23 at 04:07
  • 1
    That makes sense, I was using GDB (with GEF) to have a breakpoint on _start and was quite confused. Can an answer be written with this information (ideally, with more detail as I'm very unfamiliar with this topic). I will accept it – Cedric Martens Jan 03 '23 at 04:12
  • 5
    Related: [What happens before main in C++?](https://stackoverflow.com/q/53570678) / [Is main() really start of a C++ program?](https://stackoverflow.com/a/64116561) (on GNU/Linux, see how `_start` calls `__libc_start_main`, passing it a pointer to `main`) / [C++ Global Object Constructor Vs. main Call Sequence](https://stackoverflow.com/q/35818189) / [What order does gcc \_\_attribute\_\_((constructor)) run in relation to global variables in same translation unit?](https://stackoverflow.com/q/70582675) – Peter Cordes Jan 03 '23 at 04:12
  • 1
    Seems like a fine opportunity for another of @PeterCordes educational series for the rest of us. I'll happily add a vote. – David C. Rankin Jan 03 '23 at 04:21
  • 1
    @DavidC.Rankin: there are lots of existing answers that cover this, although none of the ones I've found have centred their attention squarely on this interaction, how an array of function pointers get called in a loop from `.init` code before `main` is called, and how asm source can mark a function to get added to that array at link time. But I expect there's a duplicate. If not, maybe I'll get around to writing an answer myself. – Peter Cordes Jan 03 '23 at 04:25
  • @PeterCordes - that's fair, I was hoping for a comment on the `_atexit()` setup -- even though there is nothing set for it. While it's not clear exactly how the assembly output was produced, generally with C, unless there is something for `atexit()` to do, you don't see that as part of the dump. (I'll have to dig further on that and any difference between C/C++) – David C. Rankin Jan 03 '23 at 04:29
  • 4
    Also fun to watch : [CppCon 2018: Matt Godbolt “The Bits Between the Bits: How We Get to main()”](https://www.youtube.com/watch?v=dOfucXtyEsU) – Pepijn Kramer Jan 03 '23 at 04:32
  • @DavidC.Rankin: This asm output was produced by `clang -O3 -S` (targeting GNU/Linux) and then stripping out directives to keep only the asm instructions and labels, as per the Godbolt compiler explorer's default. Just `#include ` will get the compiler to produce code for an init function; I guess clang is doing the printf in the same init function, like one for the whole compilation unit, instead of one per variable? The include of iostream complicates things; with just `stdio.h` or `cstdio` for `printf`, no extra atexit registering is needed: https://godbolt.org/z/GWYP4c3zK – Peter Cordes Jan 03 '23 at 04:35
  • Thank you Peter. That makes sense. My sense was it was part of the setup/cleanup for whatever the C++ initialization does that later it undoes. I'll check the godbolt output and see how my google foo is for C++ initialization. – David C. Rankin Jan 03 '23 at 04:39
  • I caught up on the links that were shared and I now understand! I am satisfied with the comments from @PeterCordes as it answers my question. Please create an answer to this question so I can give you some credit – Cedric Martens Jan 03 '23 at 05:18
  • If any of those links work as a duplicate, I'd be fine with that. Or if you want to put in the effort to write an answer connecting the dots, that'd be fine with me. I don't need the rep, and I'm not super interested in diving into the details right now to get them all accurate in an answer. – Peter Cordes Jan 03 '23 at 05:21
  • @PepijnKramer - Bravo! I didn't get around to watching Godbolt's Bits between bits until today -- that is a great presentation! (and kudos to him for presenting it in a way that keeps it interesting... following the same rabbit trails you can envision following if you started trying to chase it down yourself -- but Matt obviously has a good head start on knowing were to look) – David C. Rankin Jan 04 '23 at 00:56

0 Answers0