diff options
| author | iximeow <me@iximeow.net> | 2026-03-27 06:32:04 +0000 |
|---|---|---|
| committer | iximeow <me@iximeow.net> | 2026-03-27 06:32:04 +0000 |
| commit | ac4daa2404dcfb05b0f080d05895062747b70a47 (patch) | |
| tree | 319cd73dac7bf9eb3f48764022a47be41b0fced6 | |
| parent | dc74e3e1b6c49f38e3e91c2aebae5cdcf1f4062b (diff) | |
push/pop for segment registers has implicit memory access
| -rw-r--r-- | src/long_mode/mod.rs | 15 | ||||
| -rw-r--r-- | test/long_mode/operand.rs | 8 |
2 files changed, 23 insertions, 0 deletions
diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs index 3062783..d6ad7df 100644 --- a/src/long_mode/mod.rs +++ b/src/long_mode/mod.rs @@ -8918,11 +8918,26 @@ fn read_operands< instruction.regs[0] = RegSpec::fs(); instruction.operands[0] = OperandSpec::RegRRR; instruction.operand_count = 1; + + // good grief. from the SDM: + // + // > If the source operand is a segment register (16 bits) and the operand size is + // > 64-bits, a zeroextended value is pushed on the stack; if the operand size is + // > 32-bits, either a zero-extended value is pushed on the stack or the segment selector + // > s written on the stack using a 16-bit move + // + // the memory size here really depends on the `Default` bit in the CS descriptor. if + // the default operand size is 64 bits (basically every long-mode code), the acccess is + // 8 bytes (zero extended). if the default operand size is 32 bits, this is more complex. + instruction.mem_size = 8; } OperandCase::GS => { instruction.regs[0] = RegSpec::gs(); instruction.operands[0] = OperandSpec::RegRRR; instruction.operand_count = 1; + + // see the comment on mem size as written in OperandCase::FS + instruction.mem_size = 8; } OperandCase::AL_Ib => { instruction.regs[0] = diff --git a/test/long_mode/operand.rs b/test/long_mode/operand.rs index 10c4deb..09ac5a2 100644 --- a/test/long_mode/operand.rs +++ b/test/long_mode/operand.rs @@ -61,4 +61,12 @@ fn test_implied_memory_width() { assert_eq!(mem_size_of(&[0xc9]), Some(8)); // xlat assert_eq!(mem_size_of(&[0xd7]), Some(1)); + // push fs + assert_eq!(mem_size_of(&[0x0f, 0xa0]), Some(8)); + // pop fs + assert_eq!(mem_size_of(&[0x0f, 0xa1]), Some(8)); + // push gs + assert_eq!(mem_size_of(&[0x0f, 0xa8]), Some(8)); + // pop gs + assert_eq!(mem_size_of(&[0x0f, 0xa9]), Some(8)); } |
