Assembly demo

Assembly code written in during a live lecture

.text
.globl _start
_start:
	#write(1, QUESTION, sizeof(QUESTION) - 1);
	mov $1, %rdi		#stdout fileno
	lea question, %rsi	#pointer to string
	mov $question_len, %rdx	#length
	mov $1, %rax		#no. for write
	syscall			#do it!
	cmp $0, %rax		#check return value
	jl error		#if negative, error out

	#read(0, buffer, sizeof(buffer));
	mov $0, %rdi		#stdin fileno
	lea buffer, %rsi	#pointer to buffer
	mov $buffer_len, %rdx	#length
	mov $0, %rax		#no. for read
	syscall			#do it!
	push %rax		#save return value
	cmp $1, %rax		#check return value
	jle error		#if <= 1, error out

	#write(1, MESSAGE, sizeof(MESSAGE) - 1);
	mov $1, %rdi		#stdout fileno
	lea hellomsg, %rsi	#pointer to string
	mov $hello_len, %rdx	#length
	mov $1, %rax		#no. for write
	syscall			#do it!
	cmp $0, %rax		#check return value
	jl error		#if negative, error out

	#write(1, buffer, (size_t)len);
	mov $1, %rdi		#stdout fileno
	lea buffer, %rsi	#pointer to buffer
	pop %rdx		#saved length
	mov $1, %rax		#no. for write
	syscall			#do it!
	cmp $0, %rax		#check return value
	jl error		#if <= 1, error out

	mov $0, %rdi		#exit status of 0
	mov $60, %rax		#no. for exit
	syscall			#do it!
error:
	mov $2, %rdi		#stderr fileno
	lea errormsg, %rsi	#pointer to string
	mov $error_len, %rdx	#length
	mov $1, %rax		#no. for write
	syscall			#do it!
	mov $1, %rdi		#exit status of 1
	mov $60, %rax		#no. for exit
	syscall			#do it!

.data
question:
.ascii "What is your name?\n"
.equ question_len, . - question
errormsg:
.ascii "error!\n"
.equ error_len, . - errormsg
buffer:
.equ buffer_len, 100
.space buffer_len, 0
hellomsg:
.ascii "Hello, "
.equ hello_len, . - hellomsg

Similar prewritten example for both x86-64 and aarch64:

x86-64:

#include <syscall.h>

#define STDIN_FILENO 0
#define STDOUT_FILENO 1

.globl _start				//make _start a global symbol so linker can find it
_start:					//_start is entry point for all executibles
	mov %rax, $SYS_write		//%rax holds syscall number, 1 represents `write`
	mov %rdi, $STDOUT_FILENO	//%rdi holds first syscall arg, 1 represents `stdout`
	lea %rsi, prompt		//%rsi holds second arg, =prompt gets address if prompt string from data section
	mov %rdx, $prompt_len		//%rdx holds third arg, prompt_len is macro that expands to calculated size
	syscall				//perform a system call
	cmp %rdi, $0			//check if return is negative
	jl .out				//if it is, exit program early with exit code based on return value
	mov %rax, $SYS_read		//0 represents `read`
	mov %rdi, $STDIN_FILENO		//0 represents `stdin`
	ldr %rsi, =buffer		//read into buffer
	mov %rdx, $buffer_len		//at most buffer_len bytes
	syscall				//perform syscall
	cmp %rdi, $0			//check for error as above
	jl .out
	mov %rcx, %rdi			//save returned length to only print that many bytes
	mov %rax, $SYS_write		//back to writing, send "Hello, " to stdout
	mov %rdi, $STDOUT_FILENO
	ldr %rsi, =msg
	mov %rdx, $msg_len
	syscall
	cmp %rdi, $0			//check for error
	jl .out
	mov %rdi, $1			//need to set %rdi back to 1 because it was replaced with return code of last call
	ldr %rsi, =buffer		//whatever they input
	mov %rdx, %rcx			//and however long it was
	syscall				//send that
	cmp %rdi, $0			//check for errors
	jl .out
	mov %rdi, $0			//if there was not an error, set return code to 0
.out:					//otherwise we were sent here and %rdi already contains error code to return
	mov %rax, $SYS_exit		//60 represents exit
	syscall				//exit program
					//exit syscall does not return, so _start function does not need to return to caller

.data					//data section for strings
prompt: .ascii "What is your name? "
.equ prompt_len, .-prompt		//.equ makes a new macro, `.` represents current location in binary, and subtracting the value of prompt gives how many bytes prompt contained
buffer: .space 64
.equ buffer_len, .-buffer
msg: .ascii "Hello, "
.equ msg_len, .-msg

.data
message:
	.ascii "Hello, World!\n"
	len = . - message
.text
.global _start
_start:
	mov $1, %rdi
	mov $message, %rsi
	mov $len, %rdx
	mov $1, %rax
	syscall
	mov $13, %rdi
	mov $60, %rax
	syscall

aarch64:

#include <syscall.h>

#define STDIN_FILENO 0
#define STDOUT_FILENO 1

.globl _start			//make _start a global symbol so linker can find it
_start:				//_start is entry point for all executibles
	mov x8, #SYS_write	//x8 holds syscall number, 64 represents `write`
	mov x0, #STDOUT_FILENO	//x0 holds first syscall arg, 1 represents `stdout`
	ldr x1, =prompt		//x1 holds second arg, =prompt gets address if prompt string from data section
	mov x2, #prompt_len	//x2 holds third arg, prompt_len is macro that expands to calculated size
	svc #0			//perform a system call
	cmp x0, #0		//check if return is negative
	b.lt .out		//if it is, exit program early with exit code based on return value
	mov x8, #SYS_read	//63 represents `read`
	mov x0, #STDIN_FILENO	//0 represents `stdin`
	ldr x1, =buffer		//read into buffer
	mov x2, #buffer_len	//at most buffer_len bytes
	svc #0			//perform syscall
	cmp x0, #0		//check for error as above
	b.lt .out
	mov x3, x0		//save returned length to only print that many bytes
	mov x8, #SYS_write	//back to writing, send "Hello, " to stdout
	mov x0, #STDOUT_FILENO
	ldr x1, =msg
	mov x2, #msg_len
	svc #0
	cmp x0, #0		//check for error
	b.lt .out
	mov x0, #1		//need to set x0 back to 1 because it was replaced with return code of last call
	ldr x1, =buffer		//whatever they input
	mov x2, x3		//and however long it was
	svc #0			//send that
	cmp x0, #0		//check for errors
	b.lt .out
	mov x0, #0		//if there was not an error, set return code to 0
.out:				//otherwise we were sent here and x0 already contains error code to return
	mov x8, #SYS_exit	//93 represents exit
	svc #0			//exit program
				//exit syscall does not return, so _start function does not need to return to caller

.data				//data section for strings
prompt: .ascii "What is your name? "
.equ prompt_len, .-prompt	//.equ makes a new macro, `.` represents current location in binary, and subtracting the value of prompt gives how many bytes prompt contained
buffer: .space 64
.equ buffer_len, .-buffer
msg: .ascii "Hello, "
.equ msg_len, .-msg

Example makefile for assembly with preproccessing

.PHONY: all clean
all:asm_hello

asm_hello: asm_hello.o
	ld -o asm_hello asm_hello.o

asm_hello.o: asm_hello.s
	as asm_hello.s -o asm_hello.o

asm_hello.s: asm_hello.S
	cpp asm_hello.S -o asm_hello.s

clean:
	-rm asm_hello.s asm_hello.o asm_hello