#[inline(always)]
pub(crate) fn current_fp() -> u64 {
#[cfg(target_arch = "x86_64")]
unsafe {
let fp: u64;
core::arch::asm!(
"mov {fp}, rbp",
fp = out(reg) fp,
options(nomem, nostack, preserves_flags)
);
fp
}
#[cfg(target_arch = "aarch64")]
unsafe {
let fp: u64;
core::arch::asm!(
"mov {fp}, x29",
fp = out(reg) fp,
options(nomem, nostack, preserves_flags)
);
fp
}
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
{
0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn current_fp_is_nonzero_on_supported_archs() {
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
assert_ne!(current_fp(), 0, "FP register must be live in test fn");
}
#[test]
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
fn current_fp_changes_across_calls() {
#[inline(never)]
fn deeper() -> u64 {
let sentinel: u64 = 0;
let probe = &sentinel as *const u64 as u64;
core::hint::black_box(probe);
current_fp()
}
let a = current_fp();
let b = deeper();
if a == b {
assert_ne!(a, 0);
assert_ne!(b, 0);
} else {
assert_ne!(a, b);
}
}
}