Logo  

CS456 - Systems Programming

Displaying exercises/e4/solution/bitcount.s

; Syscall numbers are defined in /usr/include/asm/unistd_64.h:
%define SYS_READ	0
%define SYS_WRITE	1
%define SYS_OPEN	2
%define SYS_CLOSE	3
%define SYS_EXIT	60

%define STDIN_FILENO	0
%define STDOUT_FILENO	1
%define STDERR_FILENO	2

SECTION .data
	usage1:	db`Usage: `,0
	usage2:	db` <int>\n`,0
	nl:	db`\n`,0

SECTION .bss
	numbuf:	resb	32


SECTION .text
; Prints the string pointed to by rsi:
puts:
	mov	rdx, 0
.loop:	cmp	BYTE [rsi+rdx], `\0`	; rdx = strlen(rsi);
	je	.stop
	inc	rdx
	jmp	.loop
.stop:	mov	rax, SYS_WRITE		; write(STDOUT_FILENO, rsi, rdx)
	mov	rdi, STDOUT_FILENO
	syscall
	ret

; Print the number in the rax register
printnum:
	lea	rsi, [numbuf+32]
	mov	BYTE [rsi], 0

	mov	rbx, 10		; rbx = 10 (the base for our numbers)
	mov	r12, 0		; r12 = false (negative flag)
	cmp	rax, 0
	jge	.loop		; if (rax >= 0) goto .loop
	neg	rax		; rax = -rax;
	mov	r12, 1		; r12 = true (number is negative)

.loop:				; do {
	cqo
	div	rbx		;   rax = rax/rbx; rdx = rax%rbx;
	add	dl, '0'		;   rax += '0';
	dec	rsi		;   rsi--;
	mov	BYTE [rsi], dl	;   *rsi = dl;
	cmp	rax, 0		
	jne	.loop		; } while (rax > 0)

	cmp	r12, 1		; if (r12 == 1) {
	jne	.skipneg
	dec	rsi		;   *(--rsi) = '-';
	mov	BYTE [rsi], '-'	; }
.skipneg:
	call	puts		; puts(rsi);
	ret

; convert the string pointed at by rsi to a integer in rax;
myatoi:				;int64_t myatoi(char *rsi)
	mov rax, 0		;  rax = 0;  // number to be computed
	mov r11, 0		;  r11 = 0;  // negative flag
	mov r12, 0		;  r12 = 0;  // temporary variable
	mov rbx, 10		;  rbx = 10; // base to multiply by

	cmp BYTE [rsi], '-'	;  if (*s == '-') {
	jne .loop
	mov r11, 1		;    neg = 1;
	inc rsi			;    rsi++

.loop:				;  while (isdigit(*s)) {
	cmp BYTE [rsi], '0'
	jl .exit
	cmp BYTE [rsi], '9'
	jg .exit

	mul rbx			;    rax = rax * 10;
	mov r12b, BYTE [rsi]	;    r12 = *rsi;
	sub r12, '0'		;    r12 = r12 - '0';
	add rax, r12		;    rax = rax + r12;
	inc rsi			;    rsi++

	jmp .loop		;  }

.exit:
	cmp r11, 1		;  if (r11)

	jne .skip
	neg rax			;    rax = -rax;

.skip:
	ret			;  return rax;


global _start
_start:				; int main(int argc, char **argv)
	MOV	r15, 0		;   int64_t r15 = 0;
        MOV	r14, 0		;   int r14 = 0;

	CMP	QWORD [rsp], 2	;   if (argc < 2) {
	JGE .continue
	MOV	rsi, usage1		
	call puts		;     puts("Usage: ");
	MOV	rsi, [rsp+8]
	call puts		;     puts(argv[0]);
	MOV	rsi, usage2
	call puts		;     puts(" <int>\n");
	MOV	rdi, 1
	JMP .exit		;     exit(1);
				;   }

.continue:
	MOV	rsi, [rsp+16]	;   rsi = argv[1];
	call	myatoi		;   r15 = myatoi(rsi);

	MOV	rcx, 0		;   rcx = 0;	// bit-count
.loop:				;   do {
	TEST	rax, 1		;     if (rax & 1)
	JZ	.skip
	INC	rcx		;	rcx++;
.skip:
	SHR	rax, 1		;     rax >>= 1;
	JNE	.loop		;   } while (rax);

	MOV	rax, rcx
	call	printnum	;   printnum(rcx);

	MOV	rsi, nl
	call	puts		;   puts("\n");

	MOV	rdi, 0		;   exit(0);
.exit:
	MOV	rax, 60
	syscall