Assembly 如何在汇编中的XOR语句中指定3字节存储的大小?

Assembly 如何在汇编中的XOR语句中指定3字节存储的大小?,assembly,x86,nasm,intel,Assembly,X86,Nasm,Intel,在我的IA-32处理器Linux汇编程序中,我得到了两个存储器 inbuf: resb 3 outbuf: resb 4 inbuf实际上只需要3个字节,我不想浪费任何内存。现在,假设我想用零覆盖它们,如下所示: xor [inbuf], inbuf xor [outbuf], outbuf mov eax,[inbuf] ; loads value from inbuf + 1B undef xor [inbuf],ax ; word shr eax,16 ;

在我的IA-32处理器Linux汇编程序中,我得到了两个存储器

inbuf: resb 3
outbuf: resb 4
inbuf
实际上只需要3个字节,我不想浪费任何内存。现在,假设我想用零覆盖它们,如下所示:

xor [inbuf], inbuf
xor [outbuf], outbuf
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
nasm说我需要指定操作大小,这是可以理解的。现在对于exputf来说,这没有问题,因为我会写

xor dword [outbuf], outbuf
相反,但显然,对于3字节的任意大小,没有大小关键字。如何指定
inbuf
的大小

我并不是真的在寻找一个用零覆盖存储的解决方案,我想还有其他的解决方案也可以,但这也解决了我的问题,比如如何使用

mov eax, inbuf

没有得到“未指定大小”错误。

我将在注释中添加Jester的正确答案

如果您坚持对内存进行“异或”,那么“异或3B[inbuf],3B[inbuf]”可以在x86汇编中执行,如下所示:

xor [inbuf], inbuf
xor [outbuf], outbuf
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 dword变体:

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模式下,您只能以两种大小的幂访问内存,并且只能访问其中的一些大小:1、2和4,使用通用整数运算

和8或10与FPU。哦,是的,10不是二的幂,我知道,它是特别的一个,只适用于一些事情

还有各种SIMD指令,它们甚至可以访问128/256/512位(16、32和64字节)

然后,非算术特殊指令有时可以使用额外的大小,比如5或6个可能(我甚至不确定)和一些跳远,等等。。。一般来说,我不会把它们算作例外,因为整个x86指令解码都使用可变字节量的方法,并且命名大小是1B,所以这部分不是关于2的幂

无论如何,几乎没有人只在汇编中使用3个字节,这是“不正确的”十六进制大小,给用户带来了很多不幸,您应该尽可能避免它

有时人们会将其扩展到如此之远,以至于即使是由RGB数据组成的视频ram也是32位/像素对齐的,每4个字节浪费一个“无”字,就像填充一样(25%的VRAM被浪费了,它回到了过去,当时ram的价格很贵)

(早期的SVGA VESA模式也有节省内存的24位模式,但由于每个像素的寻址是*3,因此在代码中使用非常烦人,甚至在硬件加速器中使用也非常烦人……如今,大多数视频ram用于纹理,其中第4字节可以存储像素着色器的alpha或其他附加信息,因此不再浪费内存,但大小为32位)


以及如何从内存中加载3B值:

对于必须始终工作的一般3B负载:

movzx eax,byte [inbuf+2]
shl   eax,16
mov   ax,[inbuf]
当您知道3B值不在内存页的末尾,后面是受限内存页(因此该值要么在地址上以4对齐,要么在它后面总是有另一个合法内存页):


(当下一个内存页被限制时,这将在读过内存页边界上崩溃,例如“inbuf”是地址4093,而地址4096被限制到此进程=>非法内存访问崩溃,但通常不会出现“inbuf”的情况。)定义,所以这个较短的变量通常显示为正确的解决方案,没有这个愚蠢的冗长解释,当它实际上可能崩溃时。)

我将在评论中补充Jester的正确答案

如果您坚持对内存进行“异或”,那么“异或3B[inbuf],3B[inbuf]”可以在x86汇编中执行,如下所示:

xor [inbuf], inbuf
xor [outbuf], outbuf
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 dword变体:

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模式下,您只能以两种大小的幂访问内存,并且只能访问其中的一些大小:1、2和4,使用通用整数运算

和8或10的FPU。哦,是的,10不是二的幂,我知道,它是特殊的一个只有一些FP的东西

还有各种SIMD指令,它们甚至可以访问128/256/512位(16、32和64字节)

然后非算术特殊指令有时会使用额外的大小,比如5或6(我甚至不确定)一般来说,我不会把它们算作例外,因为整个x86指令解码都使用可变字节量的方法,并且命名大小是1B,所以这部分不是关于二的幂

无论如何,几乎没有人只在汇编中使用3个字节,这是“不正确的”十六进制大小,给用户带来了很多不幸,您应该尽可能避免它

有时人们会将其扩展到如此之远,以至于即使是由RGB数据组成的视频ram也是32位/像素对齐的,每4个字节浪费一个“无”字,就像填充一样(25%的VRAM被浪费了,它回到了过去,当时ram的价格很贵)

(早期的SVGA VESA模式也有节省内存的24位模式,但由于每个像素的寻址是*3,因此在代码中使用非常烦人,甚至在硬件加速器中使用也非常烦人……如今,大多数视频ram用于纹理,其中第4字节可以存储像素着色器的alpha或其他附加信息,因此不再浪费内存,但大小为32位)


以及如何从内存中加载3B值:

对于必须始终工作的一般3B负载:

movzx eax,byte [inbuf+2]
shl   eax,16
mov   ax,[inbuf]
当您知道3B值不在内存页的末尾,后面是受限内存页(因此该值要么在地址上以4对齐,要么在它后面总是有另一个合法内存页):

(当下一个内存页受到限制时,这将在读过内存页边界上崩溃,如“inbuf”是地址4093,而