i386, x86_64: F6/F7 (group 3) opcode with ModRM.reg == 1 is not recognized as TEST instruction
## Host environment
- Operating system: Kali Linux 2026.2
- OS/kernel version: Linux kali 6.19.14+kali-amd64 #1 SMP PREEMPT_DYNAMIC Kali 6.19.14-1+kali1 (2026-05-05) x86_64 GNU/Linux
- Architecture: x86_64
- QEMU flavor: qemu-i386, qemu-system-i386, qemu-x86_64, qemu-system-x86_64
- QEMU version: 11.0.50 (v11.0.0-2279-gb833716681)
- QEMU command line:
```
./qemu-x86_64 ./poc
```
## Emulated/Virtualized environment
- Operating system: Does not matter
- OS/kernel version: Does not matter
- Architecture: i386, x86_64
## Description of problem
According to table A-6 in Volume 3 of AMD64 Architecture Programmer's Manual, a group 3 opcode is decoded as TEST instruction when reg field of ModRM byte is either 0 or 1.
Intel 64 and IA-32 Architectures Software Developer's Manual leaves the cell 1 of opcode extensions group 3 blank in the opcode table (table A-6, Volume 2D). However, the instruction encoded like that actually behaves like the TEST instruction on Intel CPUs I tested, both in 32-bit compatibility and 64-bit modes:
- Intel Core i3-6100 (family 6, model 94, stepping 3, microcode version 0xf0)
- Intel Core i7-3770 (family 6, model 58, stepping 9, microcode version 0x21)
Currently, QEMU decodes a group 3 instruction as TEST only if reg field of ModRM byte is 0. When reg field of ModRM byte is 1, QEMU raises a #UD exception. This behavior does not match the behavior of the actual Intel and AMD hardware.
## Steps to reproduce
1. Compile the following binary with nasm:
```nasm
bits 64
global _start
_start:
xor eax, eax
db 0xf6, 0xc8, 0xff
jnz .end
not eax
db 0xf7, 0xc8, 0x01, 0x02, 0x03, 0x04
jz .end
int3
ud2
.end:
hlt
```
```bash
$ nasm -f elf64 poc.asm # or elf32, if building for qemu-i386
$ ld.lld -o poc poc.o
```
2. Optional: disassemble the binary
```bash
$ objdump -d -Mintel ./poc
./poc: file format elf64-x86-64
Disassembly of section .text:
0000000000201120 <_start>:
201120: 31 c0 xor eax,eax
201122: f6 c8 ff test al,0xff
201125: 75 0d jne 201134 <_start.end>
201127: f7 d0 not eax
201129: f7 c8 01 02 03 04 test eax,0x4030201
20112f: 74 03 je 201134 <_start.end>
201131: cc int3
201132: 0f 0b ud2
0000000000201134 <_start.end>:
201134: f4 hlt
$
```
3. Run the binary on the real hardware:
```bash
$ ./poc
Trace/breakpoint trap
$
```
4. Run the binary in QEMU:
```bash
$ ./qemu-x86_64 --version
qemu-x86_64 version 11.0.50 (v11.0.0-2279-gb833716681)
Copyright (c) 2003-2026 Fabrice Bellard and the QEMU Project developers
$ ./qemu-x86_64 -d int,in_asm,op,cpu --one-insn-per-tb ./poc # -d stuff and --one-insn-per-tb is to show what happens inside QEMU
----------------
IN:
0x00201120: 31 c0 xorl %eax, %eax
OP:
ld_i32 loc4,env,$0xffffffffffffffec
brcond_i32 loc4,$0x0,lt,$L0
st8_i32 $0x1,env,$0xfffffffffffffff0
---- 0000000000201120 000000000000003c 0000000000000000
mov_i64 loc0,rax
mov_i64 loc1,rax
mov_i64 loc0,$0x0
extract_i64 rax,loc0,$0x0,$0x20
mov_i64 cc_src,$0x44
discard cc_dst
discard cc_src2
discard cc_op
mov_i32 cc_op,$0x0
mov_i64 rip,$0x201122
exit_tb $0x0
set_label $L0
exit_tb $0x7b14e4000043
RAX=0000000000000000 RBX=0000000000000000 RCX=0000000000000000 RDX=0000000000000000
RSI=0000000000000000 RDI=0000000000000000 RBP=0000000000000000 RSP=00007b14e3ffed30
R8 =0000000000000000 R9 =0000000000000000 R10=0000000000000000 R11=0000000000000000
R12=0000000000000000 R13=0000000000000000 R14=0000000000000000 R15=0000000000000000
RIP=0000000000201120 RFL=00000202 [-------] CPL=3 II=0 A20=1 SMM=0 HLT=0
ES =0000 0000000000000000 00000000 00000000
CS =0033 0000000000000000 ffffffff 00effb00 DPL=3 CS64 [-RA]
SS =002b 0000000000000000 ffffffff 00cff300 DPL=3 DS [-WA]
DS =0000 0000000000000000 00000000 00000000
FS =0000 0000000000000000 00000000 00000000
GS =0000 0000000000000000 00000000 00000000
LDT=0000 0000000000000000 00000000 00008200 DPL=0 LDT
TR =0000 0000000000000000 0000ffff 00008b00 DPL=0 TSS64-busy
GDT= 00007f14f1c92000 0000007f
IDT= 00007f14f1c93000 000001ff
CR0=80010001 CR2=0000000000000000 CR3=0000000000000000 CR4=00050220
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=0000000000000000 CCD=0000000000000000 CCO=EFLAGS
EFER=0000000000000500
----------------
IN:
0x00201122: f6 .byte 0xf6
0x00201123: c8 .byte 0xc8
OP:
ld_i32 loc4,env,$0xffffffffffffffec
brcond_i32 loc4,$0x0,lt,$L0
st8_i32 $0x1,env,$0xfffffffffffffff0
---- 0000000000201122 000000000000003c 0000000000000000
mov_i64 rip,$0x201122
call raise_exception,$0xa,$0,env,$0x6
set_label $L0
exit_tb $0x7b14e4000183
RAX=0000000000000000 RBX=0000000000000000 RCX=0000000000000000 RDX=0000000000000000
RSI=0000000000000000 RDI=0000000000000000 RBP=0000000000000000 RSP=00007b14e3ffed30
R8 =0000000000000000 R9 =0000000000000000 R10=0000000000000000 R11=0000000000000000
R12=0000000000000000 R13=0000000000000000 R14=0000000000000000 R15=0000000000000000
RIP=0000000000201122 RFL=00000246 [---Z-P-] CPL=3 II=0 A20=1 SMM=0 HLT=0
ES =0000 0000000000000000 00000000 00000000
CS =0033 0000000000000000 ffffffff 00effb00 DPL=3 CS64 [-RA]
SS =002b 0000000000000000 ffffffff 00cff300 DPL=3 DS [-WA]
DS =0000 0000000000000000 00000000 00000000
FS =0000 0000000000000000 00000000 00000000
GS =0000 0000000000000000 00000000 00000000
LDT=0000 0000000000000000 00000000 00008200 DPL=0 LDT
TR =0000 0000000000000000 0000ffff 00008b00 DPL=0 TSS64-busy
GDT= 00007f14f1c92000 0000007f
IDT= 00007f14f1c93000 000001ff
CR0=80010001 CR2=0000000000000000 CR3=0000000000000000 CR4=00050220
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=0000000000000044 CCD=0000000000000000 CCO=EFLAGS
EFER=0000000000000500
check_exception old: 0xffffffff new 0x6
qemu: uncaught target signal 4 (Illegal instruction) - core dumped
Illegal instruction
$
```
issue