On 10.07.2026 08:20, Jan Beulich wrote:
> Reportedly (e.g. [1]) the LOCK handling is special to %cr0 / %cr8 only.
> Deal with it this way also in assembler and disassembler.
>
> For the assembler also introduce a separate feature indicator: Not all
> 64-bit CPUs support this insn form; only most AMD (and presumably all
> Hygon) ones do. Register names %cr9 ... %cr15 thus become invalid outside
> of 64-bit mode altogether (unprefixed forms become ordinary symbol names),
> while %cr8's availability outside of 64-bit mode now depends on the new
> feature indicator.
>
> For the disassembler don't limit this handling to non-64-bit modes. Use
> of LOCK is similarly permitted in 64-bit mode. Instead don't handle LOCK
> this way when "intel64" was specified as an option.
>
> [1] https://lists.xen.org/archives/html/xen-devel/2026-07/msg00391.html
Argh - the hunks below are also needed. I really don't understand why there
still is this kind of needless duplication in ilp32/. When the expectations
aren't different between the two modes, there really should be only one
instance (that then needs modifying when a testcase is extended).
Jan
--- a/gas/testsuite/gas/i386/ilp32/x86-64-crx.d
+++ b/gas/testsuite/gas/i386/ilp32/x86-64-crx.d
@@ -1,21 +1,4 @@
#source: ../x86-64-crx.s
#objdump: -dw
#name: x86-64 (ILP32) control register related opcodes
-
-.*: +file format .*
-
-Disassembly of section .text:
-
-0+ <_start>:
-[ ]*[0-9a-f]+: 44 0f 20 c0[ ]+movq?[ ]+?%cr8,%rax
-[ ]*[0-9a-f]+: 44 0f 20 c7[ ]+movq?[ ]+?%cr8,%rdi
-[ ]*[0-9a-f]+: 44 0f 22 c0[ ]+movq?[ ]+?%rax,%cr8
-[ ]*[0-9a-f]+: 44 0f 22 c7[ ]+movq?[ ]+?%rdi,%cr8
-[ ]*[0-9a-f]+: 44 0f 20 c0[ ]+movq?[ ]+?%cr8,%rax
-[ ]*[0-9a-f]+: 44 0f 20 c7[ ]+movq?[ ]+?%cr8,%rdi
-[ ]*[0-9a-f]+: 44 0f 22 c0[ ]+movq?[ ]+?%rax,%cr8
-[ ]*[0-9a-f]+: 44 0f 22 c7[ ]+movq?[ ]+?%rdi,%cr8
-[ ]*[0-9a-f]+: 44 0f 20 c0[ ]+movq?[ ]+?%cr8,%rax
-[ ]*[0-9a-f]+: 44 0f 20 c7[ ]+movq?[ ]+?%cr8,%rdi
-[ ]*[0-9a-f]+: 44 0f 22 c0[ ]+movq?[ ]+?%rax,%cr8
-[ ]*[0-9a-f]+: 44 0f 22 c7[ ]+movq?[ ]+?%rdi,%cr8
+#dump: ../x86-64-crx.d
--- a/gas/testsuite/gas/i386/ilp32/x86-64-crx-suffix.d
+++ b/gas/testsuite/gas/i386/ilp32/x86-64-crx-suffix.d
@@ -1,21 +1,4 @@
#source: ../x86-64-crx.s
#objdump: -dwMsuffix
#name: x86-64 (ILP32) control register related opcodes (with suffixes)
-
-.*: +file format .*
-
-Disassembly of section .text:
-
-0+ <_start>:
-[ ]*[0-9a-f]+: 44 0f 20 c0[ ]+movq[ ]+?%cr8,%rax
-[ ]*[0-9a-f]+: 44 0f 20 c7[ ]+movq[ ]+?%cr8,%rdi
-[ ]*[0-9a-f]+: 44 0f 22 c0[ ]+movq[ ]+?%rax,%cr8
-[ ]*[0-9a-f]+: 44 0f 22 c7[ ]+movq[ ]+?%rdi,%cr8
-[ ]*[0-9a-f]+: 44 0f 20 c0[ ]+movq[ ]+?%cr8,%rax
-[ ]*[0-9a-f]+: 44 0f 20 c7[ ]+movq[ ]+?%cr8,%rdi
-[ ]*[0-9a-f]+: 44 0f 22 c0[ ]+movq[ ]+?%rax,%cr8
-[ ]*[0-9a-f]+: 44 0f 22 c7[ ]+movq[ ]+?%rdi,%cr8
-[ ]*[0-9a-f]+: 44 0f 20 c0[ ]+movq[ ]+?%cr8,%rax
-[ ]*[0-9a-f]+: 44 0f 20 c7[ ]+movq[ ]+?%cr8,%rdi
-[ ]*[0-9a-f]+: 44 0f 22 c0[ ]+movq[ ]+?%rax,%cr8
-[ ]*[0-9a-f]+: 44 0f 22 c7[ ]+movq[ ]+?%rdi,%cr8
+#dump: ../x86-64-crx-suffix.d
@@ -153,6 +153,7 @@ accept various extension mnemonics. For
@code{sse4},
@code{avx},
@code{avx2},
+@code{altmovcr8},
@code{lahf_sahf},
@code{monitor},
@code{adx},
@@ -1708,9 +1709,9 @@ supported on the CPU specified. The cho
@item @samp{.rdrnd} @tab @samp{.f16c} @tab @samp{.avx2} @tab @samp{.bmi2}
@item @samp{.lzcnt} @tab @samp{.popcnt} @tab @samp{.invpcid} @tab @samp{.vmfunc}
@item @samp{.monitor} @tab @samp{.hle} @tab @samp{.rtm} @tab @samp{.tsx}
-@item @samp{.lahf_sahf} @tab @samp{.adx} @tab @samp{.rdseed} @tab @samp{.prfchw}
-@item @samp{.smap} @tab @samp{.mpx} @tab @samp{.sha} @tab @samp{.prefetchwt1}
-@item @samp{.clflushopt} @tab @samp{.xsavec} @tab @samp{.xsaves} @tab @samp{.se1}
+@item @samp{.altmovcr8} @tab @samp{.lahf_sahf} @tab @samp{.adx} @tab @samp{.rdseed}
+@item @samp{.smap} @tab @samp{.mpx} @tab @samp{.sha} @tab @samp{.prfchw}
+@item @samp{.prefetchwt1} @tab @samp{.clflushopt} @tab @samp{.xsavec} @tab @samp{.xsaves}
@item @samp{.avx512f} @tab @samp{.avx512cd} @tab @samp{.avx512er} @tab @samp{.avx512pf}
@item @samp{.avx512vl} @tab @samp{.avx512bw} @tab @samp{.avx512dq} @tab @samp{.avx512ifma}
@item @samp{.avx512vbmi} @tab @samp{.avx512_4fmaps} @tab @samp{.avx512_4vnniw}
@@ -1719,7 +1720,7 @@ supported on the CPU specified. The cho
@item @samp{.tdx} @tab @samp{.avx_vnni} @tab @samp{.avx512_fp16} @tab @samp{avx512_bmm}
@item @samp{.avx10.1} @tab @samp{.clwb} @tab @samp{.rdpid} @tab @samp{.ptwrite}
@item @samp{.ibt} @tab @samp{.prefetchi} @tab @samp{.avx_ifma} @tab @samp{.avx_vnni_int8}
-@item @samp{.cmpccxadd} @tab @samp{.wrmsrns} @tab @samp{.msrlist}
+@item @samp{.cmpccxadd} @tab @samp{.wrmsrns} @tab @samp{.msrlist} @tab @samp{.se1}
@item @samp{.avx_ne_convert} @tab @samp{.rao_int} @tab @samp{.fred} @tab @samp{.lkgs}
@item @samp{.avx_vnni_int16} @tab @samp{.sha512} @tab @samp{.sm3} @tab @samp{.sm4}
@item @samp{.pbndkb} @tab @samp{.user_msr} @tab @samp{.msr_imm} @tab @samp{.avx10.2}
@@ -1147,6 +1147,7 @@ static const arch_entry cpu_arch[] =
SUBARCH (lwp, LWP, ANY_LWP, false),
SUBARCH (movbe, MOVBE, MOVBE, false),
SUBARCH (cx16, CX16, CX16, false),
+ SUBARCH (altmovcr8, ALTMOVCR8, ALTMOVCR8, false),
SUBARCH (lahf_sahf, LAHF_SAHF, LAHF_SAHF, false),
SUBARCH (ept, EPT, ANY_EPT, false),
SUBARCH (lzcnt, LZCNT, LZCNT, false),
@@ -11655,6 +11656,7 @@ build_modrm_byte (void)
if (flag_code != CODE_64BIT && (i.rex & REX_R))
{
gas_assert (i.types[!i.tm.opcode_modifier.regmem].bitfield.class == RegCR);
+ gas_assert (i.op[!i.tm.opcode_modifier.regmem].regs->reg_num == 0);
i.rex &= ~REX_R;
add_prefix (LOCK_PREFIX_OPCODE);
}
@@ -17001,10 +17003,11 @@ static bool check_register (const reg_en
}
if (((r->reg_flags & (RegRex64 | RegRex)) || r->reg_type.bitfield.qword)
- && (!cpu_arch_flags.bitfield.cpu64
+ && flag_code != CODE_64BIT
+ && (!cpu_arch_flags.bitfield.cpualtmovcr8
|| r->reg_type.bitfield.class != RegCR
- || dot_insn ())
- && flag_code != CODE_64BIT)
+ || r->reg_num != 0
+ || dot_insn ()))
return false;
if (r->reg_type.bitfield.class == SReg && r->reg_num == RegFlat
@@ -2,7 +2,7 @@
.*:[0-9]+: Error: .\(%cr0\). is not a valid base/index expression
.*:[0-9]+: Error: .\(%cr7\). is not a valid base/index expression
.*:[0-9]+: Error: .\(%cr8\). is not a valid base/index expression
-.*:[0-9]+: Error: .\(%cr15\). is not a valid base/index expression
+.*:[0-9]+: Error: bad register name `%cr15.*'
.*:[0-9]+: Error: .\(%db0\). is not a valid base/index expression
.*:[0-9]+: Error: .\(%db7\). is not a valid base/index expression
.*:[0-9]+: Error: .\(%dr0\). is not a valid base/index expression
@@ -12,7 +12,6 @@
.*:[0-9]+: Error: .\(cr0\). is not a valid base/index expression
.*:[0-9]+: Error: .\(cr7\). is not a valid base/index expression
.*:[0-9]+: Error: .\(cr8\). is not a valid base/index expression
-.*:[0-9]+: Error: .\(cr15\). is not a valid base/index expression
.*:[0-9]+: Error: .\(db0\). is not a valid base/index expression
.*:[0-9]+: Error: .\(db7\). is not a valid base/index expression
.*:[0-9]+: Error: .\(dr0\). is not a valid base/index expression
@@ -22,7 +21,6 @@
.*:[0-9]+: Error: .\[cr0\]. is not a valid base/index expression
.*:[0-9]+: Error: .\[cr7\]. is not a valid base/index expression
.*:[0-9]+: Error: .\[cr8\]. is not a valid base/index expression
-.*:[0-9]+: Error: .\[cr15\]. is not a valid base/index expression
.*:[0-9]+: Error: .\[dr0\]. is not a valid base/index expression
.*:[0-9]+: Error: .\[dr7\]. is not a valid base/index expression
.*:[0-9]+: Error: .\[tr0\]. is not a valid base/index expression
@@ -11,6 +11,8 @@ Disassembly of section .text:
[ ]*[0-9a-f]+: 44 0f 20 c7[ ]+movq?[ ]+?%cr8,%rdi
[ ]*[0-9a-f]+: 44 0f 22 c0[ ]+movq?[ ]+?%rax,%cr8
[ ]*[0-9a-f]+: 44 0f 22 c7[ ]+movq?[ ]+?%rdi,%cr8
+[ ]*[0-9a-f]+: f0 0f 20 c1[ ]+movq?[ ]+%cr8,%rcx
+[ ]*[0-9a-f]+: f0 44 0f 20 c1[ ]+lock movq?[ ]+%cr8,%rcx
[ ]*[0-9a-f]+: 44 0f 20 c0[ ]+movq?[ ]+?%cr8,%rax
[ ]*[0-9a-f]+: 44 0f 20 c7[ ]+movq?[ ]+?%cr8,%rdi
[ ]*[0-9a-f]+: 44 0f 22 c0[ ]+movq?[ ]+?%rax,%cr8
@@ -5,6 +5,9 @@ _start:
movq %rax, %cr8
movq %rdi, %cr8
+ lock; mov %cr0, %rcx
+ lock; mov %cr8, %rcx
+
.att_syntax noprefix
movq cr8, rax
movq cr8, rdi
@@ -11,6 +11,8 @@ Disassembly of section .text:
[ ]*[0-9a-f]+: 44 0f 20 c7[ ]+movq[ ]+?%cr8,%rdi
[ ]*[0-9a-f]+: 44 0f 22 c0[ ]+movq[ ]+?%rax,%cr8
[ ]*[0-9a-f]+: 44 0f 22 c7[ ]+movq[ ]+?%rdi,%cr8
+[ ]*[0-9a-f]+: f0 0f 20 c1[ ]+movq[ ]+%cr8,%rcx
+[ ]*[0-9a-f]+: f0 44 0f 20 c1[ ]+lock movq[ ]+%cr8,%rcx
[ ]*[0-9a-f]+: 44 0f 20 c0[ ]+movq[ ]+?%cr8,%rax
[ ]*[0-9a-f]+: 44 0f 20 c7[ ]+movq[ ]+?%cr8,%rdi
[ ]*[0-9a-f]+: 44 0f 22 c0[ ]+movq[ ]+?%rax,%cr8
@@ -13297,7 +13297,11 @@ OP_C (instr_info *ins, int dummy ATTRIBU
USED_REX (REX_R);
add = 8;
}
- else if (ins->address_mode != mode_64bit && (ins->prefixes & PREFIX_LOCK))
+ else if (/* Only %cr0 -> %cr8 is dealt with this way (and also really only on
+ most AMD hardware). */
+ ins->modrm.reg == 0
+ && (ins->prefixes & PREFIX_LOCK)
+ && ins->isa64 != intel64)
{
ins->all_prefixes[ins->last_lock_prefix] = 0;
ins->used_prefixes |= PREFIX_LOCK;
@@ -392,6 +392,7 @@ static bitfield cpu_flags[] =
BITFIELD (TBM),
BITFIELD (Movbe),
BITFIELD (CX16),
+ BITFIELD (AltMovCr8),
BITFIELD (LAHF_SAHF),
BITFIELD (EPT),
BITFIELD (Rdtscp),
@@ -135,6 +135,8 @@ enum i386_cpu
CpuMovbe,
/* CMPXCHG16B instruction support required. */
CpuCX16,
+ /* MOV to/from %cr8 instruction support required (in 32-bit mode). */
+ CpuAltMovCr8,
/* LAHF/SAHF instruction support required (in 64-bit mode). */
CpuLAHF_SAHF,
/* EPT Instructions required */
@@ -470,6 +472,7 @@ typedef union i386_cpu_flags
unsigned int cputbm:1;
unsigned int cpumovbe:1;
unsigned int cpucx16:1;
+ unsigned int cpualtmovcr8:1;
unsigned int cpulahf_sahf:1;
unsigned int cpuept:1;
unsigned int cpurdtscp:1;