Logo  

CS456 - Systems Programming

Displaying exercises/e4/files/lib.s

; To compile to .o:
; nasm -felf64 lib.s

%include "lib.h"

GLOBAL getrandom, strlen, puts, putc, getc, exit
GLOBAL isspace, isdigit, printnum, printnumnl, atoi

SECTION .bss
        _ch: resb 1
   _randbuf: resq 1
     numbuf: resb 32

SECTION .text


; Converts the string pointed by rsi to a number in rax:
; registers used: rax, rsi, r8, r11, rdx
atoi:
	mov	r8, 0		; int64_t r8 = 0;
	mov	r11, 0		; int r11 = 0;

	cmp	BYTE [rsi], '-'	; if (*rsi == '-') {
	jne	.loop
	mov	r11, 1		;   r11 = 1;
	inc	rsi		;   rsi++;
				; }
.loop:
	mov	al, BYTE [rsi]	; while (isdigit(*rsi)) {
	call	isdigit
	cmp	rdx, 0
	je	.done

	imul	r8, r8, 10	;    r8 = r8 * 10;
	movzx	rdx, BYTE [rsi]	;    rdx = *rsi;  // r8 = r8 + (*rsi - '0');
	sub	rdx, '0'	;    rdx -= '0';
	add	r8, rdx		;    r8 += rdx;

	inc	rsi		;    rsi++;
	jmp	.loop		; }

.done:
	cmp	r11, 1		; if (r11)
	jne	.return
	neg	r8		;    r8 = -r8;

.return:
	mov	rax, r8		; rax = r8;
	ret			; return


; rax holds the number to be printed:
printnum:

	mov	rdi, 31
	mov	rsi, 3
	mov	BYTE [numbuf + rdi], 0
	mov	rbx, 10

.loop:
	dec	rsi
	
	cmp	rax, 0
	jne	.else
	cmp	rdi, 31
	je	.else

	dec	rdi
	mov	BYTE [numbuf+rdi], ' '
	cqo
	div	rbx
	jmp	.endif
.else:
	dec	rdi
	cqo
	div	rbx
	add	rdx, '0'
	mov	BYTE [numbuf + rdi], dl
	
.endif:

	cmp	rax, 0
	jg	.loop
	cmp	rsi, 0
	jg	.loop

	lea	rsi, [numbuf + rdi]
	call	puts
	ret

printnumnl:
	call	printnum
	mov	al, `\n`
	call	putc
	ret

; places 64 bits of randomness into rax:

getrandom:
	mov rax, SYS_getrandom
	mov rdi, _randbuf
	mov rsi, 8
	mov rdx, GRND_NONBLOCK
	syscall
	mov rax, [_randbuf]
	ret


; string in rsi, compute the length in rdx
strlen:
	mov rdx, 0			; rdx = 0
.loop:
	cmp BYTE [rsi+rdx], 0		; while (rsi[rdx] != '\0')
	je  .done

	inc rdx				;    rdx++;
	jmp .loop
.done:
	ret


; Expects the address of string to be printed in rsi
puts:
	call strlen
	mov  rax, SYS_write
	mov  rdi, STDOUT_FILENO
	syscall
	ret

; character to be printed in al
; write(STDOUT_FILENO, &_ch, 1);
putc:
	mov [_ch], al
	mov rax, SYS_write
	mov rdi, STDOUT_FILENO
	mov rsi, _ch
	mov rdx, 1
	syscall
	ret

; return character read in rax, or -1 on EOF:
getc:
	mov rax, SYS_read
	mov rdi, STDIN_FILENO
	mov rsi, _ch
	mov rdx, 1
	syscall
	cmp rax, 0
	jle .eof

	mov al, BYTE [_ch]
	ret
.eof:
	mov rax, -1
	ret

; rdx = isspace(al)
isspace:
	cmp al, ' '
	je .true
	cmp al, `\t`
	je .true
	cmp al, `\n`
	je .true
	cmp al, `\v`
	je .true
	cmp al, `\f`
	je .true
	mov rdx, 0
	ret
.true:
	mov rdx, 1
	ret

; rdx = isdigit(al);
isdigit:
	cmp al, '0'
	jl .false
	cmp al, `9`
	jg .false
	mov rdx, 1
	ret
.false:
	mov rdx, 0
	ret

; expects the exit status in rdi

exit:
	mov rax, SYS_exit
	syscall
	ret