assemblyx86nasm

Why does [COLOR1 + ECX * 4] put me in a timeout 7


I want to make a program to pick a color in a list depending on a certain level. However, when i'm getting the value with MOV EAX, [COLOR1 + ECX * 4] I'm getting the error message:

Error: Command failed: timeout 7 ./HelloWorld

How can I make it work? I know this is causing the error because if I transform it into MOV EAX, [COLOR1] I don't get the error. I see people here on stackoverflow and elsewere doing [EAX+ECX*4] (I've tried it too). I also tried doing [COLOR1 + ECX], it didn't work but [COLOR1 + 1] Works. I can also seperate everything like this

IMUL ECX, 4
MOV EAX, [COLOR1]
ADD EAX, ECX

Which is I think the same?

For my code in itself, my objective is if LEVEL = 0, should get the first value in COLOR1 and COLOR2 (00223AD0h and 0040B2DFh) and LEVEL = 1 the next one and so on. Btw, I'm using OneCompiler.

SECTION .DATA 

   COLOR1 DD   00223AD0h, 00BF2A04h, 000BA109h, 00AF04AFh, 00CB0556h, 005E90DFh, 00BF2A04h, 007703D5h,
   COLOR2 DD   0040B2DFh, 00E1963Fh, 007CBD11h, 00D775D9h, 0058D590h, 0058D590h, 00707070h, 009E050Dh
   LEVEL DB 0  

section .text
   global _start


_start:


   MOV ECX, LEVEL
   CALL .LOOP
   
   MOV EAX, [COLOR1 + ECX * 4] ;Option I'm trying but doesn't work
   MOV [COLOR1CUR], EAX

   IMUL ECX, 4                 ;Option that kinda work but the result isn't what i want
   MOV EAX, [COLOR2]
   ADD EAX, ECX
   MOV [COLOR2CUR], EAX


   CALL .PRINT

   MOV EAX,1            ; The system call for exit (sys_exit)
   MOV EBX,0            ; Exit with return "code" of 0 (no error)
   INT 80h

.LOOP:

   SUB ECX, 10
   CMP ECX, 0
   JL SHORT .LOOP
   ADD ECX, 10

   RET

.PRINT:

   ;MOV EAX, COLOR1CUR
   ;CALL CONVERT_TO_STRING ; trying to make the color readable but that's next step so not on this post

   mov eax, 4            ; The system call for write (sys_write)
   mov ebx, 1            ; File descriptor 1 - standard output
   mov ecx, COLOR1CUR       
   mov edx, 16   
   int 80h
   
   RET

Solution

  • As worked out in comments: MOV ECX, LEVEL seems to be intended to load the value from LEVEL into ECX, like C ecx = level;. But what it actually does is to put the address of LEVEL into ECX, like ecx = &level;, without actually loading anything from memory at all.

    Memory accesses in NASM's Intel-syntax x86 assembly language use square brackets, as you're already doing elsewhere. But MOV ECX, [LEVEL] wouldn't be correct: since ECX is a 32-bit register, this would perform a 32-bit load which retrieves 4 bytes from memory. But you're only using one byte to store the level (you have LEVEL DB 0 rather than LEVEL DD 0), so the other three bytes would be whatever garbage happens to come next in memory. To load a narrower value into a wider register, you need to either zero-extend (MOVZX) or sign-extend (MOVSX) and specify the size of the object to be loaded. Presumably zero-extension is appropriate here, since it wouldn't ever make sense to interpret LEVEL as a negative number, so:

    MOVZX ECX, BYTE [LEVEL]