Module initialization termination function with priorities and (mutable) statics initialization with non const functions.
Minimum rust version required: 1.49
# Functionalities
[x] Code execution before or after main
but after libc and rust runtime has been initialized.
[x] Mutable and const statics with non const initialization.
[x] Statics dropable after main
exits.
[x] Zero cost access to statics.
[x] Priorities on elf plateforms (linux, bsd, etc...) and window.
```rust use static_init::{constructor,destructor,dynamic};
fn do_init(){ } //Care not to use priorities bellow 100 //as those high priorities are used by //the rust runtime. (The lower the number //the higher the priority)
fn do_first(){ }
fn finaly() { }
fn ultimately() { }
static V: Vec
static mut V1: Vec
//Initialized before V1 //then destroyed after V1
static mut INITANDDROP: Vec
fn main(){ asserteq!(V[0],1); unsafe{ asserteq!(V1[2],3); V1[2] = 42; assert_eq!(V1[2], 42); } } ```
All functions marked with the constructor
attribute are
run before main
is started.
All function marked with the destructor
attribute are
run after main
has returned.
Static variables marked with the dynamic
attribute can
be initialized before main start and optionaly droped
after main returns.
The attributes constructor
and destructor
works by placing the marked function pointer in
dedicated object file sections.
Priority ranges from 0 to 216-1. The absence of priority is equivalent to 216.
During program initialization:
During program termination, the order is reversed:
Initialization functions pointers are placed in section "DATA,modinitfunc" and "DATA,modtermfunc"
info ld
ld --verbose
The runtime will run fonctions pointers of section ".initarray" at startup and function pointers in ".finiarray" at program exit. The linker place in the target object file sectio .initarray all sections from the source objects whose name is of the form .initarray.NNNNN in lexicographical order then the .initarray sections of those same source objects. It does equivalently with .finiarray and .fini_array.NNNN sections.
Usage can be seen in gcc source gcc/config/pru.c
Resources of libstdc++ are initialized with priority 100 (see gcc source libstdc++-v3/c++17/defaultresource.h) The rust standard library function that capture the environment and executable arguments is executed at priority 99. Some callbacks constructors and destructors with priority 0 are registered by rust/rtlibrary. Static C++ objects are usually initialized with no priority (TBC). lib-c resources are initialized by the C-runtime before any function in the initarray (whatever the priority) are executed.
At start up, any functions pointer between sections ".CRT$XIA" and ".CRT$XIZ" and then any functions between ".CRT$XCA" and ".CRT$XCZ". It happens that the C library initialization functions pointer are placed in ".CRT$XIU" and C++ statics functions initialization pointers are placed in ".CRT$XCU". At program finish the pointers between sections ".CRT$XPA" and ".CRT$XPZ" are run first then those between ".CRT$XTA" and ".CRT$XTZ".
Some reverse engineering was necessary to find out a way to implement constructor/destructor priority.
Contrarily to what is reported in this blog post, msvc linker
only performs a lexicographicall ordering of section whose name
is of the form "\ Moreover, it seems that section name of the form \ So static initialization function pointers are placed in section ".CRT$XCU" and
those with a priority p
in format!(".CRT$XCTZ{:05}",p)
. Destructors without priority
are placed in ".CRT$XPU" and those with a priority in format!(".CRT$XPTZ{:05}")
.