该问题源自笔者在阅读《汇编语言——基于x86处理器》(基普·R.欧文 著 吴为民 译)(以下简称x86)一书时原作者提到的一个问题,也即在64位模式下处理32位立即数时存在的扩展模式不同的问题。
本文使用的是原书第8版的译本,对应页码以此书为准。
在该书第161页6.1.10 64位模式下的布尔指令,作者给出了如下一段程序
.data
allones QWORD 0FFFFFFFFFFFFFFFFh
.code
mov rax, allones ; RAX = FFFFFFFFFFFFFFFFh
and rax, 80h ; RAX = 0000000000000080h
mov rax, allones ; RAX = FFFFFFFFFFFFFFFFh
and rax, 8080h ; RAX = 0000000000008080h
mov rax allones ; RAX = FFFFFFFFFFFFFFFFh
and rax, 808080h ; RAX = 0000000000808080h
mov rax allones ; RAX = FFFFFFFFFFFFFFFFh
and rax, 80808080h ; RAX = FFFFFFFF80808080h
可以看到,此处作者对32位进行and运算时,没有默认将高位看作全0,而是只对低32位进行了运算。当源操作数为32位以下的立即数时,通过0扩展将其扩充为32位。
奇怪的现象还出现在105页4.6.1 MOV指令,作者给出一系列程序
mov rax, 0ABCDEF0AFFFFFFFFh
mov rax, 0FFFFFFFFh ; RAX = 00000000FFFFFFFFh
mov rax, 06666h ; RAX = 0000000000006666h
mov rax, 055h ; RAX = 0000000000000055h
.data
myDword DWORD 80000000h
.code
mov rax, 0FFFFFFFFFFFFFFFFh
mov eax, myDword
.data
myByte BYTE 55h
myWord WORD 6666h
.code
mov ax, myWord ; RAX = 0ABCDEF0AFFFF6666h
mov al, myByte ; RAX = 0ABCDEF0AFFFFFF55h
可以看到,mov操作和and操作对不同长度的立即数处理策略是不一致的。尤其以32位为甚。
可以看到,上述提到的指令在处理立即数时反应并不一致,当and指令处理立即数时,存在32位以下和32位两种不同的情况,当mov指令处理立即数时,对立即数均进行0扩展。
当执行mov指令时,如果源操作数为立即数,而目的操作数为寄存器时,会首先进行size比较,如果立即数的size比目的寄存器的size大,汇编将不通过。可以尝试下面的指令:
mov eax, 1FFFFFFFFh
当立即数的size比目的寄存器的size小时,会将立即数扩展到与目的寄存器尺寸一致,此时为了保证扩展是安全的,自然会使用零扩展。且未使用的地址默认为0也符合我们的常识。
同时,由于进行了size对齐,对64位寄存器也支持超过32位的立即数,可以通过下列指令看出:
mov rax, 1FFFFFFFFh
上述指令是可以通过汇编且正确执行的。
此处虽然只举出了and指令的例子,但并不仅限于and指令,背后突出的是一系列的算数运算指令。
当and指令处理上述立即数时,就会遇到无法扩展的情况——当and指令的源操作数大小超过32位时,汇编过程不通过,会报错constant value too large。也即上述mov指令对应的and版本无法通过汇编:
and rax, 1FFFFFFFFh
这就很有趣了,对超过32位的立即数无法进行扩展,甚至会导致汇编无法通过。
如果问题在于x64的汇编要求的立即数最大为32位,所以当立即数超过32位时,就会报错 constant value too large. 同样的当立即数小于32位时需要将其扩展为64位之后再进行计算。而当立即数达到32位时,无需进行扩展直接和目的操作数的低32位进行计算,因此会出现上述奇怪的现象,且该立即数长度限制对mov指令无效。
但是为什么x64的汇编要求最大32位呢?为什么小于32位的立即数会默认扩展为64位呢?
找到了x86书中推荐的intel官网的资料,其中有一部分与该文件相关的表述:
可以看到,上述提及immediate operands(立即数操作数时规定了立即数的范围不能超过2^32,也即DWORD范围。
这篇文章提到了一些关于x64汇编的相关操作,但我并未看懂。尝试搜索报错信息时找到了一些相关的问答资料,分别贴在下面供参考。
资料1https://stackoverflow.com/questions/69916226/very-beginners-question-constant-value-too-large
资料2 https://masm32.com/board/index.php?topic=6434.0