Skip to content

Instantly share code, notes, and snippets.

@manojpandey
Forked from lava/hello_world.md
Created October 24, 2016 10:59
Show Gist options
  • Save manojpandey/d050c7136b4cc294e0a513dc8c247beb to your computer and use it in GitHub Desktop.
Save manojpandey/d050c7136b4cc294e0a513dc8c247beb to your computer and use it in GitHub Desktop.

Revisions

  1. @lava lava revised this gist Aug 9, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion hello_world.md
    Original file line number Diff line number Diff line change
    @@ -114,7 +114,7 @@ Let's just re-write it in a purely functional way.

    ## The Ideologue

    You should have written unit tests before writing this program.
    You should never write a program without unit tests.

    ## The Engineer

  2. @lava lava revised this gist Jul 6, 2016. 1 changed file with 5 additions and 1 deletion.
    6 changes: 5 additions & 1 deletion hello_world.md
    Original file line number Diff line number Diff line change
    @@ -107,10 +107,14 @@ statement, which has has the effect of destroying any objects with automatic
    storage duration and calling `std::exit()` with the argument `0`. (§3.6.1/5)


    ## The Ideologue

    ## The Idealist

    Let's just re-write it in a purely functional way.

    ## The Ideologue

    You should have written unit tests before writing this program.

    ## The Engineer

  3. @lava lava revised this gist Jun 20, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion hello_world.md
    Original file line number Diff line number Diff line change
    @@ -93,7 +93,7 @@ returns its first argument `out`.
    The same procedure is repeated for the next left shift operator, which has
    a left operand of type `std::ostream&` and a right operand that refers to
    a template function of two arguments with the signature
    `template<class C, class T> std::basic_ostream<C,T>&(std::basic_ostream<C,T>&).
    `template<class C, class T> std::basic_ostream<C,T>&(std::basic_ostream<C,T>&)`.
    Here, the selected overload is

    std::ostream::operator<<(std::ostream&(*f)(std::ostream& os))
  4. @lava lava revised this gist Jun 20, 2016. 1 changed file with 6 additions and 4 deletions.
    10 changes: 6 additions & 4 deletions hello_world.md
    Original file line number Diff line number Diff line change
    @@ -82,17 +82,19 @@ The best match is the template function specialization
    from §27.7.3.6.4 [ostream.inserters.character], which behaves like a formatted
    inserter of out. (§27.7.3.6.1 [ostream.formatted.reqmts])

    Therefore, the calling this function will begin by constructing an object of
    Therefore, calling this function will begin by constructing an object of
    class `std::sentry`. (§27.7.3.4 [ostream.sentry]) If this object returns `true`
    when converted to bool, the function will proceed to create a character
    sequence `seq` of 14 characters, each widened using out.widen(), to
    insert `seq` into `out`, and to call `width(0)`. (§27.7.3.6.4/3) Finally,
    the sentry object is destroyed before leaving the function and the function
    the sentry object is destroyed before leaving the function, and it
    returns its first argument `out`.

    The same procedure is repeated for the next left shift operator, which has
    operands of type `std::ostream&` and `ostream&(ostream&). Here, the selected
    overload is
    a left operand of type `std::ostream&` and a right operand that refers to
    a template function of two arguments with the signature
    `template<class C, class T> std::basic_ostream<C,T>&(std::basic_ostream<C,T>&).
    Here, the selected overload is

    std::ostream::operator<<(std::ostream&(*f)(std::ostream& os))

  5. @lava lava revised this gist Jun 20, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion hello_world.md
    Original file line number Diff line number Diff line change
    @@ -41,7 +41,7 @@ Including this header causes the effects of defining an instance
    of `ios_base::Init` with static storage duration. (§27.4.1/2 [iostream.objects.overview])
    During or before construction of this instance, the object `std::cout` of type
    `ostream` is constructed and associated with the object `stdout` declared in
    the <cstdio> header. (§27.4.2/1 [narrow.stream.objects])
    the `<cstdio>` header. (§27.4.2/1 [narrow.stream.objects])

    Next, we see the definition of a global function called `main` returning an int
    and taking no arguments. The program thus fulfills the requirements of
  6. @lava lava revised this gist Jun 20, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion hello_world.md
    Original file line number Diff line number Diff line change
    @@ -33,7 +33,7 @@ probably be the creation of a core dump in the current directory.

    Lets analyze the program according to the C++ Draft Standard in version N4296.

    Since <iostream> is one of the 53 C++ standard library header listed
    Since `<iostream>` is one of the 53 C++ standard library header listed
    in §17.6.1.2/2 [headers], its contents will be made available to the translation
    unit. (§17.6.2.2/1 [using.headers])

  7. @lava lava revised this gist Jun 20, 2016. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion hello_world.md
    Original file line number Diff line number Diff line change
    @@ -87,7 +87,8 @@ class `std::sentry`. (§27.7.3.4 [ostream.sentry]) If this object returns `true`
    when converted to bool, the function will proceed to create a character
    sequence `seq` of 14 characters, each widened using out.widen(), to
    insert `seq` into `out`, and to call `width(0)`. (§27.7.3.6.4/3) Finally,
    the sentry object is destroyed before leaving the function.
    the sentry object is destroyed before leaving the function and the function
    returns its first argument `out`.

    The same procedure is repeated for the next left shift operator, which has
    operands of type `std::ostream&` and `ostream&(ostream&). Here, the selected
  8. @lava lava revised this gist Jun 20, 2016. No changes.
  9. @lava lava revised this gist Jun 20, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion hello_world.md
    Original file line number Diff line number Diff line change
    @@ -49,7 +49,7 @@ and taking no arguments. The program thus fulfills the requirements of
    the program.

    The body of the main function consists of an expression statement as in §6.2/1 [stmt.expr].
    The expression inside that statement refers to three distinct objects by name:
    The expression inside that statement refers to three distinct entities by name:

    1) The object `std::cout` of type `std::ostream` (27.4.2 [narrow.stream.objects]),

  10. @lava lava revised this gist Jun 20, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion hello_world.md
    Original file line number Diff line number Diff line change
    @@ -56,7 +56,7 @@ The expression inside that statement refers to three distinct objects by name:
    2) The string literal `"Hello, world!"` (a static null-terminated byte string
    according to §17.5.2.1.4.1/3 Footnote 170), of type `const char[14]`, and

    3) The function `std::endl` of type `std::ostream&(std::ostream&)`
    3) The function template `std::endl` with the signature `std::basic_ostream<C,T>&(std::basic_ostream<C,T>&)`

    These are joined by two instances of the binary left-shift operator, which
    groups left-to-right. Therefore, to determine what will happen, we first have to
  11. @lava lava revised this gist Jun 19, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion hello_world.md
    Original file line number Diff line number Diff line change
    @@ -178,7 +178,7 @@ Inside `main()`, the two functions
    _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
    _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc

    defined in the shared library `libstdc++` are called for the first time, so when
    defined in the shared library `libstdc++.so.6` are called for the first time, so when
    the program jumps to their PLT-slots, a symbol lookup will be triggered. (`<glibc>/elf/dl-lookup.c`)

    What these functions do is more or less up to the standard library implementors,
  12. @lava lava revised this gist Jun 19, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion hello_world.md
    Original file line number Diff line number Diff line change
    @@ -183,7 +183,7 @@ the program jumps to their PLT-slots, a symbol lookup will be triggered. (`<glib

    What these functions do is more or less up to the standard library implementors,
    but ultimately the syscall `write(1, p, 14)` will be issued, where the arguments
    are the file descriptor 1, which is mapped to stdout, a pointer `p` containing
    are the file descriptor 1, which is mapped to stdout, a pointer p containing
    the address of the string "Hello, world!\n", and the number of bytes that should
    be written.

  13. @lava lava revised this gist Jun 19, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion hello_world.md
    Original file line number Diff line number Diff line change
    @@ -137,7 +137,7 @@ Probably we will have an ELF file, which can be recognized by the magic bytes
    by `<linux>/fs/binfmt_elf.c:load_elf_binary()`, where the elf header and the program
    header table are loaded into memory.

    First thing to do is look for a PT_INTERP section, which contains then name
    First thing to do is look for a `PT_INTERP` section, which contains then name
    of the program interpreter, another ELF executable identified by a fixed path
    on the file system, in our example `"/lib64/ld-linux-x86-64.so.2"`. If there is
    an interpreter, again the kernel needs to locate the correct file, check
  14. @lava lava revised this gist Jun 19, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion hello_world.md
    Original file line number Diff line number Diff line change
    @@ -144,7 +144,7 @@ an interpreter, again the kernel needs to locate the correct file, check
    permissions, etc.

    After all checks are done and passed, the page table of the old process is
    cleared, and a new mapping set up. All PT_LOAD sections of the binary are mapped
    cleared, and a new mapping set up. All `PT_LOAD` sections of the binary are mapped
    into their respective places, and a memory region for the stack is allocated at
    a random address. Then, the load sections of the interpreter, which is
    position-independent, are mapped into private, write-protected pages at some
  15. @lava lava revised this gist Jun 19, 2016. 1 changed file with 10 additions and 10 deletions.
    20 changes: 10 additions & 10 deletions hello_world.md
    Original file line number Diff line number Diff line change
    @@ -48,7 +48,7 @@ and taking no arguments. The program thus fulfills the requirements of
    §3.6.1 [basic.start.main] and this function will be the designated start of
    the program.

    The body of the main function consists of an expression statement (§6.2/1),
    The body of the main function consists of an expression statement as in §6.2/1 [stmt.expr].
    The expression inside that statement refers to three distinct objects by name:

    1) The object `std::cout` of type `std::ostream` (27.4.2 [narrow.stream.objects]),
    @@ -118,9 +118,9 @@ free-standing environment.
    Let's for simplicity assume we're on a standard GNU/Linux system on x86_64.
    Then, our program had a parent process, which gave birth by way of `exec(3)`.

    This means it had to store the syscall number 59 in register $rax, the virtual
    This means it had to store the syscall number 59 in register `$rax`, the virtual
    memory addresses of the file name, the argument array, and the environment array
    in the registers $rdi, $rsi,$rdx, and execute the SYSCALL instruction.
    in the registers `$rdi`, `$rsi` and `$rdx`, and execute the `SYSCAL`L instruction.

    This crosses the border from user space to the kernel, which is now responsible
    for walking the file system to the given path, and opening the file for
    @@ -133,13 +133,13 @@ registered binfmt-handlers is walked to see if one of them recognizes the
    format.

    Probably we will have an ELF file, which can be recognized by the magic bytes
    "\x7fELF" at the start of the file. In this case, the loading will be performed
    `"\x7fELF"` at the start of the file. In this case, the loading will be performed
    by `<linux>/fs/binfmt_elf.c:load_elf_binary()`, where the elf header and the program
    header table are loaded into memory.

    First thing to do is look for a PT_INTERP section, which contains then name
    of the program interpreter, another ELF executable identified by a fixed path
    on the file system, in our example "/lib64/ld-linux-x86-64.so.2". If there is
    on the file system, in our example `"/lib64/ld-linux-x86-64.so.2"`. If there is
    an interpreter, again the kernel needs to locate the correct file, check
    permissions, etc.

    @@ -153,21 +153,21 @@ free part of the address space.
    When the memory is set up, control is transferred back to user space, in
    particular to the entry point of the interpreter.

    The interpreter reads the DT_NEEDED tags of the binary to determine the shared
    The interpreter reads the `DT_NEEDED` tags of the binary to determine the shared
    library dependencies, which will in our case consist of `libstdc++.so.6`, `libc.so.6`,
    `libm.so.6`, and `libgcc_s.so.1`. The interpreter tries to locate each of these
    libraries and map them into memory at a randomly chosen address. A list of
    library load addresses is maintained in the static global `struct _r_debug`. (/usr/include/link.h)
    library load addresses is maintained in the static global `struct _r_debug`. (`/usr/include/link.h`)
    However, unless the environment variable `LD_BIND_NOW` is set to 1,
    the function symbols will not be resolved right now but lazily on the first
    call to the respective function.

    After doing its thing, the dynamic loader passes control to the entry
    point of the actual binary, which is the symbol `_start` defined by glibc. (<glibc>/sysdeps/x86_64/start.S)
    point of the actual binary, which is the symbol `_start` defined by glibc. (`<glibc>/sysdeps/x86_64/start.S`)
    This starting point will setup an initial stack frame,
    compute the correct values for argc, argv and env from the information in
    the auxiliary vector, and call the C runtime initialization
    function `__libc_start_main`. (<glibc>/csu/libc-start.c)
    function `__libc_start_main`. (`<glibc>/csu/libc-start.c`)

    This will run static initialization functions, in particular constructors of all
    static objects, and install atexit-handlers for static destruction
    @@ -179,7 +179,7 @@ Inside `main()`, the two functions
    _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc

    defined in the shared library `libstdc++` are called for the first time, so when
    the program jumps to their PLT-slots, a symbol lookup will be triggered. (<glibc>/elf/dl-lookup.c)
    the program jumps to their PLT-slots, a symbol lookup will be triggered. (`<glibc>/elf/dl-lookup.c`)

    What these functions do is more or less up to the standard library implementors,
    but ultimately the syscall `write(1, p, 14)` will be issued, where the arguments
  16. @lava lava revised this gist Jun 19, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion hello_world.md
    Original file line number Diff line number Diff line change
    @@ -15,7 +15,7 @@ It will print out "Hello, world!".

    ## The Apprentice

    Assuming a unix system, the program will write the string "Hello, world!\n" to
    Assuming a unix system, the program will write the string `"Hello, world!\n"` to
    the standard output stream, which is connected to file descriptor 1. Afterwards,
    the stream is flushed.

  17. @lava lava revised this gist Jun 19, 2016. 1 changed file with 9 additions and 9 deletions.
    18 changes: 9 additions & 9 deletions hello_world.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    ## Hello, world!
    # Hello, world!

    Please explain in detail what will happen if the following program is executed:

    @@ -8,19 +8,19 @@ Please explain in detail what will happen if the following program is executed:
    std::cout << "Hello, world!" << std::endl;
    }

    # The Novice
    ## The Novice

    It will print out "Hello, world!".


    # The Apprentice
    ## The Apprentice

    Assuming a unix system, the program will write the string "Hello, world!\n" to
    the standard output stream, which is connected to file descriptor 1. Afterwards,
    the stream is flushed.


    # The Pedant
    ## The Pedant

    The given text is not a program, but rather UTF-8 encoded C++ source code.
    After being turned into a program by a C++ compiler, it's impossible to tell
    @@ -29,7 +29,7 @@ a SIGABRT signal immediately after it started, in which case the effect would
    probably be the creation of a core dump in the current directory.


    # The Lawyer
    ## The Lawyer

    Lets analyze the program according to the C++ Draft Standard in version N4296.

    @@ -104,12 +104,12 @@ statement, which has has the effect of destroying any objects with automatic
    storage duration and calling `std::exit()` with the argument `0`. (§3.6.1/5)


    # The Ideologue
    ## The Ideologue

    Let's just re-write it in a purely functional way.


    # The Engineer
    ## The Engineer

    From the lack of any platform specific initialization code, we can
    infer that the program is intended to be run in a hosted as opposed to a
    @@ -193,7 +193,7 @@ by executing the system call `exit_group()`, with the only argument being the
    value returned by `main()` which is 0.


    # The Physicist
    ## The Physicist

    A program must run on a CPU, and a CPU is made of metal.
    Information is transmitted through metal by letting electrons flow along local
    @@ -203,6 +203,6 @@ system which will evolve according to its wave function.
    Therefore, we can't know what the program does until we measure it's outcome.


    # The Enlightened
    ## The Enlightened

    It will print out "Hello, world!".
  18. @lava lava revised this gist Jun 19, 2016. 1 changed file with 4 additions and 4 deletions.
    8 changes: 4 additions & 4 deletions hello_world.md
    Original file line number Diff line number Diff line change
    @@ -96,7 +96,7 @@ overload is
    std::ostream::operator<<(std::ostream&(*f)(std::ostream& os))

    from §27.7.3.6.3 [ostream.inserters]. This function returns `f(*this)`,
    and calling `std::endl` has the effect of calling `os.put(os.widen('\n'))
    and calling `std::endl` has the effect of calling `os.put(os.widen('\n'))`
    followed by `os.flush()`. (§27.7.3.8/1 [ostream.manip])

    Finally, control reaches the end of main without encountering a return
    @@ -157,15 +157,15 @@ The interpreter reads the DT_NEEDED tags of the binary to determine the shared
    library dependencies, which will in our case consist of `libstdc++.so.6`, `libc.so.6`,
    `libm.so.6`, and `libgcc_s.so.1`. The interpreter tries to locate each of these
    libraries and map them into memory at a randomly chosen address. A list of
    library load addresses is maintained in the static global struct _r_debug. (`/usr/include/link.h`)
    However, unless the environment variable LD_BIND_NOW is set to 1,
    library load addresses is maintained in the static global `struct _r_debug`. (/usr/include/link.h)
    However, unless the environment variable `LD_BIND_NOW` is set to 1,
    the function symbols will not be resolved right now but lazily on the first
    call to the respective function.

    After doing its thing, the dynamic loader passes control to the entry
    point of the actual binary, which is the symbol `_start` defined by glibc. (<glibc>/sysdeps/x86_64/start.S)
    This starting point will setup an initial stack frame,
    compute the correct values for `argc`, `argv` and `env` from the information in
    compute the correct values for argc, argv and env from the information in
    the auxiliary vector, and call the C runtime initialization
    function `__libc_start_main`. (<glibc>/csu/libc-start.c)

  19. @lava lava created this gist Jun 19, 2016.
    208 changes: 208 additions & 0 deletions hello_world.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,208 @@
    ## Hello, world!

    Please explain in detail what will happen if the following program is executed:

    #include <iostream>

    int main() {
    std::cout << "Hello, world!" << std::endl;
    }

    # The Novice

    It will print out "Hello, world!".


    # The Apprentice

    Assuming a unix system, the program will write the string "Hello, world!\n" to
    the standard output stream, which is connected to file descriptor 1. Afterwards,
    the stream is flushed.


    # The Pedant

    The given text is not a program, but rather UTF-8 encoded C++ source code.
    After being turned into a program by a C++ compiler, it's impossible to tell
    what will happen after it is executed. One possibility would be that it receives
    a SIGABRT signal immediately after it started, in which case the effect would
    probably be the creation of a core dump in the current directory.


    # The Lawyer

    Lets analyze the program according to the C++ Draft Standard in version N4296.

    Since <iostream> is one of the 53 C++ standard library header listed
    in §17.6.1.2/2 [headers], its contents will be made available to the translation
    unit. (§17.6.2.2/1 [using.headers])

    Including this header causes the effects of defining an instance
    of `ios_base::Init` with static storage duration. (§27.4.1/2 [iostream.objects.overview])
    During or before construction of this instance, the object `std::cout` of type
    `ostream` is constructed and associated with the object `stdout` declared in
    the <cstdio> header. (§27.4.2/1 [narrow.stream.objects])

    Next, we see the definition of a global function called `main` returning an int
    and taking no arguments. The program thus fulfills the requirements of
    §3.6.1 [basic.start.main] and this function will be the designated start of
    the program.

    The body of the main function consists of an expression statement (§6.2/1),
    The expression inside that statement refers to three distinct objects by name:

    1) The object `std::cout` of type `std::ostream` (27.4.2 [narrow.stream.objects]),

    2) The string literal `"Hello, world!"` (a static null-terminated byte string
    according to §17.5.2.1.4.1/3 Footnote 170), of type `const char[14]`, and

    3) The function `std::endl` of type `std::ostream&(std::ostream&)`

    These are joined by two instances of the binary left-shift operator, which
    groups left-to-right. Therefore, to determine what will happen, we first have to
    look at the sub-expression `std::cout << "Hello, world!"`, which is the left
    shift operator with operands of type `std::ostream` and `const char[14]`.

    Since at least one operand has class or enumeration type, overload resolution is
    used to determine which operator-function or built-in operator is invoked.
    (§13.3.1.2/2 [over.match.oper])

    The set of candidate functions is constructed according to the rules detailed
    in §13.3.1.2/3. They consist of the result of the qualified lookup of
    `std::ostream::operator<<` (§13.3.1.2/3.1), together with the result of the
    unqualified lookup of `operator<<` in the context of the expression. (§13.3.1.2/3.2)
    Since the operands can't be converted to a pair of promoted integral types,
    the requirement of clause §13.3.1.2/3.3.3 is not be fulfilled and there are no
    built-in operator candidates.

    The best match is the template function specialization

    std::ostream& std::operator<< (std::ostream& out, char const*)

    from §27.7.3.6.4 [ostream.inserters.character], which behaves like a formatted
    inserter of out. (§27.7.3.6.1 [ostream.formatted.reqmts])

    Therefore, the calling this function will begin by constructing an object of
    class `std::sentry`. (§27.7.3.4 [ostream.sentry]) If this object returns `true`
    when converted to bool, the function will proceed to create a character
    sequence `seq` of 14 characters, each widened using out.widen(), to
    insert `seq` into `out`, and to call `width(0)`. (§27.7.3.6.4/3) Finally,
    the sentry object is destroyed before leaving the function.

    The same procedure is repeated for the next left shift operator, which has
    operands of type `std::ostream&` and `ostream&(ostream&). Here, the selected
    overload is

    std::ostream::operator<<(std::ostream&(*f)(std::ostream& os))

    from §27.7.3.6.3 [ostream.inserters]. This function returns `f(*this)`,
    and calling `std::endl` has the effect of calling `os.put(os.widen('\n'))
    followed by `os.flush()`. (§27.7.3.8/1 [ostream.manip])

    Finally, control reaches the end of main without encountering a return
    statement, which has has the effect of destroying any objects with automatic
    storage duration and calling `std::exit()` with the argument `0`. (§3.6.1/5)


    # The Ideologue

    Let's just re-write it in a purely functional way.


    # The Engineer

    From the lack of any platform specific initialization code, we can
    infer that the program is intended to be run in a hosted as opposed to a
    free-standing environment.

    Let's for simplicity assume we're on a standard GNU/Linux system on x86_64.
    Then, our program had a parent process, which gave birth by way of `exec(3)`.

    This means it had to store the syscall number 59 in register $rax, the virtual
    memory addresses of the file name, the argument array, and the environment array
    in the registers $rdi, $rsi,$rdx, and execute the SYSCALL instruction.

    This crosses the border from user space to the kernel, which is now responsible
    for walking the file system to the given path, and opening the file for
    reading. (`<linux>/fs/exec.c:open_exec()`)

    If the file exists, has the right permissions etc., the binary format of the
    executable needs to be determined. To do this, the first `BINPRM_BUF_SIZE` bytes
    are loaded into memory (`<linux>/fs/exec.c:prepare_binprm()`), and the list of
    registered binfmt-handlers is walked to see if one of them recognizes the
    format.

    Probably we will have an ELF file, which can be recognized by the magic bytes
    "\x7fELF" at the start of the file. In this case, the loading will be performed
    by `<linux>/fs/binfmt_elf.c:load_elf_binary()`, where the elf header and the program
    header table are loaded into memory.

    First thing to do is look for a PT_INTERP section, which contains then name
    of the program interpreter, another ELF executable identified by a fixed path
    on the file system, in our example "/lib64/ld-linux-x86-64.so.2". If there is
    an interpreter, again the kernel needs to locate the correct file, check
    permissions, etc.

    After all checks are done and passed, the page table of the old process is
    cleared, and a new mapping set up. All PT_LOAD sections of the binary are mapped
    into their respective places, and a memory region for the stack is allocated at
    a random address. Then, the load sections of the interpreter, which is
    position-independent, are mapped into private, write-protected pages at some
    free part of the address space.

    When the memory is set up, control is transferred back to user space, in
    particular to the entry point of the interpreter.

    The interpreter reads the DT_NEEDED tags of the binary to determine the shared
    library dependencies, which will in our case consist of `libstdc++.so.6`, `libc.so.6`,
    `libm.so.6`, and `libgcc_s.so.1`. The interpreter tries to locate each of these
    libraries and map them into memory at a randomly chosen address. A list of
    library load addresses is maintained in the static global struct _r_debug. (`/usr/include/link.h`)
    However, unless the environment variable LD_BIND_NOW is set to 1,
    the function symbols will not be resolved right now but lazily on the first
    call to the respective function.

    After doing its thing, the dynamic loader passes control to the entry
    point of the actual binary, which is the symbol `_start` defined by glibc. (<glibc>/sysdeps/x86_64/start.S)
    This starting point will setup an initial stack frame,
    compute the correct values for `argc`, `argv` and `env` from the information in
    the auxiliary vector, and call the C runtime initialization
    function `__libc_start_main`. (<glibc>/csu/libc-start.c)

    This will run static initialization functions, in particular constructors of all
    static objects, and install atexit-handlers for static destruction
    functions (again, in particular destructors of static objects).

    Inside `main()`, the two functions

    _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
    _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc

    defined in the shared library `libstdc++` are called for the first time, so when
    the program jumps to their PLT-slots, a symbol lookup will be triggered. (<glibc>/elf/dl-lookup.c)

    What these functions do is more or less up to the standard library implementors,
    but ultimately the syscall `write(1, p, 14)` will be issued, where the arguments
    are the file descriptor 1, which is mapped to stdout, a pointer `p` containing
    the address of the string "Hello, world!\n", and the number of bytes that should
    be written.

    Finally, the program returns the process signals to the operating system
    that it is finished and all of its resources should be freed and cleaned up
    by executing the system call `exit_group()`, with the only argument being the
    value returned by `main()` which is 0.


    # The Physicist

    A program must run on a CPU, and a CPU is made of metal.
    Information is transmitted through metal by letting electrons flow along local
    gradients, increasing the entropy of the system.
    All of these electrons, together with the atoms of the CPU, form a huge quantum
    system which will evolve according to its wave function.
    Therefore, we can't know what the program does until we measure it's outcome.


    # The Enlightened

    It will print out "Hello, world!".