Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Provide an example of querying Intel CPU capabilities using Rust's inline assembly

I am trying to use inline assembly in Rust. The code I'm including is supposed to query Intel CPU capabilities and right now I just want to get the ebx register state after the system call.

Using an nightly build of Rust compiler (required to use the asm! macro) the code compiles. When I run the program, I get random values for the ebx register and a segmentation fault. I'm pretty sure my asm! macro syntax is just wrong but the documentation of this feature is very weak. Does anyone have any pointers as to what I could improve?

#![feature(asm)]
fn main() {
    let result: u32;
    unsafe {
        asm!("mov eax, 07H;
              mov ecx, 0;
              cpuid;"
              : "={ebx}"(result)
              :
              : "eax, ebx, ecx, edx"
              : "intel"
        )
    }
    println!("ebx from cpuid is {}", result);
}
like image 807
Barry Avatar asked Aug 15 '18 00:08

Barry


1 Answers

You can just copy my old implementation of cpuid if you feel a burning need to ignore my following advice:

fn cpuid(code: RequestType) -> (u32, u32, u32, u32) {
    let res1;
    let res2;
    let res3;
    let res4;

    unsafe {
        asm!("cpuid"
             : // output operands
             "={eax}"(res1),
             "={ebx}"(res2),
             "={ecx}"(res3),
             "={edx}"(res4)
             : // input operands
             "{eax}"(code as u32),
             "{ecx}"(0 as u32)
             : // clobbers
             : // options
             );
    }

    (res1, res2, res3, res4)
}

There's no need to mark anything as clobbered because all of the affected registers are marked as outputs. All of the input values are provided as well.


That being said, don't write this code.

  1. It's already written. Multiple times:

    • The standard library contains intrinsics for all the important CPU features. In this case, use core::arch::x86::__cpuid / core::arch::x86_64::__cpuid. These are also available in std but not documented for some reason.

    • Crates like my own: cupid

  2. Writing inline assembly requires a nightly compiler and will probably never be stabilized. It's really only useful for extremely niche cases, such as bootstrapping an OS or embedded system, dumping the state of all registers, and other very low-level details that the intrinsics don't cover (yet?).

like image 171
Shepmaster Avatar answered Oct 17 '22 08:10

Shepmaster