1

我正在编写一些非常严格的 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 

如果有一种方法可以手动编码以使其超级小,我很乐意看到这种技术。

4

2 回答 2

0

如果您有一些高 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)]

如果这将是真正的尺寸挑战,您必须发布整个代码,因为可能有(而且经常是)疯狂的方法来以非常意想不到和几乎无法想象的方式来节省尺寸。

于 2017-05-29T14:06:28.937 回答
0

有没有办法与处理器通信,您打算将 15 位偏移量应用于 32 位寄存器,并让它自己找出 0 填充?

否。英特尔手册中记录了可用的指令编码(其在线版本可在网上的各个地方获得;请参阅标签 wiki 中的链接)。对于MOV,偏移量大小与寄存器大小相匹配。MOV当您进入 16 位寄存器时,处理器仅使用 16 位偏移量。没有办法获得 15 位偏移量。

正如 Raymond Chen 所说,“这不像你可以随便编造 [你自己的自定义编码]”。

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

当然可以,但我不明白这对你有什么帮助。您的目标是减少指令的大小:添加一个额外的 16 位操作数大小前缀以更改对偏移大小的解释不会帮助您做到这一点。

一般来说,如果有一种更短的方法来对与原始指令等效的指令进行编码,那么汇编程序将为您发出该编码。当然NASM 会使用它的多通道优化选项(默认启用)。

这里或那里额外的 2 个字节真的会救我的命!

这不是您可以有效保存的地方之一。

正如 David Wohlferd 已经建议的那样,如果您重复执行此操作,您可以通过预先清除寄存器(XOR reg, reg; 2 个字节)来稍微压缩代码大小,将其用作 reg-regMOV的源寄存器(它们是每个只有 2 个字节),然后MOV对那些已经清除了高 16 位的寄存器执行 16 位 s。

在处理具有大量寄存器的 ISA 时,在特定过程的上下文中将一个专用于包含 0 是相对常见的做法。许多 ISA 通过使用专用的零寄存器更进一步。您也可以使用 x86 执行此操作,但考虑到 ISA 的寄存器限制程度,这通常是一种悲观。但是,如果您将优化大小放在首位,那么有时可能会有意义。(再一次,它可能不会,因为它可能会迫使您溢出到内存,并且每次存储和加载都会使代码膨胀至少2 个字节。)

实际上,我敢打赌,在您的代码中还有很多其他地方,您会在指令大小方面挥霍无度,并且可以实现更显着的减少。如果您想审查代码并着眼于减小其大小,请考虑在Code Review上发布一个问题(当然,假设您有工作代码)。

我不确定在什么情况下你会编写代码,节省 2 个字节会很重要。也许您正在编写一个需要容纳在 512 字节以内的引导加载程序?在这种情况下,大多数人所做的是编写一个多阶段引导加载程序,其中第一阶段,即仅限于 512 字节的阶段,只需调用第二阶段,而您没有此类限制。

于 2017-05-29T09:36:56.773 回答