是否可以消除这些冗余尾随零?

问题描述:

我正在写一些非常紧密的ASM代码。是否可以消除这些冗余尾随零?

注意此组NASM产生的操作码:

8AA4241C020000 mov ah,[esp+0x21c] 

而且类似:

051C020000 add eax,0x21c ; 4 extra 0's! 
8D84241C020000 lea eax,[esp+0x21c] ; Brutal! 

是否有你打算申请一个15位偏移到任何方式传达给处理器32位寄存器,并让它找出自己的0填充?

我一直在梳理https://c9x.me/x86/html/file_module_x86_id_176.html的一些指导。多余的2字节在这里或那里真的会拯救我的生命!

也接受:

替代的方式来重写语句来使其变小,最终什么,我在这种情况下会为是这样的:

mov eax,[esp+0x21c] 
push eax 

如果有手有办法编码,使其超小,我很想看到技术。

+0

在那里有一个LEA示例;) – baordog

+2

处理器手册告诉您什么是可用的。只有16位寄存器才支持16位偏移量。不确定你对手编码的含义。这不像你可以做些什么。 –

+0

您可以将寄存器的上半部分('xor ebx,ebx')清零,然后将您的16位值移入('mov bx,21c' - 注意:不要用'ebx')并根据需要使用('add eax, ebx')。 xor不是免费的,但是如果你多次使用这个技巧...... –

是否有任何方式与处理器通信,您打算将15位偏移量应用于32位寄存器,并让它找出自身的0填充?

号可用的指令编码在英特尔手册记录(在线版本,其中各种可用的地方在线;看到标签wiki链接)。对于MOV,偏移量大小与寄存器大小相匹配。当您将写入16位寄存器时,处理器仅使用16位偏移量。无法获得15位偏移量。

正如陈雷蒙德说,“它不喜欢你可以弥补[自己的自定义编码]”。

在某些模式下,某些指令有一个符号扩展位。

当然,但我不明白这对你有何帮助。你的目标是减小指令的大小:增加一个额外的16位操作数大小前缀为了改变偏移大小的解释不会帮助你做到这一点。

一般而言,如果存在到相当于原来的指令编码短的方式,汇编器将发射该编码为您服务。 当然 NASM会,其multi-pass optimization option(默认启用)。

这里额外的2个字节要么就真的救了我的生活!

这不是地方,你可以有效地节省之一。按照David Wohlferd的建议,如果你反复这样做,你可以通过预先清除一个寄存器(XOR reg, reg; 2个字节),使用这个寄存器作为reg寄存器的源寄存器来稍微压缩代码长度, (其中每个只有2个字节),然后将16位MOV写入那些已经清除高位16位的寄存器中。

当处理具有大量寄存器的ISA时,在特定过程的上下文中专用一个来包含0是比较常见的做法。许多ISA通过具有专用的零寄存器来进一步实现这一目标。你也可以用x86来做到这一点,但考虑到寄存器限制了ISA,它通常是一种悲观。但是,如果您的尺寸优化高于一切,它有时可能是有道理的。 (话又说回来,它可能不是,因为它可能会迫使你溢出到内存,并且将由至少 2个字节为每个存储和加载臃肿的代码。)

在现实中,我打赌有在你的代码中有很多其他的地方,在这些地方你正在花费大量的指令大小,并且可以实现更大幅度的减少。如果您希望仔细查看代码以减小尺寸,请考虑在Code Review上发布问题(当然,假设您有工作代码)。

我不确定在什么情况下你会写代码,节省2个字节会很重要。也许你正在写一个需要适合512字节的启动加载器?在这种情况下,大多数人所做的就是编写一个多级引导加载程序,其中第一级仅限于512字节,只是简单地称为第二级,在这里你没有这种限制。

如果会有些寄存器与调零上24位,则例如(对于EAX零),可以剃2个字节关:

; additional 2 bytes ruining the saving, if you don't have zero reg. 
; b0 87     mov al,0x87 

; 5 byte fetch of value 
b0 87     mov al,0x87 
8a 24 84    mov ah,BYTE PTR [esp+eax*4] 

或者,如果你知道你有一些低的值104 ..540(只有一些适合的),其他一些寄存器,可以通过降低它的偏移一点,例如假设你知道ebx == 104

8a 64 9c 7c    mov ah,BYTE PTR [esp+ebx*4+(0x21C-104*4)] 

如果这是真实尺寸的挑战,你必须发布整个代码,因为可能(并且通常它们是)疯狂的方式o以非常意想不到的和几乎难以想象的方式节省大小。