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