8

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);
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Barry
  • 237
  • 1
  • 2
  • 11
  • 6
    I don't know rust but: I suggest you first try a `nop` then maybe something like `mov ebx, 42` to see if the problem is the `cpuid` (it shouldn't be). Also verify you are supposed to list the clobbers in a single string and not as `"eax", "ebx", "ecx", "edx"`. Also use a debugger if possible to see what causes the fault directly. – Jester Aug 15 '18 at 00:56
  • Thank you Jester. Your clobbers comment was genius. Made it like your syntax and it is now working. – Barry Aug 15 '18 at 01:07
  • 1
    Are you sure it makes sense to declare a clobber on EBX when it's also an output operand? GNU C inline asm would complain about that. Also, for CPUID specifically, isn't there a built-in for it? – Peter Cordes Aug 15 '18 at 01:39
  • 2
    See also [How do I translate x86 GCC-style C inline assembly to Rust inline assembly?](https://stackoverflow.com/q/48098907/155423); [Rust inline assembly template syntax](https://stackoverflow.com/q/34477497/155423); [Inline assembly confusion when using parameters](https://stackoverflow.com/q/27587201/155423). – Shepmaster Aug 15 '18 at 02:36
  • @Jester: Since your comment solved the issue, you may wish to morph it into an answer. – Matthieu M. Aug 15 '18 at 13:41

1 Answers1

7

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:

  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?).

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • There is no need for people to react strongly and downvote etc. These are the first lines of Rust I've ever written. Just to easily play with the Intel api for education purposes. I'm just trying to have fun. – Barry Aug 15 '18 at 05:32
  • 1
    I'd agree with @Barry here. The title is not about cpuid, it's about inline assembly, and cpuid just happened to be used as an example. Of course, this might just mean that the question is a duplicate. – Matthieu M. Aug 15 '18 at 09:02
  • @MatthieuM. I actually think that the original title is far too broad. We'd dislike the question "Rust with function example" / "Rust with variable example" / "Rust with trait example" or any formulation of "write examples of for me". Additionally, OP wouldn't want just *any* inline assembly example — something that just calls NOP would provide an example but probably not what they want. I've made the title more specifically reflect their question body. – Shepmaster Aug 15 '18 at 12:20
  • 4
    @Shepmaster: Sure, the issue I see however in your answer is that the OP is less inquiring about how to use cpuid, and more about how to use inline assembly; cpuid is just an excuse to learn inline assembly. Or otherwise said, they're asking how to fish, not asking for a fish, and your answer start with "don't fish yourself, here are fishes", which is not helpful. Instead, the answer should address the issues with the OP's assembly (output/clobbers if I understand correctly), and maybe at the end mention that for cpuid there exists intrinsics/crates. – Matthieu M. Aug 15 '18 at 13:11