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