Lately I’ve been studying assembly language for the x86/x86_64 architecture. Assembly language is a human readable form of machine code and is as low level as it gets. Today there aren’t many use cases for it as other low level languages like c and rust is fast enough. But I’ve always wanted to know more about what happens at the lowest level and I think it’s good to have knowledge how the most primitives of the CPU and operating system works.
I will be writing a series of post of what I’ve learned.
When you have written an assembly program you need to translate it to machine code. This is done with an assembler. There are several different assemblers but I will be using
NASM. The Netwide assembler(NASM) is an x86 assembler that works on both on linux and windows and can output object format files like elf32/elf64 and win32/win64.
When the assembler has generated the object files we need to use a linker to generate and executeable file. The linker combines object files, relocates their data and resolves symbol references. I will be using
ld which is the GNU linker.
This is a simple hello world example for 64-bit linux. I will explain what each row does in the next post.
; ; Example code is taken from the docs of NASM ; global _start section .text _start: mov rax, 1 ; system call for write mov rdi, 1 ; file handle 1 is stdout mov rsi, message ; address of string to output mov rdx, 13 ; number of bytes syscall ; invoke operating system to do the write mov rax, 60 ; system call for exit xor rdi, rdi ; exit code 0 syscall ; invoke operating system to exit section .data message: db "Hello, World", 10 ; note the newline at the end
Compile and run
First we need to turn our assembly file to an object file
$ nasm -felf64 hello.asm
Nasm will by default call the object file
hello.o. Then we need to use the linker to create and executable.
$ ld hello.o
The default output filename of ld is
a.out and can be run by typing.
$ ./a.out Hello, World
You should get the output