До вызова fn main() в Rust-бинарнике творится целая кухня. Каждый язык полагается на рантайм: для C это libc, для Rust — стандартная библиотека, построенная поверх C-рантайма. Рантайм настраивает аллокацию, файловый ввод-вывод, thread-local storage и обработку паник. Всё это происходит в однопоточном, предсказуемом окружении — идеальном для инициализации.
Точка входа в программу — платформенный хук вроде _start на Linux (хранится в e_entry ELF-заголовка) или _WinMainCRTStartup на Windows. Рантайм получает управление от загрузчика ОС и запускает цепочку инициализаторов. Раньше это было статическое дерево вызовов, но с появлением __attribute__((constructor)) в GCC конструкторы стали собираться линкером в разделы .init_array. Приоритеты (числовые суффиксы) позволяют управлять порядком, а линкер сам отбрасывает неиспользуемые части.
В Rust можно вручную размещать статики в нужные секции через #[unsafe(link_section = "...")]. Но есть и готовые абстракции — крейты ctor и link-section из проекта linktime. Например, #[ctor(unsafe, priority = 101)] регистрирует функцию, которая выполнится до main без явного вызова.
Линкер автоматически определяет символы __start_<section> и __stop_<section> для секций с совместимым именем. Эти символы — не указатели на данные, а границы секции, используемые для построения среза. link-section превращает это в нормальный Rust-срез: TypedSection<T> или TypedMutableSection<T>.
На этом механизме строится что-то вроде Dependency Injection: любой крейт в дереве зависимостей может «зарегистрировать» данные в общей секции, а потребитель просто читает срез. Пример — регистрация CLI-подкоманд: каждый модуль помещает свой CliSubcommand в секцию CLI_SUBCOMMANDS, а main ищет совпадение по имени.
Но круче то, что до main данные можно мутировать без блокировок. Потоков нет — достаточно обеспечить, чтобы все изменения «произошли до» любых чтений. Для этого статики оборачивают в UnsafeCell (или SyncUnsafeCell), а границы секции — в MaybeUninit. Пример: пул интернированных строк. До main конструктор сортирует срез через sort_unstable, а после main любой поток читает его безопасно, без мьютексов. Крейты ctor и link-section скрывают этот бухгалтерский ад.