Search code examples
linuxassemblyx86-64nasmsystem-calls

Why is 64-bit NASM insisting on the RSI register ? Why can't I put "hello world" into RCX register and use SYSCALL?


I have this x86 assembly code for a "hello world" program.

global    _start

section   .text

_start: 
  
mov       eax, 1                  ; system call for write       
mov       ebx, 1                  ; file handle 1 is stdout        
mov       ecx, message            ; address of string to output

mov       edx, message_len        ; length of the string      
syscall                           ; invoke operating system to do the write       
mov       eax, 60                 ; system call for exit          
mov       ebx, 0                  ; exit code 0         
syscall                           ; invoke operating system to ex
        
section   .data

message:  db "Hello, World!!!!", 10      ; newline at the end
message_len equ $-message                ; length of the string

This doesn't compile with nasm -felf64 hello.asm && ld hello.o && ./a.out on a 64-bit Linux machine.

But if I change the third line mov ecx, message to mov rsi, message it works!

My question is why is 64-bit NASM insisting on the RSI register?
Because I have seen people compiling with ECX on 32-bit Arch Linux.


Solution

  • x86 does not use the same calling convention as x64.

    In x86, the first argument is EBX which contains the descriptor, ECX contains the buffer, EDX contains the length and EAX contains the system call ordinal.

    In x64, the first argument is contained in RDI, second in RSI, third in RDX and fourth in RCX while RAX contains the ordinal for the system call.

    That's why your call is working on x86 but needs to be adjusted to work on x64 as well.