Ryzen supports the monitorx
instructions, as indicated by the cpuid flag. Unfortunately the visual studio masm assembler doesn't seem to like these instructions, and there is very little documentation online for how to use them.
The following code (which is very based on AMD's own documentation) reports the error A2070 "invalid instruction operands:
push rbx
mov eax, 5844h
mov ecx, 0
mov edx, 0
monitorx eax, ecx, edx
pop rbx
ret
I understand that this code isn't very useful, but it shouldn't be throwing build time errors, so what's the deal?
CodePudding user response:
The problem is that eax, ecx, and edx are 32 bit registers, but it was being assembled in 64 bit mode. Because the first operand is pointer size, it must be 64 bits. The following code will work on 64 bit programs:
push rbx
mov eax, 5844h
mov ecx, 0
mov edx, 0
monitorx rax, rcx, rdx
pop rbx
ret
CodePudding user response:
In machine code, the operands are implicit. In assembly syntax, plain monitorx
works for most assemblers. The operands can be specified to document the instruction, or in some assemblers to specify an override to the address-size.
AMD's manual explicitly says that ECX and EDX are 32-bit operands. (They say there are no hints or extensions defined, so ECX must be 0 else #GP, and EDX is ignored by current CPUs.)
For the address operand, they document it as rAX, which I think means it can be EAX or RAX. In the pseudocode example, they use MONITORX EAX, ECX, EDX
, but the 32-bit EAX means that's a 32-bit-mode example.
This is in their vol.3 manual, Nov. 2021 rev 3.33, the latest linked from https://developer.amd.com/resources/developer-guides-manuals/.
NASM 2.15.05 (support added for monitorx
in version 2.12.01)
The operand list can be specified or omitted. If specified, the first operand must be EAX or RAX, and the next two must be ECX and EDX. (It's an error to specify RCX or RDX).
But NASM doesn't infer 32-bit address-size in 64-bit mode from using EAX.
Segment overrides can be specified with NASM prefixes.
Example listing from nasm -l/dev/stdout -felf64 foo.asm
:
1 00000000 0F01FA monitorx
2 00000003 0F01FA monitorx rax, ecx, edx
3 00000006 0F01FA monitorx eax, ecx, edx ; address-size override not inferred from EAX
4 00000009 670F01FA a32 monitorx ; address-size prefix, NASM style
5 0000000D 640F01FA fs monitorx rax, ecx, edx ; segment override works, too
ndisasm -b64
disassembles it as just monitorx
, fs monitorx
, or a32 monitorx
without listing the implicit operands. GNU Binutils objdump
is the same in -Mintel
syntax mode, but lists operands in AT&T mode. (Backwards, with %rax
or