Hello x64 Part I

This is the same as the previous x86 Hello World program, but for x64 instead.

NOTE: This code does work, but this is not how x64 system calls are made. Look into the next part to learn the real x64 way.

ASM Code


segment .data                   ;section declaration

msg db     "Hello, world!", 0xA, 0x0 ;our NULL-terminated string, ending with 0xA (lf) or 0xD (CR)
len equ     $ - msg             ;length of our string

segment .text                   ;section declaration

                                ;we must export the entry point to the ELF linker or loader
    global  asm_main

pushaq:     ; push all registers
    enter 0,0
    push rax
    push rcx
    push rdx
    push rbx
    push rbp
    push rsi
    push rdi
    push  r8
    push  r9
    push r10
    push r11
    push r12
    push r13
    push r14
    push r15

popaq:      ; pop back all registers in the complementary order
    enter 0,0
    pop r15
    pop r14
    pop r13
    pop r12
    pop r11
    pop r10
    pop  r9
    pop  r8
    pop rdi    
    pop rsi    
    pop rbp    
    pop rbx    
    pop rdx    
    pop rcx
    pop rax

                ;entry point.
    enter 0,0
    call pushaq

                                ;write string to stdout
    mov     rdx,len             ;third argument: message length
    mov     rcx,msg             ;second argument: pointer to message to write
    mov     rbx,1               ;first argument: file handle (stdout)
    mov     rax,4               ;system call number (sys_write)
    int     0x80                ;call kernel

    call popaq                       ; return to the C caller with 0 status, sets rax 0, but C will only receive eax part as returning `int`
    mov rax, 0


Get the 64-bit driver

$ mv driver.c driver64.c
$ gcc -c driver64.c

Compile and link programm

$ nasm -f elf64 hello64.asm
$ gcc -o hello64 driver64.o hello64.o


After compiling to hello64.o and hello, we can now run the program.

$ ./hello64
Hello World!