Be it statically or dynamically linked, the startup of glibc-based programs is quite hairy on GNU Hurd systems.

open issue documentation, open issue glibc

How libc startup in a process works

Statically-linked program

  • The ELF headers points program start at _start.
  • _start (sysdeps/mach/hurd/i386/static-start.S) calls _hurd_stack_setup
  • _hurd_stack_setup (sysdeps/mach/hurd/i386/init-first.c) calls first_init which calls __mach_init to initialize enough to run RPCs, then runs the _hurd_preinit_hook hooks, which initialize global variables of libc.
  • _hurd_stack_setup (sysdeps/mach/hurd/i386/init-first.c) calls _hurd_startup.
  • _hurd_startup (hurd/hurdstartup.c) gets hurdish information from servers and calls its main parameter.
  • the main parameter was actually doinit (in sysdeps/mach/hurd/i386/init-first.c), which mangles the stack and calls doinit1 which calls init.
  • init sets threadvars, tries to initialize threads (and perhaps switches to the new stack) and gets to call init1.
  • init1 gets the Hurd block, calls _hurd_init on it
  • _hurd_init (hurd/hurdinit.c) initializes initial ports, starts the signal thread, runs the _hurd_subinit hooks (init_dtable hurd/dtable.c notably initializes the FD table and the _hurd_fd_subinit hooks, which notably checks std*).
  • We are back to _start, which jumps to _start1 which is the normal libc startup which calls __libc_start_main
  • __libc_start_main (actually called LIBC_START_MAIN in csu/libc-start.c) initializes libc, tls, libpthread, atexit
  • __libc_start_main calls initialization function given as parameter __libc_csu_init,
  • __libc_csu_init (csu/elf-init.c) calls preinit_array_start functions
  • __libc_csu_init calls _init
  • _init (sysdeps/i386/crti.S) calls PREINIT_FUNCTION, (actually libpthread on Linux, __gmon_start__ on hurd)
  • back to __libc_csu_init calls init_array_start functions
  • back to __libc_start_main, it calls calls application's main, then exit.

dynamically-linked program

  • dl.so ELF headers point its start at _start.
  • _start (sysdeps/i386/dl-machine.h) calls _dl_start.
  • _dl_start (elf/rtld.c) initializes bootstrap_map, calls _dl_start_final
  • _dl_start_final calls _dl_sysdep_start.
  • _dl_sysdep_start (sysdeps/mach/hurd/dl-sysdep.c) calls __mach_init to initialize enough to run RPCs, then calls _hurd_startup.
  • _hurd_startup (hurd/hurdstartup.c) gets hurdish information from servers and calls its main parameter.
  • the main parameter was actually go inside _dl_sysdep_start, which calls dl_main.
  • dl_main (elf/rtld.c) interprets ld.so parameters, loads the binary and libraries, calls _dl_allocate_tls_init.
  • we are back to go, which branches to _dl_start_user.
  • _dl_start_user (./sysdeps/i386/dl-machine.h) runs RTLD_START_SPECIAL_INIT (sysdeps/mach/hurd/i386/dl-machine.h) which calls _dl_init_first.
  • _dl_init_first (sysdeps/mach/hurd/i386/init-first.c) calls first_init which calls __mach_init to initialize enough to run RPCs, then runs the _hurd_preinit_hook hooks, which initialize global variables of libc.
  • _dl_init_first calls init.
  • init sets threadvars, tries to initialize threads (and perhaps switches to the new stack) and gets to call init1.
  • init1 gets the Hurd block, calls _hurd_init on it
  • _hurd_init (hurd/hurdinit.c) initializes initial ports, starts the signal thread, runs the _hurd_subinit hooks (init_dtable hurd/dtable.c notably initializes the FD table and the _hurd_fd_subinit hooks, which notably checks std*).
  • we are back to _dl_start_user, which calls _dl_init (elf/dl-init.c) which calls application initializers.
  • _dl_start_user jumps to the application's entry point, _start
  • _start (sysdeps/i386/start.S) calls __libc_start_main
  • __libc_start_main (actually called LIBC_START_MAIN in csu/libc-start.c) initializes libc, atexit,
  • __libc_start_main calls initialization function given as parameter __libc_csu_init,
  • __libc_csu_init (csu/elf-init.c) calls _init
  • _init (sysdeps/i386/crti.S) calls PREINIT_FUNCTION, (actually libpthread on Linux, __gmon_start__ on hurd)
  • back to __libc_csu_init calls init_array_start functions
  • back to __libc_start_main, it calls application's main, then exit.

IRC, freenode, #hurd, 2013-12-31

<youpi> braunr: btw, after patching glibc and trying installing it, do you
  try rebuilding hurd against it? ext2fs.static often breaks due to details
<braunr> youpi: yes
<braunr> youpi: always
<youpi> ok, good :)
<braunr> i want the rootfs to benefit from it too :)
<youpi> heh :)
<braunr> and yes, there were issues that occurred only in the rootfs
<braunr> but because of the special early state, not because of static
  linking