← Back to context

Comment by jeffbee

2 days ago

The general lesson of these things is main is not that special and it pays to understand how your program actually starts. This has little/nothing to do with Rust or other language tools. On Linux, given a static ELF program, the kernel returns to the IP given by e_entry, which can proceed to do anything. If the program is dynamic (has a .interp) then it loads the interpreter and returns to its e_entry instead. The interpreter, in turn, can do absolutely whatever.

The relevance to Rust is precisely that it doesn't have life before main at the language level; therefore, if you need it*, you need to use these kinds of linker hacks (which fortunately are amenable to encapsulation through macros). By contrast, if the article were about C++, the focus would be on "what happens under the hood when you use static initialization, in case you were curious" rather than "how to use these low-level mechanisms to do something not otherwise possible".

* Which you should think very carefully before concluding is the case, as it's responsible for rather a lot of bugs in C++. I think in Rust it is mostly used for registry-pattern type stuff since the const system can't currently(?) handle that.

  • Yes. There isn't Rust language support for this.

    Order of initialization can be supported at various levels:

    - Completely random (OK if interdependence are locked out, otherwise bad)

    - Consistent, but sorted by something such as alphabetical name (meh.)

    - Manual, controlled in linker scripts (headache)

    - True dependency tree order, including diagnosing loops (seen in the Modula family).

    General comment: yes, you can, and you probably shouldn't unless you have profiling data that indicates a significant performance improvement for a critical use case.

    • I think these things are used more for developer experience than for performance, since you can always just do the initialization in main if you really have to.

      4 replies →

  • You don't need linker hacks to control what happens before main in Rust. You can disable the default runtime setup with `#![no_main]` in your crate root, and then manually designate a starting point via an unmangled function named appropriately for your specific platform (e.g. `_start`).