Expand description
The crate is part of the linktime project.
§dtor
Shutdown functions for Rust (like __attribute__((destructor)) in C/C++) for
Linux, macOS, Windows, mobile (iOS/Android), WASM, BSD/BSD-likes and many other
platforms.
use dtor::dtor;
use libc_print::*;
#[dtor(unsafe)]
fn foo() {
libc_println!("Life after main!");
}§Examples
Print a message at shutdown time.
#[dtor(unsafe)]
fn shutdown() {
// Using println! or eprintln! here may panic as Rust may have
// shut down some stdlib services at this time.
libc_println!("Shutting down!");
}§Platform Support
| Platform | Link Section | at_binary_exit | at_module_exit |
|---|---|---|---|
| Linux | .fini_array | Yes (atexit) | Yes (__cxa_atexit) |
| macOS | .mod_term_func 🍎 | Yes (atexit) | Yes (__cxa_atexit) |
| Windows | .CRT$XPU 🪟 | No | Yes (atexit) |
| WASM 🕸️ | No | Yes | No |
| AIX | “Kind of” 🔵 | Yes | Yes |
| Other POSIX-like platforms | .fini_array/.dtors | Yes (atexit) | Yes (__cxa_atexit) |
Notes:
- 🍎 Not recommended. Apple platforms no longer call
mod_term_funcfunctions. - 🪟 Not recommended. Windows platforms may not reliably call functions in link sections, unless a binary is built with a static CRT.
- 🔵 Link sections are not supported on AIX, but the
platform calls functions with the prefix
__sinitand__stermat startup and shutdown respectively.__sterm-prefixed functions are used when the method is specified aslinker. - 🕸️ WASM
wasm-unknown-unknown,wasm-wasip1,wasm-wasip2are supported.- Rust does not currently allow linking into
.fini_arraysections on WASM, regardless of target, soat_binary_exitis the only supported method on all WASM targets. wasm-unknown-unknownrequires host environment support foratexit.wasm-wasip2may require you to manually call__wasm_call_ctorsand__wasm_call_dtorsat the appropriate times.
- Rust does not currently allow linking into
§Shutdown Method (#[dtor(method = ...)])
The #[dtor] macro supports multiple registration strategies via
#[dtor(method = ...)]. The best choice is platform-dependent:
#[dtor](no method specified): Use the platform’s most reliable method:at_module_exiton Windows and Apple platforms, andlinkeron others.unload: Run on module unload (library unload or process exit) using the platform’s default unload method.term: Run on process termination only using the platform’s default termination method. Not recommended: code may be unloaded before the dtor runs.at_module_exit: Register using__cxa_atexit(non-Windows) oratexit(Windows) so the dtor runs when the module unloads. Unsupported on WASM.at_binary_exit: Register to run at process exit (unsupported on Windows).linker: Register using the platform’s linker mechanism (link_sectionon all platforms with the exception ofexport_name_prefixon AIX). Unsupported on Apple platforms.
Default:
- Apple and Windows default to
at_module_exit - WASM defaults to
at_binary_exit(note that you will need to provide your own atexit implementation forwasm32-unknown-unknown) - Most other platforms default to
linker
Examples:
use dtor::dtor;
/// Use `at_module_exit` on all platforms
#[dtor(unsafe, method = at_module_exit)]
fn shutdown() {}use dtor::dtor;
/// Use `link_section` with a section name of `.dtors` on most platforms,
/// and `export_name_prefix` on AIX.
///
/// Platform note: this will fail to compile on Apple platforms.
#[dtor(unsafe, method = linker, link_section = ".dtors")]
fn shutdown() {}§Warnings
Rust’s philosophy is that nothing happens before or after main and this library
explicitly subverts that. The code that runs in the ctor and dtor functions
should be careful to limit itself to libc functions and code that does not
rely on Rust’s stdlib services.
See ::life_before_main for more information.
§Under the Hood
The #[dtor] macro effectively creates a constructor that calls libc::atexit
with the provided function, i.e. roughly equivalent to:
#[ctor]
fn dtor_atexit() {
libc::atexit(dtor);
}§Crate Features
| Cargo feature | Description |
|---|---|
proc_macro | Enable support for the proc-macro #[dtor] attribute. The declarative form (dtor!(...)) is always available. It is recommended that crates re-exporting the dtor macro disable this feature and only use the declarative form. |
std | Enable support for the standard library. |
§Macro Attributes
| Attribute | Description |
|---|---|
anonymous |
Do not give the destructor’s registration entry a name in the generated
code (allows for multiple items with the same name). Equivalent to
wrapping the registration in an anonymous const (i.e.: |
crate_path = ::path::to::dtor::crate |
Specify a custom crate path for the |
ctor(export_name_prefix = "ctor_") |
Specify a custom export name prefix for the generated constructor function. If specified, an export with the given prefix will be generated in the form:
|
ctor(link_section = ".ctors") |
Place the generated registration constructor’s function pointer in a custom link section. |
export_name_prefix = "ctor_" |
Specify a custom export name prefix for the destructor function. If specified, an export with the given prefix will be generated in the form:
|
link_section = ".dtors" |
Place the destructor function pointer in a custom link section. |
method = term|unload|at_module_exit|at_binary_exit|linker |
Specify the dtor method.
|
unsafe |
Marks a dtor as unsafe. Required. The |
used(linker) |
Mark generated function pointers This can be made the default by using the For a crate using this macro to function correctly with and without this flag, it is recommended to add the following line to the top of lib.rs in the crate root:
|
§Defaults
§ctor_export_name_prefix
#[cfg(target_os = "aix")]
ctor_export_name_prefix = "__sinit80000000"
// default
ctor_export_name_prefix = ()§ctor_link_section
#[cfg(target_vendor = "apple")]
ctor_link_section = "__DATA,__mod_init_func,mod_init_funcs"
#[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd",
target_os = "netbsd", target_os = "openbsd", target_os = "dragonfly",
target_os = "illumos", target_os = "haiku", target_os = "vxworks", target_os =
"nto", target_family = "wasm"))]
ctor_link_section = ".init_array"
#[cfg(target_os = "none")]
ctor_link_section = ".init_array"
#[cfg(target_arch = "xtensa")]
ctor_link_section = ".ctors"
#[cfg(all(target_vendor = "pc", any(target_env = "gnu", target_env = "msvc")))]
ctor_link_section = ".CRT$XCU"
#[cfg(all(target_vendor = "pc", not(any(target_env = "gnu", target_env = "msvc"))))]
ctor_link_section = ".ctors"
#[cfg(all(target_os = "aix"))]
ctor_link_section = ()
// default
ctor_link_section = (compile_error! ("Unsupported target for #[ctor]"))§default_term_method
#[cfg(target_vendor = "pc")]
default_term_method = at_module_exit
// default
default_term_method = at_binary_exit§default_unload_method
// default
default_unload_method = at_module_exit§export_name_prefix
#[cfg(target_os = "aix")]
export_name_prefix = "__sterm80000000"
// default
export_name_prefix = ()§link_section
#[cfg(target_vendor = "apple")]
link_section = "__DATA,__mod_term_func,mod_term_funcs"
#[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd",
target_os = "netbsd", target_os = "dragonfly", target_os = "illumos",
target_os = "haiku", target_os = "vxworks", target_os = "nto", target_family =
"wasm"))]
link_section = ".fini_array"
#[cfg(target_os = "openbsd")]
link_section = ".dtors"
#[cfg(target_os = "none")]
link_section = ".fini_array"
#[cfg(target_arch = "xtensa")]
link_section = ".dtors"
#[cfg(all(target_vendor = "pc", any(target_env = "gnu", target_env = "msvc")))]
link_section = ".CRT$XPU"
#[cfg(all(target_vendor = "pc", not(any(target_env = "gnu", target_env = "msvc"))))]
link_section = ".dtors"
#[cfg(all(target_os = "aix"))]
link_section = ()
// default
link_section = (compile_error! ("Unsupported target for #[dtor]"))§method
#[cfg(target_vendor = "apple")]
method = at_module_exit
#[cfg(target_vendor = "pc")]
method = at_module_exit
#[cfg(target_family = "wasm")]
method = at_binary_exit
#[cfg(target_os = "openbsd")]
method = at_module_exit
// default
method = linker§r#unsafe
#[cfg(linktime_no_fail_on_missing_unsafe)]
r#unsafe = (no_fail_on_missing_unsafe)
// default
r#unsafe = ()§used_linker
#[cfg(linktime_used_linker)]
used_linker = used_linker
// default
used_linker = ()Modules§
- declarative
- Declarative forms of the
#[dtor]macro. - life_
before_ main - Life-Before-Main and Other Link-Time Hazards
Functions§
- at_
binary_ ⚠exit - Registers a raw function to be called at binary exit time.
- at_
module_ ⚠exit - Registers a raw function to be called at library (libc calls this a DSO or “dynamic shared object”) exit time.
Attribute Macros§
- dtor
- Marks a function as a library/executable destructor. This uses OS-specific linker sections to call a specific function at termination time.