Recently I was trying to print a number in x86_64 assembly on Linux with NASM, and it took me quite some time to figure out how to do it correctly. In this article I will share my solution with you, together with some explanations.
Printing Hello World!
This is the file main.asm
, which contains the main function of our program.
BITS 64;
global main ; the standard gcc entry point
extern printf ; declare a C function to be called
section .text
main:
push rbp ; set up stack frame, must be alligned
mov rdi, message ; first argument for printf
xor rax, rax ; rax must be 0 (see explanations below)
call printf ; call the printf function
pop rbp ; restore stack
mov rax, 0 ; normal, no error, return value
ret ; return
section .data
message: db "Hello, World!", 10, 0 ; note the newline (10) and null (0) at the end
This Makefile
will compile and link our NASM program.
all: main
main: main.o
gcc -m64 -o main main.o -lc -no-pie
main.o: main.asm
nasm -f elf64 -o main.o main.asm
clean:
rm -f main.o
To build and call the program:
$ make
$ ./main
# Hello World!
Explanations
The first line: BITS 64;
tells NASM that we are running on a 64 bits architecture. It prevents a number of syntax highlight errors in VS Code.
Because we are linking with gcc, and not ld, the entry point is not _start
but main
like the int main()
function in C. Therefore, we declare our main function with global main
, we setup the stack frame with push rbp
and pop rbp
, and we return zero with mov rax, 0
and ret
.
Calling printf()
is done like in C. The first argument is a pointer to the null terminated string "Hello, World!\n"
, so we set it with mov rdi, message
. According to the calling convention on Linux for functions with variable arguments, the register RAX contains the number of vector register arguments. Since we do not pass any floating-point numbers, RAX must be equal to zero. We reset it with xor rax, rax
.
When linking with gcc, the option -no-pie
is used in order to prevent a linking error about position independent executables. And the option -lc
tells gcc to link with the C library.
Printing a number
If we wanted to print a number like this printf("Number = %d", 42)
in C, we would use the following code.
mov rdi, message
mov rsi, 42
xor rax, rax
call printf
With the message string:
message: db 'Number = %d', 10, 0