以下是代码:
.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO, dwExitCode:DWORD
.DATA
.code
Main proc
mov rax,0
mov rbx,0
mov rcx,0
mov rdx,0
mov al, 0F0H ;using 8-bit register
mov bx, 1012H ;using 16-bit register
mov ecx, 15284H ;using 32-bit register
mov rdx, 3578815H ;using 64-bit register
INVOKE ExitProcess, 0
main ENDP
END main
每当我运行这个时,它都会说:
未定义符号rax、rbx、rcx、rdx
但当我使用时它有效
.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO, dwExitCode:DWORD
.DATA
.code
Main proc
mov eax,0
mov ebx,0
mov ecx,0
mov edx,0
mov al, 0F0H ;using 8-bit register
mov bx, 1012H ;using 16-bit register
mov ecx, 15284H ;using 32-bit register
mov edx, 3578815H ;using 64-bit register
INVOKE ExitProcess, 0
main ENDP
END main
我使用的是x86配置。x64对我不起作用。有人能告诉我为什么RAX、RBX、RCX和RDX不起作用吗?
对于Visual Studio,64位构建将使用ML64.EXE而不是MASM.EXE。不要使用.386指令。ML64.EXE没有.model指令,因为64位调用约定是固定的。
您不能在32位代码中使用64位寄存器
在16位模式中,32位寄存器可用于前缀为66h
和67h
的机器代码。因此,16位和32位代码都可以使用类似movzx ax, byte ptr [ecx]
的指令(当然,假设代码运行在386或更新版本上,因此.model 386
会告诉汇编程序,它应该允许您编写这样的代码(。
但对于x86-64,在32位模式中没有一个未使用的字节可以用作前缀,因此AMD64架构师不得不采取不同的做法。x86-64的新功能仅在64位模式下可用,而不是在32位兼容模式下可用。
他们选择的实际机制是删除inc reg
和dec reg
的1字节编码,并将这些0x4?
字节重新用作REX前缀,包括一个用于区分add eax, ecx
和add rax, rcx
的Width位,以及3个用于寄存器号的额外位,从而允许访问r8-r15以获取add r8d, [r9 + r10]
等指令。
Ashttps://wiki.osdev.org/X86-64_Instruction_Encoding#REX_prefix说,REX前缀仅在长模式下可用
有趣的事实:如果您尝试在32位模式下使用CPU执行64位机器代码(例如,在源代码中使用NASMbits 64
并与nasm -fwin32
组合(,REX前缀将解码为inc
或dec
指令。
你可以玩一些有趣的把戏,比如制作机器代码,根据它在什么模式下执行,以3种不同的方式运行。例如,x86-32/x86-64多语言机器代码片段,它在运行时检测64位模式。此外,一个3向代码高尔夫答案显示了同一代码的3种不同的反汇编方式。