# mutself Create self-mutating executables. ## Purpose // TODO ## Usage ```rust mutself::mutself! { DATA = "alice" } fn main() { if let Some(arg) = std::env::args().nth(1) { println!("Hello {}", &arg); mutself("new.exe", Some(&arg)).unwrap(); } else { println!("Hello {}", &*DATA); } } ``` Running our executable gives : ```shell $ cargo run Hello alice ``` Now with an argument : ```shell $ cargo run -- bob Hello bob # This creates another executable named 'new.exe' $ new Hello bob ``` Yes, data size can be changed. ```shell $ cargo run -- someverylongstringthatwouldntfitinsidethespace ``` ## How ? The library parses the executable it's running in and changes values before dumping a new executable. ### In depth Simply put : an abuse of the `#[link_section = ".custom"]` attribute. There is no assembly patching or anything. The data entries in the `mutself!` macro are stored in a custom section in the executable. The code that run only has a pointer to the top of the section (that pointer always stays valid because the custom section will always be at the same place in virtual memory). All entries in the section are referenced relatively to this pointer. The layout in memory is like so (factoring out alignment) : ```text #ENTRY0 size (usize) <-- hardcoded pointer #ENTRY0 #ENTRY1 size (usize) #ENTRY1 // And so on ``` Since every entry is defined relatively to the base, they can grow or shrink in size freely without fear the runtime code can't address them. ## Limitations The initializer expression must be of a type that can be stored inline (e.g. not a slice). A slice will only store a ptr and a size in the custom executable section referencing `.data`, which means we can't modify it.