1 // 2 // Copyright © 2020 Intel Corporation 3 // 4 // SPDX-License-Identifier: Apache-2.0 5 // 6 7 #![allow(non_camel_case_types)] 8 9 // 10 // MOV-Move 11 // SDM Volume 1, Chapter 4.3 12 // Copies the second operand (source operand) to the first operand (destination operand). 13 // 14 15 use crate::arch::x86::emulator::instructions::*; 16 17 macro_rules! mov_rm_r { 18 ($bound:ty) => { 19 fn emulate( 20 &self, 21 insn: &Instruction, 22 state: &mut T, 23 platform: &mut dyn PlatformEmulator<CpuState = T>, 24 ) -> Result<(), EmulationError<Exception>> { 25 let src_reg_value = get_op(&insn, 1, std::mem::size_of::<$bound>(), state, platform) 26 .map_err(EmulationError::PlatformEmulationError)?; 27 28 set_op( 29 &insn, 30 0, 31 std::mem::size_of::<$bound>(), 32 state, 33 platform, 34 src_reg_value, 35 ) 36 .map_err(EmulationError::PlatformEmulationError)?; 37 38 Ok(()) 39 } 40 }; 41 } 42 43 macro_rules! mov_rm_imm { 44 ($bound:ty) => { 45 fn emulate( 46 &self, 47 insn: &Instruction, 48 state: &mut T, 49 platform: &mut dyn PlatformEmulator<CpuState = T>, 50 ) -> Result<(), EmulationError<Exception>> { 51 let imm = get_op(&insn, 1, std::mem::size_of::<$bound>(), state, platform) 52 .map_err(EmulationError::PlatformEmulationError)?; 53 54 set_op( 55 &insn, 56 0, 57 std::mem::size_of::<$bound>(), 58 state, 59 platform, 60 imm, 61 ) 62 .map_err(EmulationError::PlatformEmulationError)?; 63 64 Ok(()) 65 } 66 }; 67 } 68 69 macro_rules! movzx { 70 ($dest_op_size:ty, $src_op_size:ty) => { 71 fn emulate( 72 &self, 73 insn: &Instruction, 74 state: &mut T, 75 platform: &mut dyn PlatformEmulator<CpuState = T>, 76 ) -> Result<(), EmulationError<Exception>> { 77 let src_value = get_op( 78 &insn, 79 1, 80 std::mem::size_of::<$src_op_size>(), 81 state, 82 platform, 83 ) 84 .map_err(EmulationError::PlatformEmulationError)?; 85 86 set_op( 87 &insn, 88 0, 89 std::mem::size_of::<$dest_op_size>(), 90 state, 91 platform, 92 src_value, 93 ) 94 .map_err(EmulationError::PlatformEmulationError)?; 95 96 Ok(()) 97 } 98 }; 99 } 100 101 // MOV r/rm is a special case of MOVZX, where both operands have the same size. 102 macro_rules! mov_r_rm { 103 ($op_size:ty) => { 104 movzx!($op_size, $op_size); 105 }; 106 } 107 108 macro_rules! mov_r_imm { 109 ($bound:ty) => { 110 fn emulate( 111 &self, 112 insn: &Instruction, 113 state: &mut T, 114 platform: &mut dyn PlatformEmulator<CpuState = T>, 115 ) -> Result<(), EmulationError<Exception>> { 116 let imm = get_op(&insn, 1, std::mem::size_of::<$bound>(), state, platform) 117 .map_err(EmulationError::PlatformEmulationError)?; 118 119 set_op( 120 &insn, 121 0, 122 std::mem::size_of::<$bound>(), 123 state, 124 platform, 125 imm, 126 ) 127 .map_err(EmulationError::PlatformEmulationError)?; 128 129 Ok(()) 130 } 131 }; 132 } 133 134 pub struct Mov_r8_rm8; 135 impl<T: CpuStateManager> InstructionHandler<T> for Mov_r8_rm8 { 136 mov_r_rm!(u8); 137 } 138 139 pub struct Mov_r8_imm8; 140 impl<T: CpuStateManager> InstructionHandler<T> for Mov_r8_imm8 { 141 mov_r_imm!(u8); 142 } 143 144 pub struct Mov_r16_rm16; 145 impl<T: CpuStateManager> InstructionHandler<T> for Mov_r16_rm16 { 146 mov_r_rm!(u16); 147 } 148 149 pub struct Mov_r16_imm16; 150 impl<T: CpuStateManager> InstructionHandler<T> for Mov_r16_imm16 { 151 mov_r_imm!(u16); 152 } 153 154 pub struct Mov_r32_rm32; 155 impl<T: CpuStateManager> InstructionHandler<T> for Mov_r32_rm32 { 156 mov_r_rm!(u32); 157 } 158 159 pub struct Mov_r32_imm32; 160 impl<T: CpuStateManager> InstructionHandler<T> for Mov_r32_imm32 { 161 mov_r_imm!(u32); 162 } 163 164 pub struct Mov_r64_rm64; 165 impl<T: CpuStateManager> InstructionHandler<T> for Mov_r64_rm64 { 166 mov_r_rm!(u64); 167 } 168 169 pub struct Mov_r64_imm64; 170 impl<T: CpuStateManager> InstructionHandler<T> for Mov_r64_imm64 { 171 mov_r_imm!(u64); 172 } 173 174 pub struct Mov_rm8_imm8; 175 impl<T: CpuStateManager> InstructionHandler<T> for Mov_rm8_imm8 { 176 mov_rm_imm!(u8); 177 } 178 179 pub struct Mov_rm8_r8; 180 impl<T: CpuStateManager> InstructionHandler<T> for Mov_rm8_r8 { 181 mov_rm_r!(u8); 182 } 183 184 pub struct Mov_rm16_imm16; 185 impl<T: CpuStateManager> InstructionHandler<T> for Mov_rm16_imm16 { 186 mov_rm_imm!(u16); 187 } 188 189 pub struct Mov_rm16_r16; 190 impl<T: CpuStateManager> InstructionHandler<T> for Mov_rm16_r16 { 191 mov_rm_r!(u16); 192 } 193 194 pub struct Mov_rm32_imm32; 195 impl<T: CpuStateManager> InstructionHandler<T> for Mov_rm32_imm32 { 196 mov_rm_imm!(u32); 197 } 198 199 pub struct Mov_rm32_r32; 200 impl<T: CpuStateManager> InstructionHandler<T> for Mov_rm32_r32 { 201 mov_rm_r!(u32); 202 } 203 204 pub struct Mov_rm64_imm32; 205 impl<T: CpuStateManager> InstructionHandler<T> for Mov_rm64_imm32 { 206 mov_rm_imm!(u32); 207 } 208 209 pub struct Mov_rm64_r64; 210 impl<T: CpuStateManager> InstructionHandler<T> for Mov_rm64_r64 { 211 mov_rm_r!(u64); 212 } 213 214 // MOVZX 215 pub struct Movzx_r16_rm8; 216 impl<T: CpuStateManager> InstructionHandler<T> for Movzx_r16_rm8 { 217 movzx!(u16, u8); 218 } 219 220 pub struct Movzx_r32_rm8; 221 impl<T: CpuStateManager> InstructionHandler<T> for Movzx_r32_rm8 { 222 movzx!(u32, u8); 223 } 224 225 pub struct Movzx_r64_rm8; 226 impl<T: CpuStateManager> InstructionHandler<T> for Movzx_r64_rm8 { 227 movzx!(u64, u8); 228 } 229 230 pub struct Movzx_r32_rm16; 231 impl<T: CpuStateManager> InstructionHandler<T> for Movzx_r32_rm16 { 232 movzx!(u32, u16); 233 } 234 235 pub struct Movzx_r64_rm16; 236 impl<T: CpuStateManager> InstructionHandler<T> for Movzx_r64_rm16 { 237 movzx!(u64, u16); 238 } 239 240 pub struct Mov_moffs16_AX; 241 impl<T: CpuStateManager> InstructionHandler<T> for Mov_moffs16_AX { 242 movzx!(u16, u16); 243 } 244 245 pub struct Mov_AX_moffs16; 246 impl<T: CpuStateManager> InstructionHandler<T> for Mov_AX_moffs16 { 247 movzx!(u16, u16); 248 } 249 250 pub struct Mov_moffs32_EAX; 251 impl<T: CpuStateManager> InstructionHandler<T> for Mov_moffs32_EAX { 252 movzx!(u32, u32); 253 } 254 255 pub struct Mov_EAX_moffs32; 256 impl<T: CpuStateManager> InstructionHandler<T> for Mov_EAX_moffs32 { 257 movzx!(u32, u32); 258 } 259 260 pub struct Mov_moffs64_RAX; 261 impl<T: CpuStateManager> InstructionHandler<T> for Mov_moffs64_RAX { 262 movzx!(u64, u64); 263 } 264 265 pub struct Mov_RAX_moffs64; 266 impl<T: CpuStateManager> InstructionHandler<T> for Mov_RAX_moffs64 { 267 movzx!(u64, u64); 268 } 269 270 #[cfg(test)] 271 mod tests { 272 use super::*; 273 use crate::arch::x86::emulator::mock_vmm::*; 274 275 #[test] 276 // mov rax,rbx 277 fn test_mov_r64_r64() { 278 let rbx: u64 = 0x8899aabbccddeeff; 279 let ip: u64 = 0x1000; 280 let cpu_id = 0; 281 let insn = [0x48, 0x89, 0xd8]; 282 let mut vmm = MockVmm::new(ip, vec![(Register::RBX, rbx)], None); 283 assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok()); 284 285 let rax: u64 = vmm 286 .cpu_state(cpu_id) 287 .unwrap() 288 .read_reg(Register::RAX) 289 .unwrap(); 290 assert_eq!(rax, rbx); 291 } 292 293 #[test] 294 // mov rax,0x1122334411223344 295 fn test_mov_r64_imm64() { 296 let imm64: u64 = 0x1122334411223344; 297 let ip: u64 = 0x1000; 298 let cpu_id = 0; 299 let insn = [0x48, 0xb8, 0x44, 0x33, 0x22, 0x11, 0x44, 0x33, 0x22, 0x11]; 300 let mut vmm = MockVmm::new(ip, vec![], None); 301 assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok()); 302 303 let rax: u64 = vmm 304 .cpu_state(cpu_id) 305 .unwrap() 306 .read_reg(Register::RAX) 307 .unwrap(); 308 assert_eq!(rax, imm64); 309 } 310 311 #[test] 312 // mov rax, [rax+rax] 313 fn test_mov_r64_m64() { 314 let target_rax: u64 = 0x1234567812345678; 315 let mut rax: u64 = 0x100; 316 let ip: u64 = 0x1000; 317 let cpu_id = 0; 318 let memory: [u8; 8] = target_rax.to_le_bytes(); 319 let insn = [0x48, 0x8b, 0x04, 0x00]; 320 let mut vmm = MockVmm::new(ip, vec![(Register::RAX, rax)], Some((rax + rax, &memory))); 321 assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok()); 322 323 rax = vmm 324 .cpu_state(cpu_id) 325 .unwrap() 326 .read_reg(Register::RAX) 327 .unwrap(); 328 assert_eq!(rax, target_rax); 329 } 330 331 #[test] 332 // mov al,0x11 333 fn test_mov_r8_imm8() { 334 let imm8: u8 = 0x11; 335 let ip: u64 = 0x1000; 336 let cpu_id = 0; 337 let insn = [0xb0, 0x11]; 338 let mut vmm = MockVmm::new(ip, vec![], None); 339 assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok()); 340 341 let al = vmm 342 .cpu_state(cpu_id) 343 .unwrap() 344 .read_reg(Register::AL) 345 .unwrap(); 346 assert_eq!(al as u8, imm8); 347 } 348 349 #[test] 350 // mov eax,0x11 351 fn test_mov_r32_imm8() { 352 let imm8: u8 = 0x11; 353 let ip: u64 = 0x1000; 354 let cpu_id = 0; 355 let insn = [0xb8, 0x11, 0x00, 0x00, 0x00]; 356 let mut vmm = MockVmm::new(ip, vec![], None); 357 assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok()); 358 359 let eax = vmm 360 .cpu_state(cpu_id) 361 .unwrap() 362 .read_reg(Register::EAX) 363 .unwrap(); 364 assert_eq!(eax as u8, imm8); 365 } 366 367 #[test] 368 // mov rax,0x11223344 369 fn test_mov_r64_imm32() { 370 let imm32: u32 = 0x11223344; 371 let ip: u64 = 0x1000; 372 let cpu_id = 0; 373 let insn = [0x48, 0xc7, 0xc0, 0x44, 0x33, 0x22, 0x11]; 374 let mut vmm = MockVmm::new(ip, vec![], None); 375 assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok()); 376 377 let rax: u64 = vmm 378 .cpu_state(cpu_id) 379 .unwrap() 380 .read_reg(Register::RAX) 381 .unwrap(); 382 assert_eq!(rax, imm32 as u64); 383 } 384 385 #[test] 386 // mov byte ptr [rax],dh 387 fn test_mov_m8_r8() { 388 let rax: u64 = 0x100; 389 let dh: u8 = 0x99; 390 let ip: u64 = 0x1000; 391 let cpu_id = 0; 392 let insn = [0x88, 0x30]; 393 let mut vmm = MockVmm::new( 394 ip, 395 vec![(Register::RAX, rax), (Register::DH, dh.into())], 396 None, 397 ); 398 assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok()); 399 400 let mut memory: [u8; 1] = [0; 1]; 401 vmm.read_memory(rax, &mut memory).unwrap(); 402 403 assert_eq!(u8::from_le_bytes(memory), dh); 404 } 405 406 #[test] 407 // mov dword ptr [rax],esi 408 fn test_mov_m32_r32() { 409 let rax: u64 = 0x100; 410 let esi: u32 = 0x8899; 411 let ip: u64 = 0x1000; 412 let cpu_id = 0; 413 let insn = [0x89, 0x30]; 414 let mut vmm = MockVmm::new( 415 ip, 416 vec![(Register::RAX, rax), (Register::ESI, esi.into())], 417 None, 418 ); 419 assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok()); 420 421 let mut memory: [u8; 4] = [0; 4]; 422 vmm.read_memory(rax, &mut memory).unwrap(); 423 424 assert_eq!(u32::from_le_bytes(memory), esi); 425 } 426 427 #[test] 428 // mov dword ptr [rax+0x00000001],edi 429 fn test_mov_m32imm32_r32() { 430 let rax: u64 = 0x100; 431 let displacement: u64 = 0x1; 432 let edi: u32 = 0x8899; 433 let ip: u64 = 0x1000; 434 let cpu_id = 0; 435 let insn = [0x89, 0x3c, 0x05, 0x01, 0x00, 0x00, 0x00]; 436 let mut vmm = MockVmm::new( 437 ip, 438 vec![(Register::RAX, rax), (Register::EDI, edi.into())], 439 None, 440 ); 441 assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok()); 442 443 let mut memory: [u8; 4] = [0; 4]; 444 vmm.read_memory(rax + displacement, &mut memory).unwrap(); 445 446 assert_eq!(u32::from_le_bytes(memory), edi); 447 } 448 449 #[test] 450 // mov eax,dword ptr [rax+10h] 451 fn test_mov_r32_m32imm32() { 452 let rax: u64 = 0x100; 453 let displacement: u64 = 0x10; 454 let eax: u32 = 0xaabbccdd; 455 let memory: [u8; 4] = eax.to_le_bytes(); 456 let ip: u64 = 0x1000; 457 let cpu_id = 0; 458 let insn = [0x8b, 0x40, 0x10]; 459 let mut vmm = MockVmm::new( 460 ip, 461 vec![(Register::RAX, rax)], 462 Some((rax + displacement, &memory)), 463 ); 464 assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok()); 465 466 let new_eax = vmm 467 .cpu_state(cpu_id) 468 .unwrap() 469 .read_reg(Register::EAX) 470 .unwrap(); 471 assert_eq!(new_eax, eax as u64); 472 } 473 474 #[test] 475 // mov al,byte ptr [rax+10h] 476 fn test_mov_r8_m32imm32() { 477 let rax: u64 = 0x100; 478 let displacement: u64 = 0x10; 479 let al: u8 = 0xaa; 480 let ip: u64 = 0x1000; 481 let cpu_id = 0; 482 let insn = [0x8a, 0x40, 0x10]; 483 let memory: [u8; 1] = al.to_le_bytes(); 484 let mut vmm = MockVmm::new( 485 ip, 486 vec![(Register::RAX, rax)], 487 Some((rax + displacement, &memory)), 488 ); 489 assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok()); 490 491 let new_al = vmm 492 .cpu_state(cpu_id) 493 .unwrap() 494 .read_reg(Register::AL) 495 .unwrap(); 496 assert_eq!(new_al, al as u64); 497 } 498 499 #[test] 500 // mov rax, 0x100 501 // mov rbx, qword ptr [rax+10h] 502 fn test_mov_r64_imm64_and_r64_m64() { 503 let target_rax: u64 = 0x1234567812345678; 504 let rax: u64 = 0x100; 505 let displacement: u64 = 0x10; 506 let ip: u64 = 0x1000; 507 let cpu_id = 0; 508 let memory: [u8; 8] = target_rax.to_le_bytes(); 509 let insn = [ 510 0x48, 0xc7, 0xc0, 0x00, 0x01, 0x00, 0x00, // mov rax, 0x100 511 0x48, 0x8b, 0x58, 0x10, // mov rbx, qword ptr [rax+10h] 512 ]; 513 let mut vmm = MockVmm::new(ip, vec![], Some((rax + displacement, &memory))); 514 assert!(vmm.emulate_insn(cpu_id, &insn, Some(2)).is_ok()); 515 516 let rbx: u64 = vmm 517 .cpu_state(cpu_id) 518 .unwrap() 519 .read_reg(Register::RBX) 520 .unwrap(); 521 assert_eq!(rbx, target_rax); 522 } 523 524 #[test] 525 // mov rax, 0x100 526 // mov rbx, qword ptr [rax+10h] 527 fn test_mov_r64_imm64_and_r64_m64_first_insn() { 528 let target_rax: u64 = 0x1234567812345678; 529 let rax: u64 = 0x100; 530 let displacement: u64 = 0x10; 531 let ip: u64 = 0x1000; 532 let cpu_id = 0; 533 let memory: [u8; 8] = target_rax.to_le_bytes(); 534 let insn = [ 535 0x48, 0xc7, 0xc0, 0x00, 0x01, 0x00, 0x00, // mov rax, 0x100 536 0x48, 0x8b, 0x58, 0x10, // mov rbx, qword ptr [rax+10h] 537 ]; 538 539 let mut vmm = MockVmm::new(ip, vec![], Some((rax + displacement, &memory))); 540 // Only run the first instruction. 541 assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok()); 542 543 assert_eq!(ip + 7, vmm.cpu_state(cpu_id).unwrap().ip()); 544 545 let new_rax: u64 = vmm 546 .cpu_state(cpu_id) 547 .unwrap() 548 .read_reg(Register::RAX) 549 .unwrap(); 550 assert_eq!(rax, new_rax); 551 } 552 553 #[test] 554 // mov rax, 0x100 555 // mov rbx, qword ptr [rax+10h] 556 // mov rax, 0x200 557 fn test_mov_r64_imm64_and_r64_m64_two_insns() { 558 let target_rax: u64 = 0x1234567812345678; 559 let rax: u64 = 0x100; 560 let displacement: u64 = 0x10; 561 let ip: u64 = 0x1000; 562 let cpu_id = 0; 563 let memory: [u8; 8] = target_rax.to_le_bytes(); 564 let insn = [ 565 0x48, 0xc7, 0xc0, 0x00, 0x01, 0x00, 0x00, // mov rax, 0x100 566 0x48, 0x8b, 0x58, 0x10, // mov rbx, qword ptr [rax+10h] 567 0x48, 0xc7, 0xc0, 0x00, 0x02, 0x00, 0x00, // mov rax, 0x200 568 ]; 569 570 let mut vmm = MockVmm::new(ip, vec![], Some((rax + displacement, &memory))); 571 // Run the 2 first instructions. 572 assert!(vmm.emulate_insn(cpu_id, &insn, Some(2)).is_ok()); 573 574 assert_eq!(ip + 7 + 4, vmm.cpu_state(cpu_id).unwrap().ip()); 575 576 let rbx: u64 = vmm 577 .cpu_state(cpu_id) 578 .unwrap() 579 .read_reg(Register::RBX) 580 .unwrap(); 581 assert_eq!(rbx, target_rax); 582 583 // Check that rax is still at 0x100 584 let new_rax: u64 = vmm 585 .cpu_state(cpu_id) 586 .unwrap() 587 .read_reg(Register::RAX) 588 .unwrap(); 589 assert_eq!(rax, new_rax); 590 } 591 592 #[test] 593 // movzx eax, bl 594 fn test_movzx_r32_r8l() { 595 let bx: u16 = 0x8899; 596 let ip: u64 = 0x1000; 597 let cpu_id = 0; 598 let insn = [0x0f, 0xb6, 0xc3]; 599 let mut vmm = MockVmm::new(ip, vec![(Register::BX, bx as u64)], None); 600 assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok()); 601 602 let eax: u64 = vmm 603 .cpu_state(cpu_id) 604 .unwrap() 605 .read_reg(Register::EAX) 606 .unwrap(); 607 assert_eq!(eax, (bx & 0xff) as u64); 608 } 609 610 #[test] 611 // movzx eax, bh 612 fn test_movzx_r32_r8h() { 613 let bx: u16 = 0x8899; 614 let ip: u64 = 0x1000; 615 let cpu_id = 0; 616 let insn = [0x0f, 0xb6, 0xc7]; 617 let mut vmm = MockVmm::new(ip, vec![(Register::BX, bx as u64)], None); 618 assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok()); 619 620 let eax: u64 = vmm 621 .cpu_state(cpu_id) 622 .unwrap() 623 .read_reg(Register::EAX) 624 .unwrap(); 625 assert_eq!(eax, (bx >> 8) as u64); 626 } 627 628 #[test] 629 // movzx eax, byte ptr [rbx] 630 fn test_movzx_r32_m8() { 631 let rbx: u64 = 0x100; 632 let value: u8 = 0xaa; 633 let ip: u64 = 0x1000; 634 let cpu_id = 0; 635 let insn = [0x0f, 0xb7, 0x03]; 636 let memory: [u8; 1] = value.to_le_bytes(); 637 let mut vmm = MockVmm::new(ip, vec![(Register::RBX, rbx)], Some((rbx, &memory))); 638 assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok()); 639 640 let eax: u64 = vmm 641 .cpu_state(cpu_id) 642 .unwrap() 643 .read_reg(Register::EAX) 644 .unwrap(); 645 assert_eq!(eax, value as u64); 646 } 647 648 #[test] 649 // movabs ax, ds:0x1337 650 // movabs eax, ds:0x1337 651 // movabs rax, ds:0x1337 652 fn test_mov_memoff_ax() { 653 let test_inputs: [(Register, &[u8]); 3] = [ 654 (Register::AX, &[0x66, 0xa1]), 655 (Register::EAX, &[0xa1]), 656 (Register::RAX, &[0x48, 0xa1]), 657 ]; 658 659 // Constructs the instruction with the provided inputs and emulates it. 660 fn helper(register: Register, instruction_prefix: &[u8]) { 661 let mem_addr: u64 = 0x1337; 662 let mem_value: u64 = 0x13371337deadbeef; 663 let ip: u64 = 0x1000; 664 let cpu_id = 0; 665 666 let mut instruction_bytes = Vec::new(); 667 // instruction prefix with specified register 668 instruction_bytes.extend(instruction_prefix); 669 // 64-bit memory operand 670 instruction_bytes.extend([ 671 mem_addr.to_le_bytes()[0], 672 mem_addr.to_le_bytes()[1], 673 0, 674 0, 675 0, 676 0, 677 0, 678 0, 679 ]); 680 681 let memory: [u8; 8] = mem_value.to_le_bytes(); 682 let mut vmm = MockVmm::new(ip, vec![], Some((mem_addr, &memory))); 683 assert!(vmm.emulate_first_insn(cpu_id, &instruction_bytes).is_ok()); 684 685 let ax: u64 = vmm.cpu_state(cpu_id).unwrap().read_reg(register).unwrap(); 686 687 match register { 688 Register::AX => { 689 assert_eq!(ax as u16, mem_value as u16); 690 } 691 Register::EAX => { 692 assert_eq!(ax as u32, mem_value as u32); 693 } 694 Register::RAX => { 695 assert_eq!(ax, mem_value); 696 } 697 _ => panic!(), 698 } 699 } 700 701 for (register, instruction_prefix) in test_inputs { 702 helper(register, instruction_prefix) 703 } 704 } 705 706 #[test] 707 // movabs ds:0x1337, ax 708 // movabs ds:0x1337, eax 709 // movabs ds:0x1337, rax 710 fn test_mov_ax_memoff() { 711 let test_inputs: [(Register, &[u8]); 3] = [ 712 (Register::AX, &[0x66, 0xa3]), 713 (Register::EAX, &[0xa3]), 714 (Register::RAX, &[0x48, 0xa3]), 715 ]; 716 717 // Constructs the instruction with the provided inputs and emulates it. 718 fn helper(register: Register, instruction_prefix: &[u8]) { 719 let mem_addr: u64 = 0x1337; 720 let ax: u64 = 0x13371337deadbeef; 721 let ip: u64 = 0x1000; 722 let cpu_id = 0; 723 724 let mut instruction_bytes = Vec::new(); 725 // instruction prefix with specified register 726 instruction_bytes.extend(instruction_prefix); 727 // 64-bit memory operand 728 instruction_bytes.extend([ 729 mem_addr.to_le_bytes()[0], 730 mem_addr.to_le_bytes()[1], 731 0, 732 0, 733 0, 734 0, 735 0, 736 0, 737 ]); 738 739 let mut vmm = MockVmm::new(ip, vec![(Register::RAX, ax)], None); 740 assert!(vmm.emulate_first_insn(cpu_id, &instruction_bytes).is_ok()); 741 742 match register { 743 Register::AX => { 744 let mut memory: [u8; 2] = [0; 2]; 745 vmm.read_memory(mem_addr, &mut memory).unwrap(); 746 assert_eq!(u16::from_le_bytes(memory), ax as u16); 747 } 748 Register::EAX => { 749 let mut memory: [u8; 4] = [0; 4]; 750 vmm.read_memory(mem_addr, &mut memory).unwrap(); 751 assert_eq!(u32::from_le_bytes(memory), ax as u32); 752 } 753 Register::RAX => { 754 let mut memory: [u8; 8] = [0; 8]; 755 vmm.read_memory(mem_addr, &mut memory).unwrap(); 756 assert_eq!(u64::from_le_bytes(memory), ax); 757 } 758 _ => panic!(), 759 } 760 } 761 762 for (register, instruction_prefix) in test_inputs { 763 helper(register, instruction_prefix) 764 } 765 } 766 } 767