在我的IA-32处理器Linux程序集中,我有两个存储空间.
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
没有得到"未指定大小"错误.
我将在评论中添加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模式下,您只能为两种大小的内存访问内存,并且只能访问其中一些内存:1,2和4使用通用整数运算.
和FPU 8或10.哦,是的,10不是两个的力量,我知道,这是一个特殊的只有一些FP的东西.
然后有各种SIMD指令,甚至可以访问128/256/512位(16,32和64字节).
那么非算术特殊指令有时可以使用额外的额外大小,比如5或6可能(我甚至不确定)有一些远跳等等...通常我不会将它们算作异常,因为整个x86指令解码使用可变字节数量方法,并且命名大小为1B,因此它不是关于该部分中的2的幂.
无论如何,几乎没有人只在Assembly中使用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,或者在它之后总是有另一个合法的内存页面):
mov eax,[inbuf] ; loads desired 3B + 1B garbage and eax,0x00FFFFFF ; truncate it to 3B only
(当下一个内存页面被限制时,这会在读取内存页面边界时崩溃,例如"inbuf"是地址4093,而地址4096仅限于此进程=>非法内存访问崩溃,但这通常不是你想要的地方"inbuf"定义了,所以这个较短的变体通常显示为正确的解决方案,没有这个愚蠢的长解释,当它实际上可能崩溃时).