如何在汇编的 XOR 语句中指定 3 字节存储的大小?
How do you specify the size of a 3 Byte storage in XOR statement in Assembly?
在我的 Linux IA-32 处理器汇编程序中,我有两个存储空间。
inbuf: resb 3
outbuf: resb 4
inbuf
真的只需要 3 个字节,我不想浪费任何内存。现在,假设我想用这样的零覆盖它们:
xor [inbuf], inbuf
xor [outbuf], outbuf
nasm说我需要指定运算大小,可以理解。现在 outbuf
这没问题,因为我可以写
xor dword [outbuf], outbuf
相反,但显然,对于 3 字节的任意大小没有大小关键字。如何指定 inbuf
的大小?
我并不是真的在寻找用零覆盖存储的解决方案,我想还有其他方法也能正常工作,但这也可以解决我的问题,如何使用
mov eax, inbuf
没有收到 "size not specified" 错误。
Jester 的正确答案我会在评论中加上。
如果您坚持 "xor-ing" 内存(对于归零没有意义,但对于其他值可能值得),那么 "xor 3B [inbuf],3B [inbuf]" 可以在 x86 汇编中完成,如下所示:
mov eax,[inbuf] ; loads value from inbuf + 1B undef
xor [inbuf],ax ; word
shr eax,16 ; al = b16..b23 of value @inbuf
xor [inbuf+2],al ; byte
4B 双字变体:
mov eax,[outbuf]
xor [outbuf],eax
所有这些对于归零来说都是可怕的,对于归零来说这更好:
mov word [inbuf],0
mov byte [inbuf+2],0
mov dword [outbuf],0
或者最终,如果您在某些 32b 寄存器中已经为零:
xor eax,eax
mov [inbuf],ax
mov [inbuf+2],al
mov [outbuf],eax
在 32b 模式下,您只能访问 power-of-two 大小的内存,并且只能访问其中的一些内存:使用通用整数运算的 1、2 和 4。
FPU 为 8 或 10。哦,是的,10 不是 2 的幂,我知道,它只是一些 FP 东西的特殊值。
然后是各种SIMD指令,甚至可以访问128/256/512位(16,32和64字节)。
然后非算术特殊指令有时可以使用额外的额外大小,比如 5 或 6 可能(我什至不确定)和一些远跳等等......通常我不会把它们算作例外,因为整个 x86 指令解码都使用 variable-byte-amount 方法并且命名大小为 1B,所以这部分与 2 的幂无关。
无论如何,几乎没有人只在 Assembly 中使用 3 个字节,那是 "incorrect" 十六进制大小,会给用户带来很多不幸,你应该尽可能避免它。
有时人们会把它拉长,甚至由 RGB 数据组成的视频 ram 也是 32-bit-per-pixel 对齐的,每 4 个字节浪费一次 "nothing" 就像填充一样(浪费了 25% 的 VRAM 和回到过去,那时 RAM 昂贵)。
(早期的 SVGA VESA 模式也有 memory-efficient 24 位模式,但由于每个像素的寻址是 *3,在代码中使用非常烦人,甚至是硬件加速器......现在它有助于大部分视频内存用于纹理,其中第 4 个字节可以存储 alpha 或像素着色器的其他附加信息,因此不再浪费内存,但大小为 32 位)
以及如何从内存中加载 3B 值:
对于必须一直工作的通用 3B 负载:
movzx eax,byte [inbuf+2]
shl eax,16
mov ax,[inbuf]
并且当您知道 3B 值不在内存页末尾后跟受限内存页时(因此该值要么在按 4 对齐的地址上,要么在它之后总是有另一个合法内存页):
mov eax,[inbuf] ; loads desired 3B + 1B garbage
and eax,0x00FFFFFF ; truncate it to 3B only
(当下一个内存页面被限制时,这会在读取内存页面边界时崩溃,就像如果 "inbuf" 是地址 4093,地址 4096 被限制到这个进程 => 非法内存访问崩溃,但是这通常不是你定义 "inbuf" 的地方,所以这个较短的变体通常显示为正确的解决方案,没有这个愚蠢的长解释,当它实际上 可能 崩溃时)。 =16=]
在我的 Linux IA-32 处理器汇编程序中,我有两个存储空间。
inbuf: resb 3
outbuf: resb 4
inbuf
真的只需要 3 个字节,我不想浪费任何内存。现在,假设我想用这样的零覆盖它们:
xor [inbuf], inbuf
xor [outbuf], outbuf
nasm说我需要指定运算大小,可以理解。现在 outbuf
这没问题,因为我可以写
xor dword [outbuf], outbuf
相反,但显然,对于 3 字节的任意大小没有大小关键字。如何指定 inbuf
的大小?
我并不是真的在寻找用零覆盖存储的解决方案,我想还有其他方法也能正常工作,但这也可以解决我的问题,如何使用
mov eax, inbuf
没有收到 "size not specified" 错误。
Jester 的正确答案我会在评论中加上。
如果您坚持 "xor-ing" 内存(对于归零没有意义,但对于其他值可能值得),那么 "xor 3B [inbuf],3B [inbuf]" 可以在 x86 汇编中完成,如下所示:
mov eax,[inbuf] ; loads value from inbuf + 1B undef
xor [inbuf],ax ; word
shr eax,16 ; al = b16..b23 of value @inbuf
xor [inbuf+2],al ; byte
4B 双字变体:
mov eax,[outbuf]
xor [outbuf],eax
所有这些对于归零来说都是可怕的,对于归零来说这更好:
mov word [inbuf],0
mov byte [inbuf+2],0
mov dword [outbuf],0
或者最终,如果您在某些 32b 寄存器中已经为零:
xor eax,eax
mov [inbuf],ax
mov [inbuf+2],al
mov [outbuf],eax
在 32b 模式下,您只能访问 power-of-two 大小的内存,并且只能访问其中的一些内存:使用通用整数运算的 1、2 和 4。
FPU 为 8 或 10。哦,是的,10 不是 2 的幂,我知道,它只是一些 FP 东西的特殊值。
然后是各种SIMD指令,甚至可以访问128/256/512位(16,32和64字节)。
然后非算术特殊指令有时可以使用额外的额外大小,比如 5 或 6 可能(我什至不确定)和一些远跳等等......通常我不会把它们算作例外,因为整个 x86 指令解码都使用 variable-byte-amount 方法并且命名大小为 1B,所以这部分与 2 的幂无关。
无论如何,几乎没有人只在 Assembly 中使用 3 个字节,那是 "incorrect" 十六进制大小,会给用户带来很多不幸,你应该尽可能避免它。
有时人们会把它拉长,甚至由 RGB 数据组成的视频 ram 也是 32-bit-per-pixel 对齐的,每 4 个字节浪费一次 "nothing" 就像填充一样(浪费了 25% 的 VRAM 和回到过去,那时 RAM 昂贵)。
(早期的 SVGA VESA 模式也有 memory-efficient 24 位模式,但由于每个像素的寻址是 *3,在代码中使用非常烦人,甚至是硬件加速器......现在它有助于大部分视频内存用于纹理,其中第 4 个字节可以存储 alpha 或像素着色器的其他附加信息,因此不再浪费内存,但大小为 32 位)
以及如何从内存中加载 3B 值:
对于必须一直工作的通用 3B 负载:
movzx eax,byte [inbuf+2]
shl eax,16
mov ax,[inbuf]
并且当您知道 3B 值不在内存页末尾后跟受限内存页时(因此该值要么在按 4 对齐的地址上,要么在它之后总是有另一个合法内存页):
mov eax,[inbuf] ; loads desired 3B + 1B garbage
and eax,0x00FFFFFF ; truncate it to 3B only
(当下一个内存页面被限制时,这会在读取内存页面边界时崩溃,就像如果 "inbuf" 是地址 4093,地址 4096 被限制到这个进程 => 非法内存访问崩溃,但是这通常不是你定义 "inbuf" 的地方,所以这个较短的变体通常显示为正确的解决方案,没有这个愚蠢的长解释,当它实际上 可能 崩溃时)。 =16=]