Reputation: 314
In my Linux Assembly program for IA-32 processors I got two storages.
inbuf: resb 3
outbuf: resb 4
inbuf
really only needs 3 bytes and I don't like to waste any memory. Now, let's say I want to overwrite them with zeros like this:
xor [inbuf], inbuf
xor [outbuf], outbuf
nasm says that I need to specify the operation size, which is understandable. Now for outbuf
this is no problem, because I can write
xor dword [outbuf], outbuf
instead, but apparently, there are no size keywords for arbitrary sizes as 3 byte. How can I specify the size of inbuf
?
I am not really looking for a solution to overwrite a storage with zeros and I guess there are other ones that work just as well, but this would also solve my problem how to use something like
mov eax, inbuf
without getting a "size not specified" error.
Upvotes: 1
Views: 352
Reputation: 16586
I will add over Jester's correct answer in comments.
If you would insist on "xor-ing" the memory (doesn't make sense for zeroing, but may be worth for other values), then "xor 3B [inbuf],3B [inbuf]" can be done in x86 assembly like this:
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
The 4B dword variant:
mov eax,[outbuf]
xor [outbuf],eax
And all of that is horrible for zeroing, for zeroing this is better:
mov word [inbuf],0
mov byte [inbuf+2],0
mov dword [outbuf],0
Or eventually, if you have already zero in some 32b register:
xor eax,eax
mov [inbuf],ax
mov [inbuf+2],al
mov [outbuf],eax
You can access memory only for power-of-two sizes, and only for some of them, in 32b mode: 1, 2 and 4 with general purpose integer arithmetic.
And 8 or 10 with FPU. Oh yeah, 10 is not power of two, I know, it's special one only for some FP things.
And then there're various SIMD instructions, which can access even 128/256/512 bits (16,32 and 64 bytes).
Then non arithmetic special instructions can sometimes use additional extra sizes, like 5 or 6 maybe (I'm not even sure) with some far jumping, etc... Generally I wouldn't count them even as exception, as the whole x86 instruction decoding is using variable-byte-amount approach and the denominating size is 1B, so it's not about powers of two in that part.
Anyway, almost nobody works with 3 bytes only in Assembly, that's "incorrect" hexed size and bring lot of misfortune upon user, you should avoid it whenever possible.
Sometimes people stretch it so far, that even video ram consisting of RGB data is 32-bit-per-pixel aligned, wasting every 4th byte for "nothing" only like padding (25% of VRAM wasted and it was back in time, when RAM was expensive).
(Early the SVGA VESA modes did have also memory-efficient 24bit modes, but as the addressing per pixel is *3, it was very annoying to use in code, or even by HW accelerators ... nowadays it helps that most of the video ram usage is for textures, where 4th byte can store alpha or other additional information for pixel shader, so it's no more wasted memory, yet the size is 32 bit)
And how to load 3B value from memory:
For generic 3B load which must work all the time:
movzx eax,byte [inbuf+2]
shl eax,16
mov ax,[inbuf]
And when you know that 3B value is not at end of memory page followed by restricted memory page (so the value is either on address aligned by 4, or there's always another legal memory page after it):
mov eax,[inbuf] ; loads desired 3B + 1B garbage
and eax,0x00FFFFFF ; truncate it to 3B only
(this would crash on the read over memory page boundary when next memory page is restricted, like if "inbuf" is address 4093, and address 4096 is restricted to this process => illegal memory access crash, but that's usually not where you would have "inbuf" defined, so this shorter variant is usually shown as the correct solution, without this stupidly long explanation, when it actually may crash).
Upvotes: 6