We can use the read syscall to read a string (really, a fixed-length array
of bytes) from a file descriptor, but that just gives us plain text. If we want
to read in an integer value and actually interpret it numerically, we have
to write an int_read routine ourselves. In this group program, you will do
just that. You will write two functions:
int_readreceives a buffer address inrdiand its length inrsiand should interpret the contents as an unsigned 64-bit integer, returning the value inrax. You should try to finish this part in-class, although you’ll have to use GDB to inspect the values your function is returning to see if you’ve done it right.If the input is not correctly formatted as a number (e.g., “abc”) then
int_readcan return anything. (I.e., you don’t need to worry about handling errors.)Don’t forget that the length returned by the
SYS_READsyscall include the newline at the end.int_printreceives an unsigned 64-bit integer value inrdiand should print its decimal representation to the standard output stream. The process for converting a value to a decimal representation is similar to the process for converting a decimal value to binary:
1. Divide the value by 10.
2. The remainder becomes the last digit.
3. The quotient becomes the new value. Goto 1 until the value is 0.
Here are some links to the important instructions you will need:
Note that you cannot multiply/divide by an immediate.
Before doing either you almost certainly want to clear
rdx. (This is particularly important fordiv, becausedivwrites the remainder tordx, so if you do it in a loop, you have to clear it every time.)mulwill adjust (overflow) the size of its result to the size of its operand, so if you multiply by a byte, you’ll only get a byte’s worth of output.
Here’s a skeleton file to get you started. You can find a copy of this file
on the server in /usr/local/class/src/group_proj2.s.
;;;
;;; group_proj2.s
;;; Read in integers and then print them back out.
;;;
section .data
prompt: db "> "
prompt_len: equ $-prompt
buffer_len: equ 256
in_buffer: times buffer_len db 0
; Output buffer, for use by int_write
out_buffer: times buffer_len db 0, 10
SYS_READ: equ 0
SYS_WRITE: equ 1
STDIN: equ 0
STDOUT: equ 1
section .text
global _start
;;
;; _start
;; Runs the input-print loop forever.
;;
_start:
.begin_loop:
; Print prompt
mov rax, SYS_WRITE
mov rdi, STDOUT
mov rsi, prompt
mov rdx, prompt_len
syscall
; Read in input
mov rax, SYS_READ
mov rdi, STDIN
mov rsi, in_buffer
mov rdx, buffer_len
syscall
mov rdi, in_buffer
mov rsi, rax ; Input length
dec rsi ; Remove newline
call int_read
mov rdi, rax
call int_print
jmp .begin_loop
; Infinite loop, so there's no SYS_EXIT
; The only way to quit is with Ctrl-C
;;
;; int_read
;; Reads a 64-bit unsigned integer from rdi, with length rsi,
;; returning its result in rax.
;;
int_read:
; Replace this with your code
mov rax, 0
ret
;;
;; int_print
;; Prints a decimal representation of rdi (64-bit unsigned) to
;; standard output.
;;
int_print:
; Your code here
ret