Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Binary patching rust hot-reloading, sub-second rebuilds, independent server/client hot-reload #3797

Draft
wants to merge 41 commits into
base: main
Choose a base branch
from
Draft
Changes from 1 commit
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
ed53d2f
wip: inline object diffing logic
jkelleyrtp Feb 25, 2025
309e5e6
inline more logic
jkelleyrtp Feb 25, 2025
5e2c247
fix new linker
jkelleyrtp Feb 25, 2025
609f595
wip
jkelleyrtp Feb 26, 2025
dda3167
mostly applied
jkelleyrtp Feb 26, 2025
68becb3
smaller refactor
jkelleyrtp Feb 27, 2025
2d6bb37
dont need app
jkelleyrtp Feb 28, 2025
981bd1a
finish wiring some stuff together
jkelleyrtp Feb 28, 2025
846d999
wip....
jkelleyrtp Mar 1, 2025
72a76c3
fix missing statics with --whole-archive
jkelleyrtp Mar 2, 2025
db3aaaf
wip: wire up jump table
jkelleyrtp Mar 11, 2025
88efabf
drop hot-fn
jkelleyrtp Mar 11, 2025
12ad69c
rt in core
jkelleyrtp Mar 11, 2025
320dee8
mostly finish migration
jkelleyrtp Mar 12, 2025
41eec1b
clean up prototype code a bit
jkelleyrtp Mar 12, 2025
fe61fee
more cleanups
jkelleyrtp Mar 12, 2025
862c6ea
arbitrary callbacks work, switch to websocket
jkelleyrtp Mar 18, 2025
8fa7259
docs, panic, wip unwind system
jkelleyrtp Mar 18, 2025
b08f255
macos, ios, working. windows/linux not tested by theoretically working?
jkelleyrtp Mar 19, 2025
b87c665
more formal target support
jkelleyrtp Mar 19, 2025
35096fb
wip: fairly thick refactor
jkelleyrtp Mar 20, 2025
dcf5446
get back to compiling state
jkelleyrtp Mar 20, 2025
429cb87
... fix compilation whoops
jkelleyrtp Mar 20, 2025
37bceae
switch to using proper patching instead of runtime lookups
jkelleyrtp Mar 21, 2025
1e095a9
bidirectional websocket
jkelleyrtp Mar 21, 2025
79b82cc
i somehow broke it... one sec
jkelleyrtp Mar 21, 2025
4f44029
checkpoint - mac and ios
jkelleyrtp Mar 21, 2025
63ab8f2
hot-patch work on android
jkelleyrtp Mar 22, 2025
6c8c072
wip, get harness compiling on wasm
jkelleyrtp Mar 22, 2025
dc6b110
build wasm
jkelleyrtp Mar 22, 2025
c11d76c
wip: wasm
jkelleyrtp Mar 22, 2025
6eec643
wasm is very very close
jkelleyrtp Mar 23, 2025
5297bbb
goly gee wasm hot patching works
jkelleyrtp Mar 23, 2025
4eccd45
clean up impl a bit
jkelleyrtp Mar 24, 2025
438e782
auto assemble jump table
jkelleyrtp Mar 24, 2025
b22ca5d
add websocket support for web
jkelleyrtp Mar 24, 2025
880ef29
hmmmmmm
jkelleyrtp Mar 25, 2025
d731787
back to stable point
jkelleyrtp Mar 25, 2025
a9ad5f0
aha! wasm works completely
jkelleyrtp Mar 25, 2025
ddbbd4d
dlopen wasm manually
jkelleyrtp Mar 26, 2025
84f98fe
fix stability issues with wasm implementation
jkelleyrtp Mar 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
bidirectional websocket
jkelleyrtp committed Mar 21, 2025
commit 1e095a9f1fb59433d268f66134b0680283607863
35 changes: 22 additions & 13 deletions packages/subsecond/subsecond-cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -77,7 +77,7 @@ async fn hotreload_loop() -> anyhow::Result<()> {
.spawn()?;

// Wait for the websocket to come up
let mut websocket = wait_for_ws(9393).await?;
let mut client = wait_for_ws(9393).await?;

// don't log if the screen has been taken over - important for tui apps
let should_log = rust_log_enabled();
@@ -99,7 +99,7 @@ async fn hotreload_loop() -> anyhow::Result<()> {
}

let started = Instant::now();
let Ok(output_temp) = fast_build(&result).await else {
let Ok(output_temp) = fast_build(&result, client.aslr_reference).await else {
continue;
};

@@ -112,7 +112,8 @@ async fn hotreload_loop() -> anyhow::Result<()> {
)
.unwrap();

websocket
client
.socket
.send(tokio_tungstenite::tungstenite::Message::Binary(
bincode::serialize(&jump_table).unwrap().into(),
))
@@ -175,14 +176,24 @@ impl FsWatcher {
}
}

async fn wait_for_ws(port: u16) -> anyhow::Result<WebSocketStream<tokio::net::TcpStream>> {
struct WsClient {
aslr_reference: u64,
socket: WebSocketStream<tokio::net::TcpStream>,
}

async fn wait_for_ws(port: u16) -> anyhow::Result<WsClient> {
let port = port;
let addr = format!("127.0.0.1:{}", port);
let try_socket = TcpListener::bind(&addr).await;
let listener = try_socket.expect("Failed to bind");
let (conn, _sock) = listener.accept().await?;
let socket = tokio_tungstenite::accept_async(conn).await?;
Ok(socket)
let mut socket = tokio_tungstenite::accept_async(conn).await?;
let msg = socket.next().await.unwrap()?;
let aslr_reference = msg.into_text().unwrap().parse().unwrap();
Ok(WsClient {
aslr_reference,
socket,
})
}

/// Store the linker args in a file for the main process to read.
@@ -263,7 +274,10 @@ fn rust_log_enabled() -> bool {
}
}

async fn fast_build(original: &CargoOutputResult) -> anyhow::Result<Utf8PathBuf> {
async fn fast_build(
original: &CargoOutputResult,
aslr_reference: u64,
) -> anyhow::Result<Utf8PathBuf> {
let fast_build = Command::new(original.direct_rustc[0].clone())
.args(original.direct_rustc[1..].iter())
.arg("-C")
@@ -287,16 +301,11 @@ async fn fast_build(original: &CargoOutputResult) -> anyhow::Result<Utf8PathBuf>
.map(|arg| PathBuf::from(arg))
.collect::<Vec<_>>();

let refernce: u64 = std::fs::read_to_string(subsecond_folder().join("data").join("aslr.txt"))
.unwrap()
.parse()
.unwrap();

let resolved = subsecond_cli_support::resolve::resolve_undefined(
&original.output_location.as_std_path(),
&object_files,
&Triple::host(),
refernce,
aslr_reference,
)
.unwrap();
let syms = subsecond_folder().join("data").join("syms.o");
2 changes: 1 addition & 1 deletion packages/subsecond/subsecond-harness/src/dioxus_demo.rs
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@ pub fn launch() {

fn app() -> Element {
let mut count = use_signal(|| 0);
let value = 12211231;
let value = 12211123;

rsx! {
h2 { "iOS Binary Patching - {count}" }
7 changes: 4 additions & 3 deletions packages/subsecond/subsecond-harness/src/ws_conn.rs
Original file line number Diff line number Diff line change
@@ -7,9 +7,6 @@ pub extern "C" fn aslr_reference() -> u64 {
}

pub fn initialize() {
let aslr_file = std::env::var("ASLR_FILE").unwrap();
std::fs::write(aslr_file, format!("{}", aslr_reference())).unwrap();

if let Some(endpoint) = dioxus::cli_config::devserver_ws_endpoint() {
// dioxus_devtools::connect(endpoint, |msg| match msg {
// dioxus_devtools::DevserverMsg::HotReload(hot_reload_msg) => {
@@ -35,6 +32,10 @@ pub fn initialize() {
Err(_) => panic!("Failed to connect to hotreload endpoint"),
};

websocket
.send(tungstenite::Message::Text(aslr_reference().to_string()))
.unwrap();

while let Ok(msg) = websocket.read() {
if let tungstenite::Message::Binary(bytes) = msg {
if let Ok(msg) = bincode::deserialize::<JumpTable>(bytes.as_ref()) {