[!warning] This is an experiment and I can personally guarantee it is unsafe. I describe below some of the unobvious (to me) issues I ended up facing. I'm keen to hear of any possible workarounds for these issues, just open a PR.
This code is based on the following previous work:
Some github and rust-lang issues from the journey, thank you friends!:
no_std for i686-pc-windows-gnu ignores panic=abort-lkernel32 and others when compiling #![no_std] for i686-pc-windows-gnui686-w64-mingw32-gcc and relative data addressing (PIC)The following targets are supported.
| Target | Payload Size |
|---|---|
i686-linux |
4141B |
x86_64-linux |
4167B |
i686-windows |
4141B |
x86_64-windows |
4120B |
[!NOTE] Last tested with
rustc 1.97.0-nightly (20de910db 2026-05-02)andcargo 1.97.0-nightly (4f9b52075 2026-05-01)
The following dependencies must be installed:
cargo install --force cargo-make
# Cross-compiler for windows
sudo apt-get install mingw-w64
# Cross-compiler for i686 linux
sudo apt-get install gcc-multilib
# Linux rustup targets
rustup target add i686-unknown-linux-gnu
rustup target add x86_64-unknown-linux-gnu
# Windows rustup targets
rustup target add i686-pc-windows-gnu
rustup target add x86_64-pc-windows-gn
Or you can build in the provided docker environment:
docker run --rm -it -v .:/build stardust-rs bash
To build one of these targets use cargo make -p $target build
Following is the current output of cargo make -p x86_64-linux run:
*** [LOADER] ***
[*] Allocate RW Memory
[*] Copy Shellcode Into RW Memory
[*] Set Memory RX
[*] Allocation Start Address: 0x700000000000
[*] Allocation End Address: 0x700000001047
[*] Allocation Size: 4167B
*** [STARDUST x86_64] ***
[*] Hello Stardust!
[*] Stardust Start Address: 0x700000000000
[*] Stardust Length: 4167
[*] Stardust Instance: 0x7f785645f000
[*] Hitting Breakpoint!
format! macro e.g. &'static &strUsing the alloc::fmt::format! macro will result in a segementation fault due to absolute addresses to reference the pieces in Arguments { pieces, fmt: None, args }.
This results in the if !piece.is_empty() check failing within the following code
@ https://github.com/rust-lang/rust/blob/master/library/core/src/fmt/mod.rs:
/* core::fmt::write () at core/src/fmt/mod.rs:1179 */
/* 1172 */ match args.fmt {
/* 1173 */ None => {
/* 1174 */ // We can use default formatting parameters for all arguments.
/* 1175 */ for (i, arg) in args.args.iter().enumerate() {
/* 1176 */ // SAFETY: args.args and args.pieces come from the same Arguments,
/* 1177 */ // which guarantees the indexes are always within bounds.
/* 1178 */ let piece = unsafe { args.pieces.get_unchecked(i) };
/* 1179 */ if !piece.is_empty() { // This is the check currently failing
/* 1180 */ formatter.buf.write_str(*piece)?;
/* 1181 */ }
/* 1182 */
/* 1183 */ // SAFETY: There are no formatting parameters and hence no
/* 1184 */ // count arguments.
/* 1185 */ unsafe {
/* 1186 */ arg.fmt(&mut formatter)?;
/* 1187 */ }
/* 1188 */ idx += 1;
/* 1189 */ }
/* 1190 */ }
This leads to a call being made to _gcc_except_table which has been removed by linux.ld resulting in a segmentation fault.
[!note] Patching the GOT appeared to get us a little further along before it crashes. YAY!🥳
Solution: None
A bunch of stuff uses the GOT including calls to functions with the compiler_builtins crate, e.g. the following functions:
memcpymemmovememsetmemcmpbcmpThis resulted in a segmentation fault due to a call made to a bad/absolute hard-coded memory address stored within the GOT and then referenced by a RIP-relative offset.
Similarly using extern "C" functions directly may result in the use the GOT.
The following code was used to ensure memcpy was required by the binary:
let src = alloc::string::String::from("SSECCUS\t\t:ypcmem gnitseT");
let dst: String = src.chars().rev().collect();
info!(&dst);
Patching the hardcoded addresses with GDB results in a successful execution as seen below:

Solution:
compiler_builtins!extern functions before patching, call them within asm! macro-fPICYou're best off reading this (or maybe you're not, won't get that time back) i686-w64-mingw32-gcc and relative data addressing (PIC).
Solution:
stdcall where required.The short summary is that, in Rust, the compiler emits GOT references implicitly for static data and compiler_builtins — you cannot opt out without either going fully GOT-free (no statics, no compiler_builtins functions). In this case fighting the compiler's codegen is harder than patching the GOT at runtime.
$ claude mcp add stardust-rs \
-- python -m otcore.mcp_server <graph>