Assembly Tutorial – A Simple Echo Program

We are gong to write a simple program that reads from the terminal and writes the data it has read back out to the terminal. As we know from the previous post, reading and writing to the terminal is just a matter of reading and writing to two special files, stdin and stdout. These have file descriptors 0 and 1 respectively. We also need to set aside some space in memory to store the characters we read in from the terminal.

Let’s look at the code!

movq $1, %rax
movq $0, %rbx
int $0x80
.section .data 
.section .bss
.lcomm buffer_data, 500

.section .text

.globl _start
_start:

movq $0, %rax
movq $0, %rdi
movq $buffer_data, %rsi
movq $500, %rdx
syscall

movq $1, %rax
movq $1, %rdi
syscall

movq $60, %rax
movq $0, %rdi
syscall

We have some new syntax here. The second line:

.section .bss

indicates to the assembler that this is the section in which we will define buffers. A buffer is a chunk of contiguous memory that we use to perform input and output operation. The next line:

.lcomm buffer_data, 500

declares a buffer named buffer_data that is 500 byes long. Now we read from the terminal with a usual file I/O kernel interrupt. We set rax to 0 to indicate we are reading form this file and we set rdi to 0 as that is the file descriptor of stdin. We set rsi to the address of our buffer with

movq $buffer_data, %rsi

and we set rdx to 500 to tell the kernel we would like to read 500 bytes. Then we invoke the system call to transfer control to the kernel.

The next three lines set up the system call to write the contents of the buffer to the terminal. The registers rsi and rdx will not have been altered by the kernel, so they still contain the address of the buffer and the number of bytes, 500. We set rax to 1 to indicate that we want to write and rdi to 1 to tell the kernel that it is stdout that we want to write to.

The final three lines are the usual exit with 0. Now if you write this code in a file named echo_input.s and run

as echo_input.s -o echo_input.o
ld echo_input.o -o echo_input

you will have a new binary file named echo input. If you execute this binary, it will wait for you to enter some input and hit the return key. When you do this, it will print what you wrote out again and exit with exit code 0.

Now, in our code, we specified that our buffer is 500 bytes long, and that we should read and write 500 bytes. The read and write operations will handle data smaller than 500 bytes perfectly well. However if you try to pass in a string larger than this, only the first 500 characters will be passed to our echo utility, the shell will try, and probably fail, to execute whatever comes after that.

Leave a Reply

Your email address will not be published. Required fields are marked *