assemblyx86masmmasm32

Counting number of elements equal to 1 in DW array


I want to count the number of 1's in an array (using MASM32). In the first iteration I am getting some weird value in EAX. Instead of 00000000, I'm getting 00010000. Hence also getting an incorrect value in the counter ECX.

.386  
.model small  
.data  
var1 dw 0,1,1 
.code  
main PROC  
   LEA ESI, var1  
   MOV EBX, 3  
   MOV ECX, 0  
L1:CMP EBX, 0  
   JE L3  
   MOV EAX, [ESI]  
   CMP EAX, 0  
   JE L2  
   INC ECX  
L2:DEC EBX  
   ADD ESI, 2  
   JMP L1  
L3:INVOKE ExitProcess, 0  
main ENDP  
END main  

See this image, getting 00010000 in EAX instead of 00000000 as content at [ESI] is 0 at begining

See this image getting 00010000 in EAX instead of 0000000 as ESI content is 0 at begining


Solution

  • You defined var1 as word (16-bit) and not dword, but you are loading a dword (32-bit) because you load into eax which is a 32-bit-sized register, so you are getting the next word in memory (which is 1) in the upper half of your dword. See this example:

    x dw 1
    y dw 2
    z dw 3
    
    # resulting memory layout:
    # 01 00 02 00 03 00
    # \_x_/ \_y_/ \_z_/
    
    
    mov ax, [x] # you get 0001
    mov eax, [x] # you get 00020001 !! because you are reading x AND y
    movzx eax, word ptr [x] # you get 00000001
    
    # 01 00 02 00 03 00
    # \_x_/ \_y_/ \_z_/
    # \ax_/
    # \___eax___/
    
    
    mov ax, [y] # you get 0002
    mov eax, [y] # you get 00030002 !! because you are reading y AND z
    movzx eax, word ptr [y] # you get 00000002
    
    # 01 00 02 00 03 00
    # \_x_/ \_y_/ \_z_/
    #       \ax_/
    #       \___eax___/
    

    In your case, it's not another named variable but the second part of var1 (you have var1 dw 0,1,1 so you define three words with values 0000, 0001, 0001 - but the same thing applies here as with the example above).

    var1 dw 0,1,1
    
    # 00 00 01 00 01 00
    # \___/ \___/ \___/
    #  \var1 \     \var1+4
    #         \var1+2
    # \ax_/
    # \___eax___/
    

    So, either make your variable a dword using dd instead of dw (and then also increase esi by 4 instead of 2), or read a word by either storing it into a smaller register like ax or using movzx (or movsx if you need a signed value) with word ptr, which extends the value to fill the whole register.

    var1 dd 0,1,1
    
    # 00 00 00 00 01 00 00 00 01 00 00 00
    # \__var1___/ \_var1+4__/ \_var1+8__/
    # \___eax___/
    

    Note that if you decide to use ax, then remember that loading data into it won't modify the upper half of eax, it will keep its previous value, so you cannot write into ax and then read from eax, because you will again get unexpected things in the upper half. You'd then need to do cmp ax, 0 instead of cmp eax, 0 too. You need to be always aware of what exactly (and how much) you are reading or writing.