From ef55ea2e231572a58300397cc9a6499aca9358c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20Unneb=C3=A4ck?= Date: Sat, 12 Sep 2026 13:32:10 +0200 Subject: [PATCH 1/3] add pushfd, popfd Co-Authored-By: Claude Fable 5.1 --- tc/src/codegen/misc.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tc/src/codegen/misc.rs b/tc/src/codegen/misc.rs index 827dd83d..0e9e233b 100644 --- a/tc/src/codegen/misc.rs +++ b/tc/src/codegen/misc.rs @@ -93,7 +93,15 @@ impl<'a> CodeGen<'a> { self.todo(format!("int {:#x}", instr.immediate8())); } } - Int3 | Cmpxchg | Pushfd | Cpuid | Xgetbv | Bt | Div => self.todo(instr_name(instr)), + Int3 | Cmpxchg | Cpuid | Xgetbv | Bt | Div => self.todo(instr_name(instr)), + + Pushfd => self.line("ctx.push32(ctx.cpu.flags.bits());"), + Popfd => { + // Keep bits we don't model (like ID, bit 21) so that the usual + // "can I toggle ID?" probe for cpuid support sees them again. + self.line("let flags = ctx.pop32();"); + self.line("ctx.cpu.flags = Flags::from_bits_retain(flags);"); + } // CBW/CWDE: sign extend to next larger ax Cbw => self.line("ctx.cpu.regs.set_ax(ctx.cpu.regs.get_al() as i8 as i16 as u16);"), From 7b39a737873e110bdf4437c56645953a60de1423 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20Unneb=C3=A4ck?= Date: Sat, 12 Sep 2026 13:32:33 +0200 Subject: [PATCH 2/3] add bt Co-Authored-By: Claude Fable 5.1 --- tc/src/codegen/misc.rs | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/tc/src/codegen/misc.rs b/tc/src/codegen/misc.rs index 0e9e233b..e1a292e4 100644 --- a/tc/src/codegen/misc.rs +++ b/tc/src/codegen/misc.rs @@ -93,7 +93,27 @@ impl<'a> CodeGen<'a> { self.todo(format!("int {:#x}", instr.immediate8())); } } - Int3 | Cmpxchg | Cpuid | Xgetbv | Bt | Div => self.todo(instr_name(instr)), + Int3 | Cmpxchg | Cpuid | Xgetbv | Div => self.todo(instr_name(instr)), + + Bt => { + // With a memory operand and a register index the hardware can + // address bits outside the operand; only handle the in-range forms. + if instr.op0_kind() == iced_x86::OpKind::Memory + && instr.op1_kind() == iced_x86::OpKind::Register + { + self.todo(format!("{instr}")); + return true; + } + let size = op_size(instr, 0); + self.line(format!( + "let bit = ({} as u32) % {size};", + self.get_op(instr, 1) + )); + self.line(format!( + "ctx.cpu.flags.set(Flags::CF, ({} >> bit) & 1 != 0);", + self.get_op(instr, 0) + )); + } Pushfd => self.line("ctx.push32(ctx.cpu.flags.bits());"), Popfd => { From ccb1f3de9a44cd2ac514317799a8d0af17762587 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20Unneb=C3=A4ck?= Date: Sat, 12 Sep 2026 13:32:35 +0200 Subject: [PATCH 3/3] add cpuid It describes a plain Pentium with an FPU and nothing else, so programs probing for TSC or MMX take the paths we implement. Co-Authored-By: Claude Fable 5.1 --- runtime/src/ops/misc.rs | 16 ++++++++++++++++ tc/src/codegen/misc.rs | 4 +++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/runtime/src/ops/misc.rs b/runtime/src/ops/misc.rs index a4c06e3d..ac92b5a8 100644 --- a/runtime/src/ops/misc.rs +++ b/runtime/src/ops/misc.rs @@ -12,6 +12,22 @@ impl Context { .write::(segofs(self.cpu.regs.ss, self.cpu.regs.get_sp()), x); } + /// cpuid, describing a plain Pentium: an FPU and nothing else (no TSC, no + /// MMX), so programs take the paths this runtime implements. + pub fn cpuid(&mut self) { + let (eax, ebx, ecx, edx) = match self.cpu.regs.eax { + // Highest leaf, and "GenuineIntel" in ebx:edx:ecx. + 0 => (1, 0x756e_6547, 0x6c65_746e, 0x4965_6e69), + // Family 5 model 4 stepping 3; feature flags: FPU. + 1 => (0x543, 0, 0, 0x1), + _ => (0, 0, 0, 0), + }; + self.cpu.regs.eax = eax; + self.cpu.regs.ebx = ebx; + self.cpu.regs.ecx = ecx; + self.cpu.regs.edx = edx; + } + pub fn pop32(&mut self) -> u32 { let x = self.memory.read::(self.cpu.regs.esp); self.cpu.regs.esp += 4; diff --git a/tc/src/codegen/misc.rs b/tc/src/codegen/misc.rs index e1a292e4..e1338b00 100644 --- a/tc/src/codegen/misc.rs +++ b/tc/src/codegen/misc.rs @@ -93,7 +93,9 @@ impl<'a> CodeGen<'a> { self.todo(format!("int {:#x}", instr.immediate8())); } } - Int3 | Cmpxchg | Cpuid | Xgetbv | Div => self.todo(instr_name(instr)), + Int3 | Cmpxchg | Xgetbv | Div => self.todo(instr_name(instr)), + + Cpuid => self.line("ctx.cpuid();"), Bt => { // With a memory operand and a register index the hardware can