Search code examples
arraysassemblyx86nasm

Can't access array index in assembly x86


I'm trying to do in assembly the equivalent to:

const array = ["ola", "mundo"]

for (i = 0; i < array.length; i++){
  console.log(array[i])
}
global main

section .data
        newline db 0xa
        array db "ola","mundo"
        arrayLength equ $ - array

section .text

main:
        mov ecx, 0

beginLoop:
        cmp ecx, arrayLength
        je exit

        mov r8d, ecx
        push ecx

        mov eax, 4
        mov ebx, 1
        mov ecx, array+r8d
        mov edx, arrayLength
        int 0x80

        mov eax, 4
        mov ebx, 1
        mov ecx, newline
        mov edx, 1
        int 0x80

        pop ecx
        inc ecx
        jmp beginLoop

exit:
        mov eax, 1
        mov ebx, 0
        int 0x80

But when I compile it, it throws an error whenever I use the register r8d to access the index:

nasm -f elf64 -o array.o array.asm
array.asm:22: error: invalid operand type

The line 22 is mov ecx, array+r8d.


Solution

  • but when I compile it, it throws an error whenever I use the register r8d to access the index:

    NASM can't load the address via mov ecx, array+r8d because the r8d component is not an immediate value, it's a register whose value is only available at runtime. You could use LEA and write lea rcx, [array + r8]. Use the whole qword register in an addressing mode.

    array db "ola","mundo"
    

    There's no way for your program to know where one array element ends and where the next array element begins. All your program 'sees' is an 8-character string of characters "olamundo".
    One solution could be using zero-termination like in array db "ola", 0, "mundo", 0. Another solution could do with strings of equal size using a filler like in array db "ola ", "mundo ". And yet another solution could be prefixing the array elements with a byte that holds a length indication:

    array db 3, "ola", 5, "mundo"
    arrayLength equ $ - array
    

    A first draft:

    main:
      mov   rsi, array
      mov   ebx, 1
    .Loop:
      movzx edx, byte [rsi]  ; Load RDX with length byte
      inc   rsi              ; Make RSI point at current text string
      mov   rcx, rsi
      add   rsi, rdx         ; Now RSI points at next array element
      mov   eax, 4
      int   0x80
      mov   edx, 1
      mov   rcx, newline
      mov   eax, 4
      int   0x80
      cmp   rsi, array + arrayLength
      jb    .Loop