Live data from Hacker News

There Is Life Before Main in Rust

grack.com

21–28 of 28 posts

Re: There Is Life Before Main in Rust

#21
post #6

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 i…

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…

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`).

Re: There Is Life Before Main in Rust

#22
post #6

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 i…

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…

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.

Re: There Is Life Before Main in Rust

#23
post #22

Earlier quoted context omitted.

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…

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,…

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.

Re: There Is Life Before Main in Rust

#24
post #22

Earlier quoted context omitted.

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,…

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.

It's something of an issue if you have some crate that needs to set itself up at load time without a call from main. But those are very rare. Even "simplelog" needs a call at startup to do anything.

Re: There Is Life Before Main in Rust

#25
post #24

Earlier quoted context omitted.

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.

It's something of an issue if you have some crate that needs to set itself up at load time without a call from main. But those are very rare. Even "simplelog" needs a call at startup to do anything.

Yeah, I think of avoiding the call from main as a devex consideration rather than a performance one, since either way the initialization code runs once at process startup.

Re: There Is Life Before Main in Rust

#26
I ran into this with embedded Rust: put alloc in a .init_array function, but the global allocator also uses .init_array, and there's no ordering guarantee. Took me hours to figure out why I was getting garbage from the heap before main.

Re: There Is Life Before Main in Rust

#27
post #24

Earlier quoted context omitted.

It's something of an issue if you have some crate that needs to set itself up at load time without a call from main. But those are very rare. Even "simplelog" needs a call at startup to do anything.

Yeah, I think of avoiding the call from main as a devex consideration rather than a performance one, since either way the initialization code runs once at process startup.

I'm trying to think of any useful crate that really uses this. "Tracy", the profiling crate, used to self-start on loading, but that was changed to require a call to get it going.

Re: There Is Life Before Main in Rust

#28
post #24

Earlier quoted context omitted.

It's something of an issue if you have some crate that needs to set itself up at load time without a call from main. But those are very rare. Even "simplelog" needs a call at startup to do anything.

Yeah, I think of avoiding the call from main as a devex consideration rather than a performance one, since either way the initialization code runs once at process startup.

But it can cause problems when there's multiple crates trying to do it. If the call is explicit, the application developer can sequence the calls appropriately (or at least deterministically), as opposed to having the order determined by details of the implementation (something that was learned from the C++ 'static initialization order fiasco')
Post reply on HN