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

Your First Assembly Program

A hands-on walkthrough of writing, assembling, linking, and running a minimal x86-64 Linux assembly program from scratch.

FoundationsBeginner10 min readJul 10, 2026
Analogies

Your First Assembly Program

The traditional first program in any language prints a greeting and exits, and assembly is no exception — but writing it forces you to confront details a high-level language normally hides entirely, such as exactly how a program talks to the operating system. On Linux x86-64, a program requests OS services through system calls: placing a syscall number in RAX, arguments in RDI, RSI, RDX (and further registers as needed), then executing the syscall instruction, which transfers control to the kernel and returns with a result in RAX. Printing text requires the write syscall (number 1), which needs a file descriptor (1 for standard output) in RDI, a pointer to the bytes to print in RSI, and the byte count in RDX; exiting cleanly requires the exit syscall (number 60), which needs only an exit code in RDI. There is no print() function to call — you are directly issuing the same low-level request that every print statement in every higher-level language eventually boils down to.

🏏

Cricket analogy: A syscall is like a fielder radioing the umpire directly with a specific coded request ('DRS review, code 3') rather than going through a translator — you specify exactly the request number and details, and the umpire (kernel) handles it.

Anatomy of the Program

A minimal NASM program is organized into sections that tell the assembler and linker how to lay out the final binary. The .data section holds initialized values known at assembly time — a string like msg db 'Hello, Assembly!', 10 stores the literal bytes of the message plus a trailing newline (byte value 10), and equ msg_len, $ - msg computes the string's length automatically by subtracting the label's address from the current position ($). The .text section holds actual instructions, and by Linux convention the label _start marks the program's true entry point — not main, which is a C runtime convention; the linker needs global _start so this symbol is visible outside the file and can be used as the entry point when producing the executable. Every instruction in .text executes strictly in order unless a jump, call, or syscall return redirects control, which is why the exit syscall must appear as literally the last thing the program does — without it, execution would fall off the end of _start into whatever bytes happen to follow in memory, causing a crash.

🏏

Cricket analogy: The .data section is like the pre-match team sheet listing fixed facts (playing XI, toss result) decided before a ball is bowled, while .text is the live over-by-over action — data is prepared upfront, code executes step by step afterward.

Assembling, Linking, and Running It

Producing a runnable program from the source requires the two-stage toolchain covered elsewhere in this course: nasm -f elf64 hello.asm -o hello.o assembles the source into an ELF object file, encoding each mnemonic into its machine-code bytes and recording the _start symbol so it's visible to the linker; ld hello.o -o hello then links that single object file into a final executable, since this minimal program makes no external library calls and therefore has no unresolved symbols to worry about. Running ./hello executes the binary directly — the Linux kernel's ELF loader maps the file's sections into a fresh process's address space, sets RIP to the _start label's address, and execution begins exactly where you wrote it to begin. Checking echo $? immediately afterward reveals the process's exit code, which is precisely the value you placed in RDI right before the exit syscall — a concrete, observable confirmation that the assembly you wrote is genuinely controlling the CPU end to end, with no runtime or interpreter standing between your instructions and the hardware.

🏏

Cricket analogy: Assembling then linking a single file is like a solo net session that needs no team coordination — no other players' schedules to sync, unlike a full XI's linked training plan, because this program has zero external dependencies.

asm
; hello.asm - a minimal x86-64 Linux assembly program (NASM syntax)
section .data
    msg     db  'Hello, Assembly!', 10   ; the string bytes plus newline (10 = '\n')
    msg_len equ $ - msg                   ; length computed automatically

section .text
    global  _start                        ; entry point visible to the linker

_start:
    ; write(1, msg, msg_len)
    mov     rax, 1          ; syscall number 1 = write
    mov     rdi, 1          ; file descriptor 1 = stdout
    mov     rsi, msg        ; pointer to the bytes to print
    mov     rdx, msg_len    ; number of bytes to print
    syscall

    ; exit(0)
    mov     rax, 60         ; syscall number 60 = exit
    mov     rdi, 0          ; exit code 0 = success
    syscall

Build and run it with: nasm -f elf64 hello.asm -o hello.o && ld hello.o -o hello && ./hello && echo $? — you should see 'Hello, Assembly!' printed followed by an exit code of 0.

  • On Linux x86-64, programs request OS services via syscalls: number in RAX, arguments in RDI/RSI/RDX, triggered by the syscall instruction.
  • The write syscall (1) needs a file descriptor, buffer pointer, and byte count; exit (60) needs only an exit code.
  • The .data section holds initialized values known at assembly time; equ can compute derived constants like string length automatically.
  • The .text section holds instructions; _start (not main) is the true Linux entry point and must be declared global.
  • Execution must end with an explicit exit syscall, or the CPU will run past _start into undefined memory and crash.
  • nasm -f elf64 assembles the source; ld links the resulting object file into a runnable executable.
  • echo $? after running the program reveals the exact exit code placed in RDI before the exit syscall.

Practice what you learned

Was this page helpful?

Topics covered

#Programming#AssemblyLanguageStudyNotes#YourFirstAssemblyProgram#Assembly#Program#Anatomy#Assembling#StudyNotes#SkillVeris#ExamPrep