Skip to content

Commit

Permalink
Add rdfsbase, rdgsbase, wrfsbase, wrgsbase (#172)
Browse files Browse the repository at this point in the history
  • Loading branch information
haraldh authored Aug 13, 2020
1 parent f5c4224 commit 6e961a3
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 0 deletions.
24 changes: 24 additions & 0 deletions src/asm/asm.s
Original file line number Diff line number Diff line change
Expand Up @@ -233,3 +233,27 @@ _x86_64_asm_wrmsr:
_x86_64_asm_hlt:
hlt
retq

.global _x86_64_asm_rdfsbase
.p2align 4
_x86_64_asm_rdfsbase:
rdfsbase %rax
retq

.global _x86_64_asm_wrfsbase
.p2align 4
_x86_64_asm_wrfsbase:
wrfsbase %rdi
retq

.global _x86_64_asm_rdgsbase
.p2align 4
_x86_64_asm_rdgsbase:
rdgsbase %rax
retq

.global _x86_64_asm_wrgsbase
.p2align 4
_x86_64_asm_wrgsbase:
wrgsbase %rdi
retq
24 changes: 24 additions & 0 deletions src/asm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,4 +203,28 @@ extern "C" {
link_name = "_x86_64_asm_write_rflags"
)]
pub(crate) fn x86_64_asm_write_rflags(val: u64);

#[cfg_attr(
any(target_env = "gnu", target_env = "musl"),
link_name = "_x86_64_asm_rdfsbase"
)]
pub(crate) fn x86_64_asm_rdfsbase() -> u64;

#[cfg_attr(
any(target_env = "gnu", target_env = "musl"),
link_name = "_x86_64_asm_wrfsbase"
)]
pub(crate) fn x86_64_asm_wrfsbase(val: u64);

#[cfg_attr(
any(target_env = "gnu", target_env = "musl"),
link_name = "_x86_64_asm_rdgsbase"
)]
pub(crate) fn x86_64_asm_rdgsbase() -> u64;

#[cfg_attr(
any(target_env = "gnu", target_env = "musl"),
link_name = "_x86_64_asm_wrgsbase"
)]
pub(crate) fn x86_64_asm_wrgsbase(val: u64);
}
99 changes: 99 additions & 0 deletions src/registers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,102 @@ pub fn read_rip() -> u64 {
}
rip
}

/// Writes the FS segment base address
///
/// ## Safety
///
/// If `CR4.FSGSBASE` is not set, this instruction will throw an `#UD`.
///
/// The caller must ensure that this write operation has no unsafe side
/// effects, as the FS segment base address is often used for thread
/// local storage.
#[inline]
pub unsafe fn wrfsbase(val: u64) {
#[cfg(feature = "inline_asm")]
#[inline(always)]
unsafe fn inner(val: u64) {
llvm_asm!("wrfsbase $0" :: "r"(val) :: "volatile")
}

#[cfg(not(feature = "inline_asm"))]
#[inline(always)]
unsafe fn inner(val: u64) {
crate::asm::x86_64_asm_wrfsbase(val)
}

inner(val)
}

/// Reads the FS segment base address
///
/// ## Safety
///
/// If `CR4.FSGSBASE` is not set, this instruction will throw an `#UD`.
#[inline]
pub unsafe fn rdfsbase() -> u64 {
#[cfg(feature = "inline_asm")]
#[inline(always)]
unsafe fn inner() -> u64 {
let val: u64;
llvm_asm!("rdfsbase $0" : "=r" (val) ::: "volatile");
val
}

#[cfg(not(feature = "inline_asm"))]
#[inline(always)]
unsafe fn inner() -> u64 {
crate::asm::x86_64_asm_rdfsbase()
}

inner()
}

/// Writes the GS segment base address
///
/// ## Safety
///
/// If `CR4.FSGSBASE` is not set, this instruction will throw an `#UD`.
///
/// The caller must ensure that this write operation has no unsafe side
/// effects, as the GS segment base address might be in use.
#[inline]
pub unsafe fn wrgsbase(val: u64) {
#[cfg(feature = "inline_asm")]
#[inline(always)]
unsafe fn inner(val: u64) {
llvm_asm!("wrgsbase $0" :: "r"(val) :: "volatile")
}

#[cfg(not(feature = "inline_asm"))]
#[inline(always)]
unsafe fn inner(val: u64) {
crate::asm::x86_64_asm_wrgsbase(val)
}

inner(val)
}

/// Reads the GS segment base address
///
/// ## Safety
///
/// If `CR4.FSGSBASE` is not set, this instruction will throw an `#UD`.
#[inline]
pub unsafe fn rdgsbase() -> u64 {
#[cfg(feature = "inline_asm")]
#[inline(always)]
unsafe fn inner() -> u64 {
let val: u64;
llvm_asm!("rdgsbase $0" : "=r" (val) ::: "volatile");
val
}

#[cfg(not(feature = "inline_asm"))]
#[inline(always)]
unsafe fn inner() -> u64 {
crate::asm::x86_64_asm_rdgsbase()
}

inner()
}

0 comments on commit 6e961a3

Please sign in to comment.