feat: copy frameworks to Frameworks folder, detect linkers, custom target dirs (#4174)
* feat: copy frameworks to Frameworks folder * add dylib linking to patching * remove logging * rename __aslr_offset * fix android/linux * support linker flavor * support custom target dirs * custom cargo target dir support * whoops ios * dlsym doesn't exist on windows * look for the right main symbol per platform * distinction between mains * export main on windows * enbable rlib caching * add dx hash * adjust linking warnings * update tui with hotreload state * implement symbol flags * add flags * only run ranlib on darwin * enable lld * paths * add harness test for tls * wip: revert launch mobile * wip * fix fullstack mobile * fix a few bugs - long paths? - reverting back to original * pass-thru fuse-ld args * fix nan in render, fix empty archives * consider existing dep files if archive exists * fmt * drop msrv
This commit is contained in:
1 parent
751f1920c3
commit
0982c1ff8b
25 files changed
+1044
-315
No files matched your search
@@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "cross-tls-crate-dylib"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
# when testing, use a dylib
|
||||
# crate-type = ["dylib"]
|
||||
|
||||
[dependencies]
|
||||
@@ -0,0 +1,25 @@
|
||||
pub use std::cell::Cell;
|
||||
use std::{cell::RefCell, thread::LocalKey};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct StoredItem {
|
||||
pub name: String,
|
||||
pub value: f32,
|
||||
pub items: Vec<String>,
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
pub static BAZ: RefCell<Option<StoredItem>> = const { RefCell::new(None) };
|
||||
}
|
||||
|
||||
pub fn get_baz() -> &'static LocalKey<RefCell<Option<StoredItem>>> {
|
||||
if BAZ.with(|f| f.borrow().is_none()) {
|
||||
BAZ.set(Some(StoredItem {
|
||||
name: "BAR".to_string(),
|
||||
value: 0.0,
|
||||
items: vec!["item1".to_string(), "item2".to_string()],
|
||||
}));
|
||||
}
|
||||
|
||||
&BAZ
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
[package]
|
||||
name = "cross-tls-crate"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
@@ -0,0 +1,25 @@
|
||||
pub use std::cell::Cell;
|
||||
use std::{cell::RefCell, thread::LocalKey};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct StoredItem {
|
||||
pub name: String,
|
||||
pub value: f32,
|
||||
pub items: Vec<String>,
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
pub static BAR: RefCell<Option<StoredItem>> = const { RefCell::new(None) };
|
||||
}
|
||||
|
||||
pub fn get_bar() -> &'static LocalKey<RefCell<Option<StoredItem>>> {
|
||||
if BAR.with(|f| f.borrow().is_none()) {
|
||||
BAR.set(Some(StoredItem {
|
||||
name: "BAR".to_string(),
|
||||
value: 0.0,
|
||||
items: vec!["item1".to_string(), "item2".to_string()],
|
||||
}));
|
||||
}
|
||||
|
||||
&BAR
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "subsecond-tls-harness"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
dioxus-devtools = { workspace = true }
|
||||
cross-tls-crate = { path = "../cross-tls-crate" }
|
||||
cross-tls-crate-dylib = { path = "../cross-tls-crate-dylib" }
|
||||
@@ -0,0 +1,13 @@
|
||||
harness for testing cross-crate TLS imports.
|
||||
|
||||
TLS is the hardest to get right with binary patchinig since we need to rewrite initializers.
|
||||
|
||||
this crate relies on two crates - one as a dylib and the other as an rlib
|
||||
|
||||
the dylib should make it into our bundle and the rlib should just be linked.
|
||||
|
||||
both shouldn't cause access errors or segfaults during hotpatch.
|
||||
|
||||
```sh
|
||||
cargo run --package dioxus-cli -- serve --hotpatch
|
||||
```
|
||||
@@ -0,0 +1,33 @@
|
||||
use std::{cell::Cell, thread, time::Duration};
|
||||
|
||||
use cross_tls_crate::get_bar;
|
||||
use cross_tls_crate_dylib::get_baz;
|
||||
|
||||
fn main() {
|
||||
dioxus_devtools::connect_subsecond();
|
||||
loop {
|
||||
dioxus_devtools::subsecond::call(|| {
|
||||
use cross_tls_crate::BAR;
|
||||
use cross_tls_crate_dylib::BAZ;
|
||||
|
||||
thread_local! {
|
||||
pub static FOO: Cell<f32> = const { Cell::new(2.0) };
|
||||
}
|
||||
|
||||
println!("Hello 123s123123s: {}", FOO.get());
|
||||
get_bar().with(|f| println!("Bar: {:?}", f.borrow()));
|
||||
thread::sleep(Duration::from_secs(1));
|
||||
|
||||
FOO.set(2.0);
|
||||
get_bar().with(|f| f.borrow_mut().as_mut().unwrap().value = 3.0);
|
||||
get_baz().with(|f| f.borrow_mut().as_mut().unwrap().value = 4.0);
|
||||
|
||||
BAR.with_borrow(|f| {
|
||||
println!("Bar: {:?}", f);
|
||||
});
|
||||
BAZ.with_borrow(|f| {
|
||||
println!("Baz: {:?}", f);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -495,10 +495,9 @@ pub unsafe fn apply_patch(mut table: JumpTable) -> Result<(), PatchError> {
|
||||
}
|
||||
}));
|
||||
|
||||
// Use the `__aslr_reference` symbol as a sentinel for the current executable. This is basically a
|
||||
// cross-platform version of `__mh_execute_header` on macOS that sets a reference point for the
|
||||
// jump table.
|
||||
let old_offset = __aslr_reference() - table.aslr_reference as usize;
|
||||
// Use the `main` symbol as a sentinel for the current executable. This is basically a
|
||||
// cross-platform version of `__mh_execute_header` on macOS that we can use to base the executable.
|
||||
let old_offset = aslr_reference() - table.aslr_reference as usize;
|
||||
|
||||
// Use the `main` symbol as a sentinel for the loaded library. Might want to move away
|
||||
// from this at some point, or make it configurable
|
||||
@@ -672,22 +671,49 @@ pub enum PatchError {
|
||||
AndroidMemfd(String),
|
||||
}
|
||||
|
||||
/// This function returns its own address, providing a stable reference point for hot-patch engine
|
||||
/// to hook onto. If you were to write an object file for this function, it would amount to:
|
||||
///
|
||||
/// ```asm
|
||||
/// __aslr_reference:
|
||||
/// mov rax, qword ptr [rip + __aslr_reference@GOTPCREL] // notice the @GOTPCREL relocation
|
||||
/// ret
|
||||
/// ```
|
||||
/// This function returns the address of the main function in the current executable. This is used as
|
||||
/// an anchor to reference the current executable's base address.
|
||||
///
|
||||
/// The point here being that we have a stable address both at runtime and compile time, making it
|
||||
/// possible to calculate the ASLR offset from within the process to correct the jump table.
|
||||
///
|
||||
/// It should only be called from the main executable *first* and not from a shared library since it
|
||||
/// self-initializes.
|
||||
#[doc(hidden)]
|
||||
#[inline(never)]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn __aslr_reference() -> usize {
|
||||
__aslr_reference as *const () as usize
|
||||
pub fn aslr_reference() -> usize {
|
||||
#[cfg(target_family = "wasm")]
|
||||
return 0;
|
||||
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
unsafe {
|
||||
use std::ffi::c_void;
|
||||
|
||||
// The first call to this function should occur in the
|
||||
static mut MAIN_PTR: *mut c_void = std::ptr::null_mut();
|
||||
|
||||
if MAIN_PTR.is_null() {
|
||||
#[cfg(unix)]
|
||||
{
|
||||
MAIN_PTR = libc::dlsym(libc::RTLD_DEFAULT, c"main".as_ptr() as _);
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
{
|
||||
extern "system" {
|
||||
fn GetModuleHandleA(lpModuleName: *const i8) -> *mut std::ffi::c_void;
|
||||
fn GetProcAddress(
|
||||
hModule: *mut std::ffi::c_void,
|
||||
lpProcName: *const i8,
|
||||
) -> *mut std::ffi::c_void;
|
||||
}
|
||||
|
||||
MAIN_PTR =
|
||||
GetProcAddress(GetModuleHandleA(std::ptr::null()), c"main".as_ptr() as _) as _;
|
||||
}
|
||||
}
|
||||
|
||||
MAIN_PTR as usize
|
||||
}
|
||||
}
|
||||
|
||||
/// On Android, we can't dlopen libraries that aren't placed inside /data/data/<package_name>/lib/
|
||||
|
||||
Reference in new issue
Block a user