//-----------------------------------------------------------------
//	run.s
//
//	This program demonstrates the 'fork()', 'waitpid()', and
//	'execve()' system-calls, and shows how a 'child' process
//	communicates the value of its exit-code to the 'parent'. 
//	
//		to assemble:  $ as run.s -o run.o
//		and to link:  $ ld run.o -o run
//		and execute:  $ ./run <appname> [<args>...]
//
//	programmer: ALLAN CRUSE
//	written on: 26 FEB 2008
//	revised on: 01 MAR 2009 -- for our x86_64 Linux platform
//-----------------------------------------------------------------


	# manifest constants
	.equ	sys_write, 1
	.equ	sys_fork, 57
	.equ	sys_execve, 59
	.equ	sys_exit, 60
	.equ	sys_wait4, 61
	.equ	STDOUT, 1


	.section	.data
hex:	.ascii	"0123456789ABCDEF"	# array of hex numerals
ret:	.quad	-1			# storage for exit-code
msg:	.ascii	"\nChild-process terminated with exit-code = 0x"
buf:	.ascii	"xx \n\n"		# buffer for hex string
len:	.quad	. - msg			# size of output string

	
	.section	.text
_start:
	# fork a child-process
	mov	$sys_fork, %rax		# system-call ID-number
	syscall				# invoke kernel service

	# parent waits while child launches the application
	or	%rax, %rax		# parent process?
	jz	child			# no, skip waiting

	# wait until child-process has terminated
	mov	$sys_wait4, %rax	# system-call ID-number
	mov	$0, %rdi		# PID is unspecified 
	lea	ret, %rsi		# where to save status
	mov	$0, %rdx		# no special options 
	xor	%rbx, %rbx		# no 'rusage' structure
	syscall				# invoke kernel service

	# convert exit-status to hexadecimal digit-string
	lea	buf, %rdi		# output-buffer address
	mov	ret, %rax		# get child's exit-code
	call	ah2hex			# convert int to string

	# display the report
	mov	$sys_write, %rax	# system-call ID-number
	mov	$STDOUT, %rdi		# device-file ID-number
	lea	msg, %rsi		# address of the string
	mov	len, %rdx		# length for the string
	syscall				# invoke kernel service

	# terminate the parent-process
	xor	%rdi, %rdi		# parent exit-code = 0
exit:	mov	$sys_exit, %rax		# system-call ID-number
	syscall				# invoke kernel service

child:	# child-process executes the specified application
	cmpl	$1, (%rsp)		# user supplied name?
	je	exit			# no, cannot continue

	mov	$sys_execve, %rax	# system-call ID-number
	mov	16(%rsp), %rdi		# address of prog name
	lea	16(%rsp), %rsi		# address of argv
	mov	(%rsp), %rdx		# value of argc
	lea	16(%rsp, %rdx, 8), %rdx	# address of envp
	syscall				# invoke kernel service

	# in case of failure, the child-process terminates
	mov	%rax, %rdi		# errno is exit-code
	jmp	exit			# and terminate child

#
# This helper-function converts an 8-bit value it finds in the
# AH register into its representation as a pair of hexadecimal 
# numerals in the memory-buffer whose address it finds in RDI.
#
ah2hex:	push	%rax
	push	%rbx
	push	%rcx
	push	%rdx
	push	%rdi

	mov	$2, %rcx
nxnyb:	rol	$4, %ax
	mov	%al, %bl
	and	$0xF, %rbx
	mov	hex(%rbx), %dl
	mov	%dl, (%rdi)
	inc	%rdi
	loop	nxnyb

	pop	%rdi
	pop	%rdx
	pop	%rcx
	pop	%rbx
	pop	%rax
	ret
	
	.global	_start
	.end