Browse Source

Add `ls` program

Matteo Savatteri 3 years ago
parent
commit
2b1166c817
3 changed files with 125 additions and 0 deletions
  1. 29 0
      5_ls/Makefile
  2. 14 0
      5_ls/README.md
  3. 82 0
      5_ls/src/ls.s

+ 29 - 0
5_ls/Makefile

@@ -0,0 +1,29 @@
+MAIN=ls
+
+AS=as
+ASFLAGS=
+LD=ld
+LDFLAGS=
+
+SDIR=src
+ODIR=obj
+BDIR=bin
+
+
+$(BDIR)/$(MAIN): $(ODIR)/$(MAIN).o $(BDIR)
+	$(LD) -o $@ $(ODIR)/$(MAIN).o $(LDFLAGS)
+$(BDIR):
+	mkdir $(BDIR)
+
+$(ODIR)/$(MAIN).o: $(SDIR)/$(MAIN).s $(ODIR)
+	$(AS) -o $@ $(SDIR)/$(MAIN).s $(ASFLAGS)
+$(ODIR):
+	mkdir $(ODIR)
+
+
+.PHONY: clean clen-all
+
+clean:
+	rm -rf $(ODIR)
+clean-all:
+	rm -rf $(ODIR) $(BDIR)

+ 14 - 0
5_ls/README.md

@@ -0,0 +1,14 @@
+# ls
+Call the getdents64 function and list filenames of directory entries.
+
+## Description
+The program `ls` asks the kernel the entries of the the current
+working directory and prints them to standard output.
+
+## Usage
+`$ ls`
+
+## Comment
+The entries are listed in directory order and not sorted :).
+Note that "dot" files are not treated specially.
+There's a limit of 16 MiB for the directory structure length. 

+ 82 - 0
5_ls/src/ls.s

@@ -0,0 +1,82 @@
+.text					# Section for machine istructions to be executed
+	.global _start			# Needed by ld to find his default entry point
+_start:					# _start symbol
+	mov	$257, %rax		# sys_openat call
+	mov	$-100, %rdi		# Set dir file descriptor. -100 is special for
+					# AT_FDCWD (fd of current dir)
+	mov	$cwd, %rsi		# Set filename
+	xor	%rdx, %rdx		# Call kernel
+	syscall				# Set file status flag. 0 = O_RDONLY
+	test	%rax, %rax		# Test return value. Negative is failure.
+					# Anithing else is dir file descriptor
+	js	exit_error		# If signed jump to error
+
+	mov	%rax, %rdi		# Set dir file descriptor
+	mov	$217, %rax		# sys_getdents64 call
+	mov	$buf, %rsi		# Set pointer to buffer for storing dir entries
+	mov	$ 16777216, %rdx	# Set buffer length
+	syscall				# Call kernel
+	test	%rax, %rax		# Negative is error. Anything else is number of
+					# bytes read
+	js	exit_error
+
+	mov	%rax, %r12		# Save number of bytes read
+	mov	%rsi, %r13		# Save buffer pointer
+
+dirent_loop:				# Loop over directory entries
+        lea	19(%r13), %r15		# Save pointer to filename
+        mov	%r15, %rdi		# Set pointer to filename
+	xor	%rcx, %rcx		# Set %rdx to zero
+	xor	%al, %al		# Set %al to zero
+	not	%rcx			# Set %rdx to max integer (not of 0)
+	cld				# Set direction flag to zero.
+					# When direction flag is set to zero all string istructions
+					# run ahead (from low to high adresses)
+	repne	scasb			# repne = repeat argument operation %rcx times unless
+					# confronted areas are equal, decrementing %rcx each time.
+					# scasb = compare %al with byte at %rdi then set status flags.
+					# In other words: search zero byte at the and of the string.
+	not	%rcx			# Now %rcx is max int - filename_length - 1 (zero byte).
+					# But max int = -1 so %rcx = -2 - filename_length and
+					# Note that not number is  abs(number) - 1,
+					# so %rcx = filename_length + 2 -1 = filename_length + 1
+	dec	%rcx			# Decrease %rcx so that now %rcx = filename_length
+
+	mov	$1, %rax		# Print filename to stdout
+	mov	$1, %rdi
+	mov	%r15, %rsi
+	mov	%rcx, %rdx
+	syscall
+
+	mov	$1, %rax		# Print endline to stdout
+	mov	$endl, %rsi
+	mov	$1, %rdx
+	syscall
+
+	movw    16(%r13), %r14w		# Save size of current entry in low word of %r14
+	add	%r14, %r13		# Add size to buffer pointer to shift to next entry
+	sub	%r14, %r12		# Subtract size from buffer size
+
+	test	%r12, %r12		# Test if left buffer size is zero
+	jnz	dirent_loop		# Loop if nonzero
+
+exit:					# Exit success
+	mov	$60, %rax
+	xor	%rdi, %rdi
+	syscall
+
+exit_error:				# Exit failure
+	mov	$60, %rax
+	mov	$1, %rdi
+	syscall
+
+.section .rodata
+	cwd:				# Variable for current dir (.)
+		.asciz "."
+	endl:				# Variable for endline
+		.byte '\n'
+.section .bss
+	buf:				# Dir entries buffer.
+					# Attention! This sets a limit to entries
+					# read from dir.
+		.skip  16777216		# 16 MiB