Coincidentally, the two versions of this are exactly the same size in bytes
global _start
; =========================================================================================================
section .data
Prompt db 10, 'Hello Cruel World!', 10, 0
section .text
; =-= =-= =-= =-= =-= =-= =-= =-= =-= =-= =-= =-= =-= =-= =-= =-= =-= =-= =-= =-= =-= =-= =-= =-= =-= =-=
; Dispaly applications signon message
_start: enter 24, 0 ; Create dummy frame
mov rsi, Prompt
call Console
.Exit: leave ; Kill dummy frame
xor rax, rax
mov rdi, rax ; Exit status NULL
mov al, SYS_EXIT
syscall
; =========================================================================================================
; Display ASCII string on console (monitor)
; ENTRY: RSI = Pointer to null terminated string to be displayed.
; LEAVE: RAX = Bytes displayed excluding null.
; All other registers preseved.
; FLAGS: ZR = 1 If nothing was displayed.
; 30H - 48 Bytes
; ---------------------------------------------------------------------------------------------------------
Console: push rdi
push rcx
push rdx
; First order of business is to search for end of string (NULL). Why? because we don't always
; know because there are times where strings are being built at runtime and this would have
; to be done anyway.
xor rcx, rcx
dec rcx ; Should be sufficiently large enough
mov al, 0 ; Byte we are search for
mov rdi, rsi
repnz scasb ; Find terminating character
neg rcx
dec rcx
dec rcx ; This is the actual length of string excluding null
; Setup registers for syscall
xor rax, rax
mov al, STDOUT ; I do this like this becuase it uses 5 bytes
mov rdi, rax ; versus mov RDI, STDOUT would take 11
mov al, SYS_WRITE
mov rdx, rcx ; Move count of bytes
syscall
pop rdx
pop rcx
pop rdi
or rax, rax
ret ; Return with string size in RAX and ZR=1 if string empty.