@@ -224,36 +224,42 @@ This state is generally referred to as being "clobbered".
224
224
We need to tell the compiler about this since it may need to save and restore this state around the inline assembly block.
225
225
226
226
``` rust
227
- use std :: arch :: asm;
227
+ use core :: arch :: asm;
228
228
229
- let mut ebx : u32 ;
230
- let mut edx : u32 ;
231
- let mut ecx : u32 ;
232
- unsafe {
233
- asm! (
234
- " push rbx" ,
235
- " cpuid" ,
236
- " mov {0:e}, ebx" ,
237
- " pop rbx" ,
238
- // String is stored as ascii in ebx, edx, ecx in order
239
- // Because ebx is reserved, we get a scratch register and move from
240
- // ebx into it in the asm. The asm needs to preserve the value of
241
- // that register though, so it is pushed and popped around the main asm
242
- // (in 64 bit mode for 64 bit processors, 32 bit processors would use ebx)
243
- out (reg ) ebx ,
244
- out (" edx" ) edx ,
245
- out (" ecx" ) ecx ,
246
- // EAX 0 selects CPUID parameter and manufacturer ID
247
- inout (" eax" ) 0 => _ ,
248
- );
249
- }
229
+ fn main () {
230
+ // three entries of four bytes each
231
+ let mut name_buf = [0_u8 ; 12 ];
232
+ // String is stored as ascii in ebx, edx, ecx in order
233
+ // Because ebx is reserved, we get a scratch register and move from
234
+ // ebx into it in the asm. The asm needs to preserve the value of
235
+ // that register though, so it is pushed and popped around the main asm
236
+ // (in 64 bit mode for 64 bit processors, 32 bit processors would use ebx)
250
237
251
- // Turn the resulting values into a string
252
- let mut s = String :: with_capacity (12 );
253
- ebx . to_ne_bytes (). map (| b | s . push (char :: from (b )));
254
- edx . to_ne_bytes (). map (| b | s . push (char :: from (b )));
255
- ecx . to_ne_bytes (). map (| b | s . push (char :: from (b )));
256
- println! (" CPU Manufacturer ID: {}" , s );
238
+ unsafe {
239
+ asm! (
240
+ " push rbx" ,
241
+ " cpuid" ,
242
+ " mov [{0}], ebx" ,
243
+ " mov [{0} + 4], edx" ,
244
+ " mov [{0} + 8], ecx" ,
245
+ " pop rbx" ,
246
+ // We use a pointer to an array for storing the values to simplify
247
+ // the Rust code at the cost of a couple more asm instructions
248
+ // This is more explicit with how the asm works however, as opposed
249
+ // to explicit register outputs such as `out("ecx") val`
250
+ // The *pointer itself* is only an input even though it's written behind
251
+ in (reg ) name_buf . as_mut_ptr (),
252
+ // select cpuid 0, also specify eax as clobbered
253
+ inout (" eax" ) 0 => _ ,
254
+ // cpuid clobbers these registers too
255
+ out (" ecx" ) _ ,
256
+ out (" edx" ) _ ,
257
+ );
258
+ }
259
+
260
+ let name = core :: str :: from_utf8 (& name_buf ). unwrap ();
261
+ println! (" CPU Manufacturer ID: {}" , name );
262
+ }
257
263
```
258
264
259
265
In the example above we use the ` cpuid ` instruction to read the CPU manufacturer ID.
0 commit comments