Hello World in nasm

System: Intel 32-bit processor architecture on a GNU/Linux system

Hello World with correct exit

Let’s try to break this down into something useful/understandable.

The .asm file is divided into 2 different sections as you can see. Here’s some beautiful asci to illustrate it :)
| text section This section contain the instructions
| data section This contain the variables (afaik)

global _start
^ This will tell the linker where the entry point of the program is. Ie: _start


Our program need to execute two tasks. Print Hello World! and then exit.
To do this we will do two different system calls to the kernel. The system call we need can be found in the file unistd_32.h. It will probably wary a bit from system to system where you can find it but on the distribution I use it’s located here: /usr/include/i386-linux-gnu/asm/unistd_32.h

Looking through the file we can quite easy locate these two system calls:
#define __NR_exit 1
#define __NR_write 4


The call for the exit function looks like this:
void _exit(int status);

In the man page we can find the following description:
The exit() function causes normal process termination and the value of status & 0377 is returned to the parent.

Great, this mean we can pass a return integer that we later on can check with an echo in the terminal. To make sure our program exited as it should.


Next up is the write function.
ssize_t write(int fd, const void *buf, size_t count);

Man page: write() writes up to count bytes from the buffer pointed buf to the file referred to by the file descriptor fd.

File descriptors:
0 – stdin
1 – stdout
2 – stderr

This mean that we need to pass stdout (1) to fd (the file descriptor).
const void *buf should contain a pointer to our msg variable which means it will just be msg.
size_t count should contain the length of the variable the pointer is set to. Which means 12 since len(“Hello World!”) equals 12

This mean the call would look something like this: write(1, msg, 12);

This part might be a bit flawed, but it’s as far as I’ve come :)

Name – Explanation
eax – system call number
ebx – 1 argument
ecx – 2 argument
edx – 3 argument
esi – 4 argument
edi – 5 argument

Worth to note: A functions return value will be placed in eax after execution.
To move data from registry into the memory we will use mov
Also please note that the numbers are entered as hex!

Time to execute the write code:

              mov eax, 0x4                Assign system call nr 4 to eax
              mov ebx, 0x1                Assign 1 into argument 1
              mov ecx, msg                Assign variable msg into argument 2
              mov edx, 0xC                Assign 12 into argument 3
              int 0x80                    Call upon the almighty kernel for execution

Time to exit the program:

              mov eax, 0x1                Assign system call nr 1 to eax
              mov ebx, 2                  Assign 2 into argument 1
              int 0x80                    Call upon the almighty kernel for execution

At this point the last piece of the code should be somewhat self explanatory.

1) Create object file
nasm -f elf32 -o HelloWorld.o HelloWorld.asm
2) Link it into an executable
ld -o HelloWorld HelloWorld.o

Execute as usual

The nasm code would look something like this in cpp.

    printf("Hello World");

Compiling the two examples (nasm & cpp) and comparing the size of the binaries is pretty interesting.
Nasm: 651 bytes
Cpp Linux: 7157 bytes
Cpp Windows: 11912 bytes

Obviously very tedious to code in nasm (at least in the start) but in the end it reveals a pretty neat result!