Skip to content

Commit

Permalink
[DO NOT MERGE] use asm syscall
Browse files Browse the repository at this point in the history
  • Loading branch information
taiki-e committed Jun 26, 2023
1 parent 1518f14 commit ac8ddbf
Showing 1 changed file with 167 additions and 35 deletions.
202 changes: 167 additions & 35 deletions src/imp/atomic128/detect/auxv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,28 +121,132 @@ mod os {
#[allow(non_camel_case_types)]
pub(super) mod ffi {
pub(crate) use super::super::c_types::{c_int, c_long, c_size_t, c_uint, c_ulong, c_void};
use core::arch::asm;

// https://github.com/rust-lang/libc/blob/0.2.139/src/unix/mod.rs#LL25
pub(crate) type pid_t = i32;
// https://github.com/freebsd/freebsd-src/blob/67633329693723734aef003044e13db07f1fbf5f/sys/sys/syscall.h
pub(crate) const SYS_getpid: usize = 20;
pub(crate) const SYS_sysctl: usize = 202;

extern "C" {
// Defined in sys/sysctl.h.
// https://man.freebsd.org/sysctl(3)
// https://github.com/freebsd/freebsd-src/blob/4aeb939ecf8b2b6913ae51d828416743bad812ab/sys/sys/sysctl.h
// https://github.com/rust-lang/libc/blob/0.2.139/src/unix/bsd/freebsdlike/mod.rs#L1670-L1677
pub(crate) fn sysctl(
name: *const c_int,
name_len: c_uint,
old_p: *mut c_void,
old_len_p: *mut c_size_t,
new_p: *const c_void,
new_len: c_size_t,
) -> c_int;

// Defined in unistd.h.
// https://man.freebsd.org/getpid(2)
// https://github.com/freebsd/freebsd-src/blob/deb63adf945d446ed91a9d84124c71f15ae571d1/include/unistd.h
pub(crate) fn getpid() -> pid_t;
// https://github.com/freebsd/freebsd-src/blob/main/lib/libc/aarch64/SYS.h
// https://github.com/golang/go/blob/4badad8d477ffd7a6b762c35bc69aed82faface7/src/syscall/asm_freebsd_arm64.s
#[cfg(target_arch = "aarch64")]
#[inline]
pub(crate) fn getpid() -> pid_t {
#[allow(clippy::cast_possible_truncation)]
// SAFETY: calling getpid is safe.
unsafe {
let n = SYS_getpid;
let r: isize;
asm!(
"svc 0",
in("x8") n,
out("x0") r,
options(nostack, readonly),
);
r as pid_t
}
}
#[cfg(target_arch = "aarch64")]
#[inline]
pub(crate) unsafe fn sysctl(
name: *const c_int,
name_len: c_uint,
old_p: *mut c_void,
old_len_p: *mut c_size_t,
new_p: *const c_void,
new_len: c_size_t,
) -> c_int {
#[allow(clippy::cast_possible_truncation)]
// SAFETY: the caller must uphold the safety contract.
unsafe {
let n = SYS_sysctl;
let r: isize;
asm!(
"svc 0",
"b.cc 2f",
// "mov {err}, x0",
"mov x0, #-1",
"2:",
in("x8") n,
inout("x0") name => r,
inout("x1") name_len as usize => _,
in("x2") old_p,
in("x3") old_len_p,
in("x4") new_p,
in("x5") new_len,
options(nostack),
);
r as c_int
}
}

// https://github.com/freebsd/freebsd-src/blob/main/lib/libc/powerpc64/SYS.h
#[cfg(target_arch = "powerpc64")]
#[inline]
pub(crate) fn getpid() -> pid_t {
#[allow(clippy::cast_possible_truncation)]
// SAFETY: calling getpid is safe.
unsafe {
let n = SYS_getpid;
let r: isize;
asm!(
"sc",
inout("r0") n => _,
out("r3") r,
out("r4") _,
out("r5") _,
out("r6") _,
out("r7") _,
out("r8") _,
out("r9") _,
out("r10") _,
out("r11") _,
out("r12") _,
out("cr0") _,
options(nostack, readonly),
);
r as pid_t
}
}
#[cfg(target_arch = "powerpc64")]
#[inline]
pub(crate) unsafe fn sysctl(
name: *const c_int,
name_len: c_uint,
old_p: *mut c_void,
old_len_p: *mut c_size_t,
new_p: *const c_void,
new_len: c_size_t,
) -> c_int {
#[allow(clippy::cast_possible_truncation)]
// SAFETY: the caller must uphold the safety contract.
unsafe {
let n = SYS_sysctl;
let r: isize;
asm!(
"sc",
"bns 2f",
// "mr {err}, %r3",
"li %r3, -1",
"2:",
inout("r0") n => _,
inout("r3") name => r,
inout("r4") name_len as usize => _,
inout("r5") old_p => _,
inout("r6") old_len_p => _,
inout("r7") new_p => _,
inout("r8") new_len => _,
out("r9") _,
out("r10") _,
out("r11") _,
out("r12") _,
out("cr0") _,
options(nostack),
);
r as c_int
}
}

// Defined in sys/sysctl.h.
Expand Down Expand Up @@ -194,8 +298,7 @@ mod os {

let mut len: ffi::c_size_t = core::mem::size_of_val(&auxv) as ffi::c_size_t;

// SAFETY: calling getpid is safe.
let pid = unsafe { ffi::getpid() };
let pid = ffi::getpid();
let mib = [ffi::CTL_KERN, ffi::KERN_PROC, ffi::KERN_PROC_AUXV, pid];

#[allow(clippy::cast_possible_truncation)]
Expand Down Expand Up @@ -322,7 +425,7 @@ mod tests {
#[test]
fn test_freebsd() {
use test_helper::sys;
fn getauxval_elf_aux_info(aux: ffi::c_int) -> ffi::c_ulong {
fn getauxval_libc_elf_aux_info(aux: ffi::c_int) -> ffi::c_ulong {
#[allow(clippy::cast_possible_wrap, clippy::cast_possible_truncation)]
const OUT_LEN: ffi::c_int = core::mem::size_of::<ffi::c_ulong>() as ffi::c_int;
let mut out: ffi::c_ulong = 0;
Expand All @@ -341,7 +444,49 @@ mod tests {
}
out
}
assert_eq!(os::getauxval(ffi::AT_HWCAP), getauxval_elf_aux_info(ffi::AT_HWCAP));
fn getauxval_libc_sysctl(key: ffi::c_int) -> ffi::c_ulong {
use core::{mem, ptr};

let mut auxv =
[ffi::Elf_Auxinfo { a_type: 0, a_un: ffi::unnamed { a_val: 0 } }; ffi::AT_COUNT];

let mut len = mem::size_of_val(&auxv) as ffi::c_size_t;

// SAFETY: calling getpid is safe.
let pid = unsafe { sys::getpid() };
let mib = [ffi::CTL_KERN, ffi::KERN_PROC, ffi::KERN_PROC_AUXV, pid];

#[allow(clippy::cast_possible_truncation)]
// SAFETY:
// - `mib.len()` does not exceed the size of `mib`.
// - `out_len` does not exceed the size of `out`.
// - `sysctl` is thread-safe.
let res = unsafe {
sys::sysctl(
mib.as_ptr(),
mib.len() as ffi::c_uint,
auxv.as_mut_ptr().cast::<ffi::c_void>(),
&mut len,
ptr::null_mut(),
0,
)
};

if res != -1 {
for aux in &auxv {
if aux.a_type == key as ffi::c_long {
// SAFETY: aux.a_un is #[repr(C)] union and all fields have
// the same size and can be safely transmuted to integers.
return unsafe { aux.a_un.a_val as ffi::c_ulong };
}
}
}
0
}
assert_eq!(os::getauxval(ffi::AT_HWCAP), getauxval_libc_elf_aux_info(ffi::AT_HWCAP));
assert_eq!(os::getauxval(ffi::AT_HWCAP2), getauxval_libc_elf_aux_info(ffi::AT_HWCAP2));
assert_eq!(os::getauxval(ffi::AT_HWCAP), getauxval_libc_sysctl(ffi::AT_HWCAP));
assert_eq!(os::getauxval(ffi::AT_HWCAP2), getauxval_libc_sysctl(ffi::AT_HWCAP2));
}

// Static assertions for FFI bindings.
Expand Down Expand Up @@ -384,19 +529,6 @@ mod tests {
#[cfg(target_os = "freebsd")]
{
let _: ffi::pid_t = 0 as libc::pid_t;
let mut _sysctl: unsafe extern "C" fn(
*const ffi::c_int,
ffi::c_uint,
*mut ffi::c_void,
*mut ffi::c_size_t,
*const ffi::c_void,
ffi::c_size_t,
) -> ffi::c_int = ffi::sysctl;
_sysctl = libc::sysctl;
_sysctl = sys::sysctl;
let mut _getpid: unsafe extern "C" fn() -> ffi::pid_t = ffi::getpid;
_getpid = libc::getpid;
_getpid = sys::getpid;
static_assert!(ffi::CTL_KERN == libc::CTL_KERN);
static_assert!(ffi::CTL_KERN == sys::CTL_KERN as _);
static_assert!(ffi::KERN_PROC == libc::KERN_PROC);
Expand Down

0 comments on commit ac8ddbf

Please sign in to comment.