100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

Arrays in Assembly

How fixed-size, contiguous arrays are declared, laid out in memory, and indexed using scaled addressing in x86-64 assembly.

Memory & AddressingIntermediate9 min readJul 10, 2026
Analogies

Arrays in Assembly

An array in assembly is nothing more than a contiguous block of memory holding elements of the same size, one after another, with no metadata attached. Unlike a high-level language, there is no built-in bounds checking or length field; the programmer must track the element count and element size separately and compute every address by hand.

🏏

Cricket analogy: Think of a cricket scoreboard showing every over's runs in a single row of boxes: the scorer knows each box is exactly one over wide, so finding over 37 means walking 37 boxes from the start, exactly like an assembly array has no labels, just fixed-width slots.

Declaring and Laying Out Arrays

In NASM, a fixed array of doublewords is declared in the .data section with the dd directive followed by comma-separated values, or with times to reserve uninitialized space, such as buf: resd 100 in .bss. The assembler simply lays these values end to end; the label buf refers to the address of the very first element, and every subsequent element sits at buf + 4*i because each dd entry occupies four bytes.

🏏

Cricket analogy: Declaring an array with dd 1,2,3,4,5 is like a team manager writing a fixed batting order on a card before the toss: once written, the fifth name is always four slots after the first, just as buf+16 always reaches the fifth doubleword.

nasm
section .data
    arr:    dd 10, 20, 30, 40, 50   ; five doublewords, 4 bytes each
    count   equ 5

section .bss
    buf:    resd 100                ; 100 uninitialized doublewords

section .text
global _start
_start:
    xor     rcx, rcx        ; i = 0
    xor     eax, eax        ; sum = 0
.loop:
    cmp     rcx, count
    jge     .done
    mov     edx, [arr + rcx*4]   ; scaled addressing: arr + i*4
    add     eax, edx
    inc     rcx
    jmp     .loop
.done:
    mov     [buf], eax      ; store sum into buf[0]
    mov     eax, 60
    xor     edi, edi
    syscall

Indexing with Scaled Addressing

x86-64 supports base+index*scale+displacement addressing directly in a single instruction, so [arr + rcx*4] computes arr + rcx*4 in hardware without a separate multiply. The scale factor must match the element size — 1, 2, 4, or 8 bytes — so a byte array uses *1, a word array *2, a doubleword array *4, and a quadword array *8. Getting the scale wrong silently reads the wrong element rather than crashing.

🏏

Cricket analogy: A commentator predicting the score at over 12 by multiplying overs by the average run rate is doing the same single-step scaling that [arr + rcx*4] performs — one multiply-and-add, no separate steps.

On x86-64, the scale field in the ModRM/SIB byte only encodes 1, 2, 4, or 8 — there is no hardware support for scale-by-3 or scale-by-12 for oddly sized structs. For those, compute the offset with an explicit imul before adding it to the base address.

Multi-Dimensional Arrays and Row-Major Layout

A 2D array declared as rows of columns is stored in row-major order: row 0's elements come first, then row 1's, and so on. The address of element [i][j] in an array with COLS columns of 4-byte elements is base + (i*COLS + j)*4. This means i must be scaled by the full row width before j is added, so the compiler or hand-written code typically computes i*COLS with an imul first, then adds j and applies the final *4 scale.

🏏

Cricket analogy: A Test match scorecard laid out as one long list of every ball bowled in over order, rather than a grid, means finding over 5 ball 3 requires computing 5*6+3 balls from the start — exactly like row-major indexing.

Row-major and column-major layouts are not interchangeable. Code written assuming row-major (C, most assembly examples) will silently read the wrong elements if the data was actually produced in column-major order (as in Fortran), because the same (i,j) pair maps to a different byte offset in each convention.

  • An assembly array is just a contiguous, unlabeled block of same-sized elements; the programmer tracks count and element size manually.
  • NASM declares initialized arrays with dd/dw/db and comma-separated values, and reserves uninitialized space with resd/resw/resb in .bss.
  • x86-64's base+index*scale+displacement addressing mode computes arr + i*scale in one instruction, with scale restricted to 1, 2, 4, or 8.
  • Using the wrong scale factor for the element size does not crash — it silently reads or writes the wrong element.
  • 2D arrays are typically stored row-major, so element [i][j] is at base + (i*COLS + j)*elemSize, requiring an explicit multiply for the row term.
  • There is no automatic bounds checking; reading or writing past the declared array length corrupts adjacent memory without any warning.

Practice what you learned

Was this page helpful?

Topics covered

#Programming#AssemblyLanguageStudyNotes#ArraysInAssembly#Arrays#Assembly#Declaring#Laying#DataStructures#StudyNotes#SkillVeris