I am trying to write a program in Assembly x86-64 for an intel 64-bit processor. The program should be compiled with gas (GNU assembler) and run on Linux. The problem is to write a program named lowercase that takes an input string and prints the lowercase of that string. It should be compiled like this:
$> echo "STRING" | ./lowercase
string
$>
I wrote the program but the problem is that it prints spaces infinitely. Who can help me understand why the following code behaves like that?
.section .bss
.comm buf, 1
.section .text
.globl _start
_start:
mov $65, %bh
mov $97, %ch
mov $0, %dh
Loop:
mov $0, %rax # syscall number for read
mov $0, %rdi # where to read from: stdin
mov $buf, %rsi # buffer adr
mov $1, %rdx # length of the buffer in bytes
syscall
cmpb %dh, buf # if read returns 0 (EOF) or less then 0 exit
jle Exit
cmpb %bh, buf # if the character is less than 65 (Char A) print it
jl Write
cmpb %ch, buf # if the charcter is less than 97 make it lowercase
jl ToLowercase
Write:
mov $1, %rax # system call for write
mov $1, %rdi # file handle for stdout
mov $buf, %rsi # address of string to output
mov $1, %rdx # number of bytes
syscall
jmp Loop
ToLowercase:
addb $32, buf # Make the character lowercase
jmp Write # And go back to output it
Exit:
mov $60, %rax # system call for exit
movb $0, %dil # return code
syscall
CodePudding user response:
This line:
cmpb %dh, buf # if read returns 0 (EOF) or less then 0 exit
You modified %rdx (thus %dh) with the count argument to syscall. Also, syscall has no contract to preserve %rdx, so this check is invalid.
Also, the return value from syscall (linux, others) is in %rax, so you are checking an undefined value (%dh) with buf? Something more like
cmp $1, %rax
jlt Exit
would test the return from read. Then you need to see if you are in'A'..'Z':
...
mov buf, %dl
cmp $'A', %dl
jl write
cmp $'Z', %dl
jle ToLowerCase
...