capstone icon indicating copy to clipboard operation
capstone copied to clipboard

x64 jump instructions have eip as modified register

Open OBarronCS opened this issue 8 months ago • 4 comments

Questions Answers
Capstone module affected x64
Source of Capstone pip install capstone==6.0.0a4
Version/git commit 6.0.0 alpha 4

Upon disassembling different jump instructions in x64 mode, I saw that the "registers written" value have eip as the register modified, instead of rip.

Actual behavior

cstool -d x64 "e9 d0 ff ff ff"
 0  e9 d0 ff ff ff                                   jmp	0xffffffffffffffd5
	ID: 172 (jmp)
	Prefix:0x00 0x00 0x00 0x00 
	Opcode:0xe9 0x00 0x00 0x00 
	rex: 0x0
	addr_size: 8
	modrm: 0x0
	disp: 0x0
	sib: 0x0
	imm_count: 1
		imms[1]: 0xffffffffffffffd5
	op_count: 1
		operands[0].type: IMM = 0xffffffffffffffd5
		operands[0].size: 8
	Registers modified: eip
	Groups: branch_relative jump 

The same is true for je,ja,jle,jbe, etc.

Expected behavior

Register write is rip, not eip

OBarronCS avatar Apr 23 '25 07:04 OBarronCS

The problem is that X86_JMP_4 shares the same entry on x32 and x64:

{
	X86_JMP_4, X86_INS_JMP, 0,
#ifndef CAPSTONE_DIET
	{ 0 }, { X86_REG_EIP, 0 }, { X86_GRP_BRANCH_RELATIVE, 0 }, 1, 0
#endif
},

jiegec avatar May 26 '25 11:05 jiegec

That is a tricky one to fix (a pontential won't fix bug). The implicit read/writes are collected in x86_reg_access(). But it only passes a cs_insn to it, not the currently active mode (16/32/64bit). And since the jump instructions share the same ID for 32 and 64bit we can't really determine effectively if it is eip or rip.

Changing the signature of x86_reg_access to pass the mode doesn't work, because it is an API change. We could add some kind of reg_access_fixup() function. But is it really worth it? It adds some constant runtime, even if users don't really need it. And adding a CS_OPT_FIXUP_X86_INDIRECT_REG_ACCESS seems over-engineered.

Or would you argue otherwise?

Rot127 avatar May 26 '25 13:05 Rot127

I just ran into this, as well, but for the conditional jumps (e.g., jz). I agree it's not a straightforward change and might be best examined during the migration to Zydis. That said, xed, zydis, and bddisasm all report rip for these in 64-bit mode, so it's something to consider carefully.


EDIT I just noticed that the conditional jump reports rflags instead of eflags which is correct. Yet, the entry has just eflags:

{
X86_JE_1, X86_INS_JE, 0,
#ifndef CAPSTONE_DIET
	{ X86_REG_EFLAGS, 0 }, { X86_REG_EIP, 0 }, { X86_GRP_BRANCH_RELATIVE, 0 }, 1, 0
#endif
},
./cstool -dar x64 "0x7410"
 0  74 10                                            je	0x12
	ID: 260 (je)
	Prefix:0x00 0x00 0x00 0x00 
	Opcode:0x74 0x00 0x00 0x00 
	rex: 0x0
	addr_size: 8
	modrm: 0x0
	disp: 0x0
	sib: 0x0
	imm_count: 1
		imms[1]: 0x12
	op_count: 1
		operands[0].type: IMM = 0x12
		operands[0].size: 8
	Registers read: rflags        <-----
	Registers modified: eip       <-----
	EFLAGS: TEST_ZF
	Groups: branch_relative jump 

hainest avatar Jul 30 '25 21:07 hainest

I just ran into this, as well, but for the conditional jumps (e.g., jz). I agree it's not a straightforward change and might be best examined during the migration to Zydis. That said, xed, zydis, and bddisasm all report rip for these in 64-bit mode, so it's something to consider carefully.

EDIT I just noticed that the conditional jump reports rflags instead of eflags which is correct. Yet, the entry has just eflags:

{ X86_JE_1, X86_INS_JE, 0, #ifndef CAPSTONE_DIET { X86_REG_EFLAGS, 0 }, { X86_REG_EIP, 0 }, { X86_GRP_BRANCH_RELATIVE, 0 }, 1, 0 #endif },

./cstool -dar x64 "0x7410" 0 74 10 je 0x12 ID: 260 (je) Prefix:0x00 0x00 0x00 0x00 Opcode:0x74 0x00 0x00 0x00 rex: 0x0 addr_size: 8 modrm: 0x0 disp: 0x0 sib: 0x0 imm_count: 1 imms[1]: 0x12 op_count: 1 operands[0].type: IMM = 0x12 operands[0].size: 8 Registers read: rflags <----- Registers modified: eip <----- EFLAGS: TEST_ZF Groups: branch_relative jump

This one is handled by changing the register name:

	if (reg == X86_REG_EFLAGS) {
		if (ud->mode & CS_MODE_32)
			return "eflags";
		if (ud->mode & CS_MODE_64)
			return "rflags";
	}

which means you still get the X86_REG_EFLAGS, only the name printed has changed.

jiegec avatar Jul 31 '25 02:07 jiegec