DEV Community

Cover image for How to Say "Hello World" in x86 Assembly
Sk
Sk

Posted on

How to Say "Hello World" in x86 Assembly

Because why not? Software is fun.

I know this sounds insane; assembly for fun—but trust me, you feel alive.

I’m lucky to be at a point where I can build almost anything, so I’m testing the waters for a low-level series combining Node.js and assembly as a shared library.

In this article, we’re saying hello to the world in x86 Linux assembly.


Hello in Assembly

You need a Linux environment. On Windows, you can use WSL2.

Create a file called hello.s and add the following code:

.section  .data
msg:
    .asciz "Hello, World!\n"   # Define a null-terminated string with a newline
msg_len = . - msg              # Length from current location to msg

.section .text
.globl _start              # Declare _start as a global symbol (entry point)
_start:
    # --- sys_write(int fd, const void *buf, size_t count) ---
    movl $4, %eax              # sys_write into %eax
    movl $1, %ebx              # fd stdout into %ebx
    movl $msg, %ecx            # msg address
    movl $msg_len, %edx        # msg length
    int $0x80                  # Trigger the kernel system call

    # --- sys_exit(int status) ---
    movl $1, %eax              # sys_exit into %eax
    xorl %ebx, %ebx            # Zero out %ebx (exit code 0)
    int $0x80                  # Kernel call
Enter fullscreen mode Exit fullscreen mode

Compile the program using as. Installing it on Linux is simple—just install the GNU tools with:

sudo apt update && sudo apt install -y build-essential gdb libgtk-3-dev
Enter fullscreen mode Exit fullscreen mode

Then compile your assembly file:

as ./hello.s -o hello.o
Enter fullscreen mode Exit fullscreen mode

This command creates the object file. Next, link it:

ld ./hello.o -o hello
Enter fullscreen mode Exit fullscreen mode

Finally, run your program:

./hello
Enter fullscreen mode Exit fullscreen mode

This might be the most complex "Hello World" you’ve ever seen, especially if you’re new to assembly.

Let’s break it down.


Sections in Assembly

Assembly programs are divided into sections:

  • .section .data → Where we store data, like "Hello, World!"
  • .section .text → Where we write instructions
  • .globl _start → Defines the program’s entry point

Symbols and Labels

Symbols are names for memory locations.

For example, msg is a symbol. It tells assembly, "Hey, remember this location—we’ll use it later." It’s like a variable.

When you add a :, it becomes a label, defining the value of a symbol.

msg:
    .asciz "Hello, World!\n"  
Enter fullscreen mode Exit fullscreen mode

This means: "At memory location msg, store the string 'Hello, World!\n'."

This pattern is everywhere. _start is also a label:

.globl _start  
_start:
Enter fullscreen mode Exit fullscreen mode

Making _start global lets the assembler and linker find it.


Keeping Track of Memory

Assembly doesn’t track memory for you—you have to do it manually.

msg_len = . - msg

What’s happening here?

msg is just an address. It points to the start of "Hello, World!\n", but it doesn’t know where it ends.

. is the current memory location—right after the string.

So, msg_len = . - msg means:

Take the address after "Hello, World!\n" and subtract the start address.

That gives us the string’s length, which we need for the sys_write call.


CPU Architecture

CPU

Registers store data temporarily and operate way faster than RAM.

In our program, %eax is a register.

General-purpose registers:

  • %eax
  • %ebx
  • %ecx
  • %edx
  • %edi
  • %esi

Special-purpose registers:

  • %ebp
  • %esp
  • %eip
  • %eflags

Here’s how we move data between registers:

movl $4, %eax    # sys_write into %eax
movl $1, %ebx    # fd stdout into %ebx
movl $msg, %ecx  # msg address
movl $msg_len, %edx  # msg length
int $0x80        # Trigger the kernel system call
Enter fullscreen mode Exit fullscreen mode

But before we can execute anything, we need to talk about...


The Kernel

The kernel is the middleman between your program and hardware. Every system call (file access, memory allocation, exiting a program) goes through the kernel.

Whenever you see this:

int $0x80  # Kernel call
Enter fullscreen mode Exit fullscreen mode

You’re asking the kernel for help.

But the kernel has rules. Before calling it, you must set up registers with the correct values.

For example, to exit a program, the kernel expects:

movl $1, %eax  # sys_exit command
movl $0, %ebx  # Exit status
Enter fullscreen mode Exit fullscreen mode

The sys_exit call expects:

  • %eax = 1 → "I want to exit."
  • %ebx = 0 → "Exited successfully."

It’s the same as returning 0 in C:

int main() {
    return 0;  // Exit status 0 (success)
}
Enter fullscreen mode Exit fullscreen mode

Writing to the Console

Unlike sys_exit, writing to the console requires more information:

movl $4, %eax    # sys_write command
movl $1, %ebx    # File descriptor 1 (stdout)
movl $msg, %ecx  # Message address
movl $msg_len, %edx  # Message length
int $0x80        # Kernel call
Enter fullscreen mode Exit fullscreen mode

