Convert llvm_asm to asm

Summary:
The `llvm_asm` nightly feature was removed in Rust 1.59 and `asm!()` was simultaneously stabilized, so we need to make the switch so things continue compiling.

This retains the `llvm_asm` code so that it can continue compiling on old llvm versions. This will be removed when that is updated.

Reviewed By: johnhurt

Differential Revision: D34561246

fbshipit-source-id: 42cd2c7e83cea9a5c21bd5871463bb1a42be139d
This commit is contained in:
Jason White 2022-03-10 12:05:42 -08:00 committed by Facebook GitHub Bot
parent 75e875fe28
commit 193965dfe5
6 changed files with 143 additions and 15 deletions

View file

@ -36,7 +36,7 @@
#![feature(async_closure)]
#![feature(internal_output_capture)]
#![feature(never_type)]
#![feature(llvm_asm)]
#![cfg_attr(feature = "llvm_asm", feature(llvm_asm))]
#![feature(map_first_last)]
#![feature(bench_black_box)]

View file

@ -569,10 +569,30 @@ macro_rules! ret_without_perf {
/// Perform exactly `count+1` conditional branch instructions. Useful for
/// testing timer-related code.
#[cfg(target_arch = "x86_64")]
#[cfg(not(feature = "llvm_asm"))]
#[inline(never)]
pub fn do_branches(mut count: u64) {
// Anything but assembly is unreliable between debug and release
unsafe {
// Loop until carry flag is set, indicating underflow
core::arch::asm!(
"2:",
"sub {0}, 1",
"jnc 2b",
inout(reg) count,
)
}
assert_eq!(count, u64::MAX);
}
/// Perform exactly `count+1` conditional branch instructions. Useful for
/// testing timer-related code.
#[cfg(target_arch = "x86_64")]
#[cfg(feature = "llvm_asm")]
#[inline(never)]
pub fn do_branches(count: u64) {
// Anything but assembly is unreliable between debug and release
// TODO: Switch to `asm!()` when our LLVM version supports it.
#[allow(deprecated)]
unsafe {
// Loop until carry flag is set, indicating underflow

View file

@ -13,7 +13,6 @@ use core::mem;
use perf_event_open_sys::bindings as perf;
use raw_cpuid::{CpuId, FeatureInfo};
use reverie::Errno;
use std::hint::black_box;
use thiserror::Error;
use tracing::{error, warn};
@ -68,6 +67,7 @@ pub(crate) enum PmuValidationError {
#[error("Intel Kvm-In-Txcp bug found")]
IntelKvmInTxcpBugDetected,
#[cfg(feature = "llvm_asm")]
#[error("Overcount triggered by PMU interrupts detected due to Xen PMU virtualization bug")]
IntelXenPmiBugDetected,
}
@ -361,7 +361,7 @@ fn is_amd_zen(cpu_feature: FeatureInfo) -> bool {
/// This is a transcription of the function with the same name in Mozilla-RR it will
/// check for bugs specific to cpu architectures
fn check_for_arch_bugs(precise_ip: bool) -> Result<(), PmuValidationError> {
fn check_for_arch_bugs(_precise_ip: bool) -> Result<(), PmuValidationError> {
let c = CpuId::new();
let vendor = c.get_vendor_info().unwrap();
let feature_info = c
@ -371,7 +371,12 @@ fn check_for_arch_bugs(precise_ip: bool) -> Result<(), PmuValidationError> {
match vendor_str {
AMD_VENDOR if is_amd_zen(feature_info) => check_for_zen_speclockmap(),
INTEL_VENDOR => check_for_kvm_in_txcp_bug().and(check_for_xen_pmi_bug(precise_ip)),
INTEL_VENDOR => {
check_for_kvm_in_txcp_bug()?;
#[cfg(feature = "llvm_asm")]
check_for_xen_pmi_bug(_precise_ip)?;
Ok(())
}
s => panic!("Unknown CPU vendor: {}", s),
}
}
@ -395,6 +400,18 @@ fn check_for_zen_speclockmap() -> Result<(), PmuValidationError> {
let count = read_counter(&fd)?;
// A lock add is known to increase the perf counter we're looking at.
#[cfg(not(feature = "llvm_asm"))]
unsafe {
let _prev: usize;
core::arch::asm!(
"lock",
"xadd [{}], {}",
in(reg) val,
inout(reg) to_add => _prev,
)
}
#[cfg(feature = "llvm_asm")]
#[allow(deprecated)]
unsafe {
let _prev: usize;
@ -437,6 +454,8 @@ fn check_for_kvm_in_txcp_bug() -> Result<(), PmuValidationError> {
}
}
// FIXME: Convert this big block of llvm_asm over to the new asm syntax.
#[cfg(feature = "llvm_asm")]
fn check_for_xen_pmi_bug(precise_ip: bool) -> Result<(), PmuValidationError> {
#[allow(unused_assignments)]
let mut count: i32 = -1;
@ -451,7 +470,7 @@ fn check_for_xen_pmi_bug(precise_ip: bool) -> Result<(), PmuValidationError> {
20764791
}
let mut accumulator = black_box(make_accumulator_seed());
let mut accumulator = core::hint::black_box(make_accumulator_seed());
let mut expected_accumulator = accumulator;
// reproduce the assembly here to calculate what the final accumulator value should be

View file

@ -6,7 +6,7 @@
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
#![feature(llvm_asm)]
#![cfg_attr(feature = "llvm_asm", feature(llvm_asm))]
//! Basic tests that don't fall into some other category.
@ -221,12 +221,27 @@ fn i_should_segfault() {
fn i_should_segfault_2() {
use nix::sys::signal::Signal::SIGSEGV;
use reverie_ptrace::testing::test_fn;
let (output, _) = test_fn::<NoopTool, _>(|| unsafe {
#[inline]
#[cfg(not(feature = "llvm_asm"))]
unsafe fn do_segfault() {
let null_ptr: *const usize = core::ptr::null();
asm!(
"jmp {0}",
in(reg) null_ptr,
)
}
#[inline]
#[cfg(feature = "llvm_asm")]
#[allow(deprecated)]
unsafe fn do_segfault() {
llvm_asm!(r#"mov $$0, %rax
jmpq *%rax
"#:::"rax")
})
.unwrap();
}
let (output, _) = test_fn::<NoopTool, _>(|| unsafe { do_segfault() }).unwrap();
assert_eq!(output.status, ExitStatus::Signaled(SIGSEGV, true),);
}

View file

@ -6,7 +6,7 @@
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
#![feature(llvm_asm)]
#![cfg_attr(feature = "llvm_asm", feature(llvm_asm))]
// when we convert syscall, such as open -> openat, the old syscall
// args should not be clobbered, even with the conversion.
@ -61,7 +61,64 @@ mod tests {
use reverie_ptrace::testing::check_fn;
#[cfg(target_arch = "x86_64")]
#[cfg(not(feature = "llvm_asm"))]
#[allow(unused_mut)]
unsafe fn open_syscall_sanity_check() -> i32 {
let path = b"/dev/null\0".as_ptr() as usize;
let flags: usize = 0x8000; // O_LARGEFILE
let mode: usize = 0o644;
let mut ret: usize;
// // The following asm block does this:
// let ret = open("/dev/null", 0x8000, 0644);
// if ret >= -4095 as u64 { exit_group(1) }
// // Sanity check input registers to ensure they didn't change.
// if %rsi != 0x8000 { exit_group(1) }
// if %rdx != 0644 { exit_roup(1) }
// return fd
core::arch::asm!(
"mov r8, {arg1}",
"syscall",
// if (ret >= -4095 as u64) goto 1
"cmp 0xfffffffffffff001"
"jae 2f",
// if (rax != r8) goto label1;
"cmp rdi, r8",
"jne 2f",
// if (rsi != 0x8000) goto label1;
"cmp rsi, 0x8000",
"jne 2f",
// if (rdx != 0644) goto label1;
"cmp rdx, 0x1a4",
"jne 2f",
// Otherwise, we're successful.
"jmp 3f",
"2:",
// Set syscall arg1 to label1
"mov rdi, 0x1",
// Set syscall to exit_group
"mov rax, {sys_exit_group}",
// Do the syscall
"syscall",
"3:",
lateout("rax") ret,
in("rax") n,
arg1 = inlateout("rdi") path, // Reused for the exit_group syscall.
in("rsi") flags,
in("rdx") mode,
out("r8") _, // Clobbered
out("rcx") _, // rcx is used to store old rip
out("r11") _, // r11 is used to store old rflags
);
ret
}
#[cfg(target_arch = "x86_64")]
#[cfg(feature = "llvm_asm")]
#[allow(unused_mut)]
#[allow(deprecated)]
unsafe fn open_syscall_sanity_check() -> i32 {
let mut ret;
let path = b"/dev/null\0";

View file

@ -12,8 +12,7 @@
//! Syscalls are abused to communicate from the guest to the tool instructions
//! necessary to carry out the test, such as setting timers or reading clocks.
#![feature(llvm_asm)]
#![cfg_attr(feature = "llvm_asm", feature(llvm_asm))]
use core::arch::x86_64::{__cpuid, __rdtscp, _rdtsc};
use libc;
use reverie::{
@ -189,7 +188,25 @@ async fn raise_sigwinch<T: Guest<LocalState>>(guest: &mut T) -> Tgkill {
.with_sig(libc::SIGWINCH)
}
// FIXME: Use the syscalls crate for doing this when it switches to using the
// `asm!()` macro instead of asm inside of a C file.
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
#[cfg(not(feature = "llvm_asm"))]
unsafe fn syscall_no_branches(no: libc::c_long, arg1: libc::c_long) {
let mut ret: u64;
core::arch::asm!(
"syscall",
lateout("rax") ret,
in("rax") no,
in("rdi") arg1,
out("rcx") _, // rcx is used to store old rip
out("r11") _, // r11 is used to store old rflags
);
}
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
#[cfg(feature = "llvm_asm")]
#[allow(deprecated)]
unsafe fn syscall_no_branches(no: libc::c_long, arg1: libc::c_long) {
llvm_asm!("
mov $0, %rax