diff --git a/.lock b/.lock new file mode 100644 index 0000000..e69de29 diff --git a/crates.js b/crates.js new file mode 100644 index 0000000..e89c32d --- /dev/null +++ b/crates.js @@ -0,0 +1,2 @@ +window.ALL_CRATES = ["ctor_bare","ctor_bare_macros"]; +//{"start":21,"fragment_lengths":[11,19]} \ No newline at end of file diff --git a/ctor_bare/all.html b/ctor_bare/all.html new file mode 100644 index 0000000..9efdff8 --- /dev/null +++ b/ctor_bare/all.html @@ -0,0 +1 @@ +
Module initialization functions for Rust (like attribute((constructor)) in C/C++) under no_std.
+After registering a constructor function, a function pointer pointing to it will be stored in the .init_array
section.
It can support Linux, MacOS and other systems, and can be also used in no_std
environments when developing your own kernel.
In Linux, Windows, MacOS and other systems, the .init_array
section is a default section to store initialization functions. When the program starts, the system will call all functions in the .init_array
section in order.
When you are running your own operating system, you can call ctor_bare::call_ctors
to invoke all registered constructor functions.
use ctor_bare::register_ctor;
+#[register_ctor]
+fn hello_world() {
+ println!("Hello, world!");
+}
+
+static MAX_NUM: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
+
+#[register_ctor]
+fn set_max_num() {
+ MAX_NUM.store(20, std::sync::atomic::Ordering::Relaxed);
+}
+
+fn main() {
+ assert_eq!(MAX_NUM.load(std::sync::atomic::Ordering::Relaxed), 20);
+}
Because the .init_array
section is a default section to store initialization functions in Linux and some other systems, it will be included in the linker script of compilers like GCC and Clang.
However, if you are using a custom linker script, you need to add the .init_array
section and map them in the page table manually, so that these functions can be executed correctly. You can add the following line to your linker script as a reference:
.init_array : ALIGN(4K) {
+ PROVIDE_HIDDEN (__init_array_start = .);
+ *(.init_array .init_array.*)
+ PROVIDE_HIDDEN (__init_array_end = .);
+ . = ALIGN(4K);
+}
To avoid section-related symbols being optimized by the compiler, you need to add “-z nostart-stop-gc” to the compile flags (see https://lld.llvm.org/ELF/start-stop-gc).
+For example, in .cargo/config.toml
:
[build]
+rustflags = ["-C", "link-arg=-z", "link-arg=nostart-stop-gc"]
+rustdocflags = ["-C", "link-arg=-z", "-C", "link-arg=nostart-stop-gc"]
register_ctor
attribute.main
.DO NOT use this crate directly. Use the ctor_bare crate instead.
+After attching the register_ctor
macro to the given function, a pointer pointing to it will be stored in the .init_array
section.
+When the program is loaded, this section will be linked into the binary. The call_ctors
function in the ctor_bare
+crate will call all the constructor functions in the .init_array
section.
See the documentation of the ctor_bare crate for more details.
+main
.main
.")
\ No newline at end of file
diff --git a/search.desc/ctor_bare_macros/ctor_bare_macros-desc-0-.js b/search.desc/ctor_bare_macros/ctor_bare_macros-desc-0-.js
new file mode 100644
index 0000000..c8f9158
--- /dev/null
+++ b/search.desc/ctor_bare_macros/ctor_bare_macros-desc-0-.js
@@ -0,0 +1 @@
+searchState.loadedDescShard("ctor_bare_macros", 0, "DO NOT use this crate directly. Use the ctor_bare crate …\nRegister a constructor function to be called before main
.")
\ No newline at end of file
diff --git a/settings.html b/settings.html
new file mode 100644
index 0000000..8b8a22f
--- /dev/null
+++ b/settings.html
@@ -0,0 +1 @@
++1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31
#![no_std]
+#![doc = include_str!("../README.md")]
+
+pub use ctor_bare_macros::register_ctor;
+
+/// Placeholder for the `.init_array` section, so that
+/// the `__init_array_start` and `__init_array_end` symbols can be generated.
+#[link_section = ".init_array"]
+#[used]
+static _SECTION_PLACE_HOLDER: [u8; 0] = [];
+
+extern "C" {
+ fn __init_array_start();
+ fn __init_array_end();
+}
+
+/// Invoke all constructor functions registered by the `register_ctor` attribute.
+///
+/// # Notes
+/// Caller should ensure that the `.init_array` section will not be disturbed by other sections.
+pub fn call_ctors() {
+ for ctor_ptr in (__init_array_start as usize..__init_array_end as usize)
+ .step_by(core::mem::size_of::<*const core::ffi::c_void>())
+ {
+ unsafe {
+ core::mem::transmute::<*const core::ffi::c_void, fn()>(
+ *(ctor_ptr as *const *const core::ffi::c_void),
+ )();
+ }
+ }
+}
+
+1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77
//!Macros for registering constructor functions for Rust under no_std, which is like __attribute__((constructor)) in C/C++.
+//!
+//! **DO NOT** use this crate directly. Use the [ctor_bare](https://docs.rs/ctor_bare) crate instead.
+//!
+//! After attching the `register_ctor` macro to the given function, a pointer pointing to it will be stored in the `.init_array` section.
+//! When the program is loaded, this section will be linked into the binary. The `call_ctors` function in the `ctor_bare`
+//! crate will call all the constructor functions in the `.init_array` section.
+//!
+//! See the documentation of the [ctor_bare](https://docs.rs/ctor_bare) crate for more details.
+
+use proc_macro::TokenStream;
+use proc_macro2::Span;
+use quote::{format_ident, quote};
+use syn::{parse_macro_input, Error, Item};
+
+/// Register a constructor function to be called before `main`.
+///
+/// The function should have no input arguments and return nothing.
+///
+/// See the documentation of the [ctor_bare](https://docs.rs/ctor_bare) crate for more details.
+#[proc_macro_attribute]
+pub fn register_ctor(attr: TokenStream, function: TokenStream) -> TokenStream {
+ if !attr.is_empty() {
+ return Error::new(
+ Span::call_site(),
+ "expect an empty attribute: `#[register_ctor]`",
+ )
+ .to_compile_error()
+ .into();
+ }
+
+ let item: Item = parse_macro_input!(function as Item);
+ if let Item::Fn(func) = item {
+ let name = &func.sig.ident;
+ let name_str = name.to_string();
+ let name_ident = format_ident!("_INIT_{}", name_str);
+ let output = &func.sig.output;
+ // Constructor functions should not have any return value.
+ if let syn::ReturnType::Type(_, _) = output {
+ return Error::new(
+ Span::call_site(),
+ "expect no return value for the constructor function",
+ )
+ .to_compile_error()
+ .into();
+ }
+ let inputs = &func.sig.inputs;
+ // Constructor functions should not have any input arguments.
+ if !inputs.is_empty() {
+ return Error::new(
+ Span::call_site(),
+ "expect no input arguments for the constructor function",
+ )
+ .to_compile_error()
+ .into();
+ }
+ let block = &func.block;
+
+ quote! {
+ #[link_section = ".init_array"]
+ #[used]
+ #[allow(non_upper_case_globals)]
+ static #name_ident: extern "C" fn() = #name;
+
+ #[no_mangle]
+ #[allow(non_upper_case_globals)]
+ pub extern "C" fn #name() {
+ #block
+ }
+ }
+ .into()
+ } else {
+ Error::new(Span::call_site(), "expect a function to be registered")
+ .to_compile_error()
+ .into()
+ }
+}
+
fn:
) to \
+ restrict the search to a given item kind.","Accepted kinds are: fn
, mod
, struct
, \
+ enum
, trait
, type
, macro
, \
+ and const
.","Search functions by type signature (e.g., vec -> usize
or \
+ -> vec
or String, enum:Cow -> bool
)","You can look for items with an exact name by putting double quotes around \
+ your request: \"string\"
","Look for functions that accept or return \
+ slices and \
+ arrays by writing \
+ square brackets (e.g., -> [u8]
or [] -> Option
)","Look for items inside another one by searching for a path: vec::Vec
",].map(x=>""+x+"
").join("");const div_infos=document.createElement("div");addClass(div_infos,"infos");div_infos.innerHTML="${value.replaceAll(" ", " ")}
`}else{error[index]=value}});output+=`