-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Open
Labels
X86ArchArch
Description
Work environment
| Questions | Answers |
|---|---|
| System Capstone runs on OS/arch/bits | Ubuntu 24.04 (x86 64-bit) |
| Capstone module affected | x64 |
| Source of Capstone | git clone |
| Version/git commit | 8872be6 |
Instruction bytes giving faulty results
0x64,0x26,0x00,0x00
Expected results
It should be:
addb %al, %fs:(%rax)
Steps to get the wrong result
With cstool:
cstool -d x64 64260000Additional Logs, screenshots, source code, configuration dump, ...
The current output is:
addb %al, %es:(%rax)
Although (I believe) stacking multiple segment prefixes is technically undefined behavior, CPUs typically completely ignore ES/CS/SS/DS segment overrides and use a previous FS/GS segment override if present. Other disassemblers (Zydis, XED, libopcodes) all copy this behavior.
The fix below seems to work, but I have not been able to determine if there are any unexpected side-effects from not setting segmentOverride while still setting prefix1. Ideally prefix1 should only be set for conditional jumps, as 26 and 36 are also used as branch taken/not taken hints.
diff --git a/arch/X86/X86DisassemblerDecoder.c b/arch/X86/X86DisassemblerDecoder.c
index 0938d561..3b141036 100644
--- a/arch/X86/X86DisassemblerDecoder.c
+++ b/arch/X86/X86DisassemblerDecoder.c
@@ -523,19 +523,27 @@ static int readPrefixes(struct InternalInstruction *insn)
case 0x65: /* GS segment override */
switch (byte) {
case 0x2e:
- insn->segmentOverride = SEG_OVERRIDE_CS;
+ if (insn->mode != MODE_64BIT) {
+ insn->segmentOverride = SEG_OVERRIDE_CS;
+ }
insn->prefix1 = byte;
break;
case 0x36:
- insn->segmentOverride = SEG_OVERRIDE_SS;
+ if (insn->mode != MODE_64BIT) {
+ insn->segmentOverride = SEG_OVERRIDE_SS;
+ }
insn->prefix1 = byte;
break;
case 0x3e:
- insn->segmentOverride = SEG_OVERRIDE_DS;
+ if (insn->mode != MODE_64BIT) {
+ insn->segmentOverride = SEG_OVERRIDE_DS;
+ }
insn->prefix1 = byte;
break;
case 0x26:
- insn->segmentOverride = SEG_OVERRIDE_ES;
+ if (insn->mode != MODE_64BIT) {
+ insn->segmentOverride = SEG_OVERRIDE_ES;
+ }
insn->prefix1 = byte;
break;
Metadata
Metadata
Assignees
Labels
X86ArchArch