aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/long_mode/mod.rs15
-rw-r--r--src/protected_mode/mod.rs27
-rw-r--r--src/real_mode/mod.rs27
-rw-r--r--test/long_mode/operand.rs8
-rw-r--r--test/protected_mode/operand.rs8
-rw-r--r--test/real_mode/operand.rs8
6 files changed, 93 insertions, 0 deletions
diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs
index f3b4dc0..500c9f9 100644
--- a/src/long_mode/mod.rs
+++ b/src/long_mode/mod.rs
@@ -8915,11 +8915,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
+ // > is 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/src/protected_mode/mod.rs b/src/protected_mode/mod.rs
index 0df8cee..10bc9d6 100644
--- a/src/protected_mode/mod.rs
+++ b/src/protected_mode/mod.rs
@@ -8679,31 +8679,58 @@ fn read_operands<
instruction.regs[0] = RegSpec::cs();
instruction.operands[0] = OperandSpec::RegRRR;
instruction.operand_count = 1;
+
+ // see the comment on mem size as written in OperandCase::FS
+ instruction.mem_size = 2;
}
OperandCase::DS => {
instruction.regs[0] = RegSpec::ds();
instruction.operands[0] = OperandSpec::RegRRR;
instruction.operand_count = 1;
+
+ // see the comment on mem size as written in OperandCase::FS
+ instruction.mem_size = 2;
}
OperandCase::ES => {
instruction.regs[0] = RegSpec::es();
instruction.operands[0] = OperandSpec::RegRRR;
instruction.operand_count = 1;
+
+ // see the comment on mem size as written in OperandCase::FS
+ instruction.mem_size = 2;
}
OperandCase::SS => {
instruction.regs[0] = RegSpec::ss();
instruction.operands[0] = OperandSpec::RegRRR;
instruction.operand_count = 1;
+
+ // see the comment on mem size as written in OperandCase::FS
+ instruction.mem_size = 2;
}
OperandCase::FS => {
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 zero-extended 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
+ // > is 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 all 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 = 4;
}
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 = 4;
}
OperandCase::AL_Ib => {
instruction.regs[0] =
diff --git a/src/real_mode/mod.rs b/src/real_mode/mod.rs
index c11cf00..7ac4c2e 100644
--- a/src/real_mode/mod.rs
+++ b/src/real_mode/mod.rs
@@ -8724,31 +8724,58 @@ fn read_operands<
instruction.regs[0] = RegSpec::cs();
instruction.operands[0] = OperandSpec::RegRRR;
instruction.operand_count = 1;
+
+ // see the comment on mem size as written in OperandCase::FS
+ instruction.mem_size = 2;
}
OperandCase::DS => {
instruction.regs[0] = RegSpec::ds();
instruction.operands[0] = OperandSpec::RegRRR;
instruction.operand_count = 1;
+
+ // see the comment on mem size as written in OperandCase::FS
+ instruction.mem_size = 2;
}
OperandCase::ES => {
instruction.regs[0] = RegSpec::es();
instruction.operands[0] = OperandSpec::RegRRR;
instruction.operand_count = 1;
+
+ // see the comment on mem size as written in OperandCase::FS
+ instruction.mem_size = 2;
}
OperandCase::SS => {
instruction.regs[0] = RegSpec::ss();
instruction.operands[0] = OperandSpec::RegRRR;
instruction.operand_count = 1;
+
+ // see the comment on mem size as written in OperandCase::FS
+ instruction.mem_size = 2;
}
OperandCase::FS => {
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 zero-extended 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
+ // > is 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 all 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 = 2;
}
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 = 2;
}
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));
}
diff --git a/test/protected_mode/operand.rs b/test/protected_mode/operand.rs
index fe9b54a..70dcadb 100644
--- a/test/protected_mode/operand.rs
+++ b/test/protected_mode/operand.rs
@@ -55,4 +55,12 @@ fn test_implied_memory_width() {
assert_eq!(mem_size_of(&[0xc9]), Some(4));
// xlat
assert_eq!(mem_size_of(&[0xd7]), Some(1));
+ // push fs
+ assert_eq!(mem_size_of(&[0x0f, 0xa0]), Some(4));
+ // pop fs
+ assert_eq!(mem_size_of(&[0x0f, 0xa1]), Some(4));
+ // push gs
+ assert_eq!(mem_size_of(&[0x0f, 0xa8]), Some(4));
+ // pop gs
+ assert_eq!(mem_size_of(&[0x0f, 0xa9]), Some(4));
}
diff --git a/test/real_mode/operand.rs b/test/real_mode/operand.rs
index e0f59e1..cdf5113 100644
--- a/test/real_mode/operand.rs
+++ b/test/real_mode/operand.rs
@@ -28,4 +28,12 @@ fn test_implied_memory_width() {
assert_eq!(mem_size_of(&[0xc9]), Some(2));
// xlat
assert_eq!(mem_size_of(&[0xd7]), Some(1));
+ // push fs
+ assert_eq!(mem_size_of(&[0x0f, 0xa0]), Some(2));
+ // pop fs
+ assert_eq!(mem_size_of(&[0x0f, 0xa1]), Some(2));
+ // push gs
+ assert_eq!(mem_size_of(&[0x0f, 0xa8]), Some(2));
+ // pop gs
+ assert_eq!(mem_size_of(&[0x0f, 0xa9]), Some(2));
}