HOWTO+-+Write+a+simple+hello+in+assembly+and+compile+using+NASM

Read also here: http://en.wikibooks.org/wiki/X86_Assembly/Interfacing_with_Linux

int 0x80
On both Linux x86 and Linux x86_64 systems you can make a syscall by calling interrupt 0x80 using the  command. Parameters are passed by setting the general purpose registers as following:


 * Syscall # || Param 1 || Param 2 || Param 3 || Param 4 || Param 5 || Param 6 ||
 * eax || ebx || ecx || edx || esi || edi || ebp ||

All registers are preserved during the syscall.
 * Return value ||
 * eax ||

Find the system call names and numbers in the file: code format="bash" $ ls /usr/src/*/arch/x86/include/generated/uapi/asm/unistd_32.h | tail -1 /usr/src/linux-headers-3.13.0-36-generic/arch/x86/include/generated/uapi/asm/unistd_32.h code Use "man 2 " to see the order of the accepted parameters for each system call code format="bash" $ man 2 write code The files unistd_32.h and unistd_64.h are generated automatically after this Linux kernel commit: code commit 303395ac3bf3e2cb488435537d416bc840438fcb Author: H. Peter Anvin  Date: Fri Nov 11 16:07:41 2011 -0800

x86: Generate system call tables and unistd_*.h from tables code

EXAMPLE
Save the following a file hello.asm (the system call numbers are the ones in unistd_32.h) code format="asm" global _start         ; must be declared for linker (ld)

section .text _start: mov    eax, 4 ; write mov    ebx, 1 ; stdout mov    ecx, msg mov    edx, msg.len int    0x80   ; write(stdout, msg, strlen(msg));

mov    eax, 1 ; exit mov    ebx, 0 int    0x80   ; exit(0)

section .data msg:   db      "Hello, world!", 10 .len:  equ     $ - msg code

Compile and link using NASM code format="bash" $ nasm -hf $ nasm -f elf64 hello.asm                      # this will produce hello.o ELF object file $ ld -s -o hello hello.o                       # this will produce hello executable code

Run the program code format="bash" ./hello code

syscall
The x86_64 architecture introduced a dedicated instruction to make a syscall. It does not access the interrupt descriptor table and is faster. Parameters are passed by setting the general purpose registers as following:


 * Syscall # || Param 1 || Param 2 || Param 3 || Param 4 || Param 5 || Param 6 ||
 * rax || rdi || rsi || rdx || r10 || r8 || r9 ||

All registers, except  and , are preserved during the syscall.
 * Return value ||
 * rax ||

Find the system call numbers in the file: code format="bash" $ ls /usr/src/*/arch/x86/include/generated/uapi/asm/unistd_64.h | tail -1 /usr/src/linux-headers-3.13.0-36-generic/arch/x86/include/generated/uapi/asm/unistd_64.h code Use "man 2 " to see the order of the accepted parameters for each system call code format="bash" $ man 2 write code

EXAMPLE
The following code is optimized for 64 bits and uses the faster x64 "syscall" instead of the interrupt (the system call numbers are the ones in unistd_64.h). code format="asm" global _start          ; must be declared for linker (ld)

section .text _start: mov    rax, 1  ; write mov    rdi, 1  ; stdout mov    rsi, msg mov    rdx, msg.len syscall        ; write(stdout, msg, strlen(msg));

mov    rax, 60 ; exit mov    rdi, 0 syscall        ; exit(0)

section .data msg:   db      "Hello, world!", 10 .len:  equ     $ - msg code

Compile and link using NASM code format="bash" $ nasm -hf $ nasm -f elf64 hello.asm                      # this will produce hello.o ELF object file $ ld -s -o hello hello.o                       # this will produce hello executable code

Run the program code format="bash" ./hello code