I have a task to write a program in AT&T Assembly which can read and write part by part as long as you want sequence of bytes using Linux’s stdin
and stdout
.
It should be a Caesar cipher scrambler that changes only big Latin characters (A,B,C,D,…) one step forward (so like A to B, B to C, C to D, …, Z to A).
So like the program reads first part of the sequence, do operations to change letters leaving other characters untouched, writes the changed part to stdout, and reads next parts, and do everything again and again.
In the end it should work with files set to stdin and stdout by running the program by command
>./executable >output.txt < input.txt
What I was able to write by now is the program that reads some amount of characters, do operations, prints output and ask for more. However if you put more characters in the input than the buf size it crashes.
Here’s the code:
SYSCALL32 = 0x80
EXIT = 1
ERR_CODE = 0
STDIN = 0
READ = 3
STDOUT = 1
WRITE = 4
BUF_SIZE = 80
.data
textin: .space BUF_SIZE
textout: .space BUF_SIZE
.global _start
_start:
mov $READ, %eax
mov $STDIN, %ebx
mov $textin, %ecx
mov $BUF_SIZE, %edx
int $SYSCALL32 # reading 80 characters (buf_size) of std input
cmp $0, %eax
je exit #if 0 characters read exit
xorl %esi, %esi #clering iterator for loop
loop:
mov textin(%esi), %al #copying 1 character from textin buf to work with
cmp $'\n', %al
je out
cmp $'A', %al
jl skip
cmp $'Z', %al
jg skip
je takeCareOfZ
add $1, %al
jmp skip
takeCareOfZ:
mov $'A', %al
skip:
movb %al, textout(%esi)
incl %esi
jmp petla
out:
mov $WRITE, %eax
mov $STDOUT, %ebx
mov $textout, %ecx
mov $BUF_SIZE, %edx
int $SYSCALL32 #writing 80 characters to std output
jmp _start
exit:
mov $EXIT, %eax
mov $ERR_CODE, %ebx
int $SYSCALL32
Here is a version of the program that removes the complexity associated with using a buffer of fixed size.
.text
.global _start
_start:
# read(STDIN_FILENO, buf, 1)
movl $1, %edx # size_t nbyte
movl $buf, %ecx # void *buf
movl $0, %ebx # int filedes
movl $3, %eax # sys_read
int $0x80
cmp $1, %eax
jne bye # EOF or read() error
cmp $'A', (%ecx)
jl output # *buf < 'A'
cmp $'Z', (%ecx)
jg output # *buf > 'Z'
je z # *buf == 'Z'
incl (%ecx) # *buf >= 'A' && *buf < 'Z'
jmp output
z:
movl $'A', (%ecx)
output:
# write(STDOUT_FILENO, buf, 1)
movl $1, %ebx # int filedes
movl $4, %eax # sys_write
int $0x80
jmp _start
bye:
# exit(0)
movl $0, %ebx # int status
movl $1, %eax # sys_exit
int $0x80
.data
buf:
.byte 0
Sample run
$ gcc -nostdlib -m32 caesar.S -o caesar
$ ./caesar
1234
1234
ABC1
BCD1
Z12BB
A12CC
Sample run using gdb, one instruction at a time.