Here’s what’s happening:

  1. movl $4, %eax → The number 4 tells the kernel, "I want to write."
  2. movl $1, %ebx → The number 1 means "write to stdout."
  3. movl $msg, %ecx → Where’s the message? It’s at msg.
  4. movl $msg_len, %edx → How long is the message? That’s in msg_len.
  5. int $0x80 → Call the kernel to execute the write.

Once we’ve written our message, we exit:

movl $1, %eax  # sys_exit
xorl %ebx, %ebx  # Exit code 0
int $0x80  # Kernel call
Enter fullscreen mode Exit fullscreen mode

AT&T vs. Intel Syntax

This program uses AT&T syntax, which is common in GNU assemblers.

Intel syntax, used in NASM, looks slightly different. A major difference is that AT&T syntax prefixes registers with %.

Some people prefer Intel syntax, but most books stick with AT&T, so it’s worth learning.


You Made It!

That’s it! You just wrote and understood x86 assembly’s "Hello, World!"

I might start a low-level Node.js series soon. Let me know if that sounds interesting!

You can find me on x

Meanwhile, check out this series where we build a Node-native message broker from scratch:

Here's what you'll learn:

  • Long live TCP with heartbeat functionality
  • Buffers
  • Queue management: acknowledgments and cleanup
  • A client driver based on events and event queues
  • Pub/Sub
  • BSON serialization and deserialization for durable queues
  • Handshake and authentication 🚀

Top comments (20)

Collapse
 
pxlmastrxd profile image
Caleb (pxlmastr)
#include <iostream>

int main() {
    std::cout << "To be honest, I'd rather stick to something normal :D";
    return 0;
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
sfundomhlungu profile image
Sk

#include <stdio.h>

int main() {
    printf("I agree! but this is normal 😂 :D\n");
    return 0;
}

Enter fullscreen mode Exit fullscreen mode
Collapse
 
komsenapati profile image
K Om Senapati
print("Weirdos")
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
pxlmastrxd profile image
Caleb (pxlmastr)
class Test
{
    public static void main(String[] args)
    {
        System.out.println("No, we are the same when we bond against java people");
    }
}
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
perisicnikola37 profile image
Nikola Perišić
print("Good post! 9.67 score on dev-to-rater.xyz")
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
sfundomhlungu profile image
Sk
import IO, only: [puts: 1]

puts("Uhmmm lol 😂😭") 
Enter fullscreen mode Exit fullscreen mode
Collapse
 
ezek-iel profile image
Ezekiel • Edited

I'll just

gcc -s main.cpp
Enter fullscreen mode Exit fullscreen mode


`
that thanks.

Collapse
 
schemetastic profile image
Schemetastic (Rodrigo)
console.log("I think I'll stay with the good 'ol JS haha, but cool post 😉")
Enter fullscreen mode Exit fullscreen mode
Collapse
 
teminian profile image
Robert Teminian

Let me join. lol

Program HelloPascal;
begin
    writeln('Please don''t forget here''s Pascal.');
end.
Enter fullscreen mode Exit fullscreen mode
Collapse
 
skhmt profile image
Mike 🐈‍⬛ • Edited
Collapse
 
sfundomhlungu profile image
Sk

😭😭😂 solved!!

Collapse
 
benny00100 profile image
Benny Schuetz

Great to see assembly again. I used to code in assembly on the Amiga in the good old days.

Collapse
 
sfundomhlungu profile image
Sk

ahhh the old days 🏖️ I remember, I am lying I started this year 😂, I think I am a jr assembler? Loving it thou, so good to touch the metal

Collapse
 
benny00100 profile image
Benny Schuetz

Enjoy the ride. IMHO it will teach you a lot.

Collapse
 
chmoez profile image
Info Comment hidden by post author - thread only accessible via permalink
moez cherif

Protect your images in WordPress with adding watermarks automatically in just a few clicks with RMBG.PRO 🚀

youtu.be/Xqhtht95P-c

WordPress #Watermark #WordPressPlugin #ImageProtection #WebDesign #Photography #BloggingTips #WordPressTutorial

Collapse
 
anmolbaranwal profile image
Anmol Baranwal

People having entire conversations through code in comments lol. 🤣

Between, awesome post. 🔥

Collapse
 
chaymankala profile image
Chaitanya Mankala

Everyone who is commenting that they rather use high-level programming language for "Hello World", you should understand that even author is not recommending to use assembly in real life. We developed High Level languages to make our lives easier, everyone agrees on that. Its so sad that they cant appreciate assembly and not at all curious to understand how things work.

Future will be just like,
When someone writes a C program to print hello world, commentors like these will comment like "I would rather use chatGPT prompt, this is so stupid!"

Collapse
 
0xw3ston profile image
Youssef El Idrissi

this is quite a cool blog post,
so I began to learn Computer Architecture & Organization and I found the assembly section to be the most interesting (because it's practical, and you could see the theory about registers etc in action).
But honestly I didn't find a right motive to learn it and be proficient in it, I'm learning it only for the curiosity at the moment but yk I still didn't find the right purpose.
So I ask you, could it possibly be useful in something like say... Malware development ? because code could be obfuscated etc on a very low level.
What do you think?

Collapse
 
cc_f9f91ece754f4e626078c2 profile image
cc44599

1

Some comments have been hidden by the post's author - find out more