summaryrefslogtreecommitdiff
path: root/glibc/startup.mdwn
blob: 9a7a3de2d0672ee115676153dfa38c32101dc212 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
[[!meta copyright="Copyright © 2011, 2014, 2016, 2018 Free Software Foundation,
Inc."]]

[[!meta license="""[[!toggle id="license" text="GFDL 1.2+"]][[!toggleable
id="license" text="Permission is granted to copy, distribute and/or modify this
document under the terms of the GNU Free Documentation License, Version 1.2 or
any later version published by the Free Software Foundation; with no Invariant
Sections, no Front-Cover Texts, and no Back-Cover Texts.  A copy of the license
is included in the section entitled [[GNU Free Documentation
License|/fdl]]."]]"""]]

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

[[!taglink open_issue_documentation]], [[!taglink open_issue_glibc]]

  * [[!message-id "200103081944.f28JiDk00232@delius.kettenis.local"]]

  * [[!message-id "3B7BF2B1.1417CD84@alcor.concordia.ca"]]

  * [[!message-id "871xc9qv6y.wl@ulysses.g10code.de"]]


# 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