;name: palindrome.asm
;
;description: The program checks if a given string is a palindrome. If no string is passed on
; the commandline a brief message is displayed on how to use the program.
; The string can be any charactersequence and is case sensitive thus Aa is a
; palindrome of aA but not of aa.
;
;build: nasm -felf64 palindrome.asm -o palindrome.o
; ld -melf_x86_64 palindrome.o -o palindrome
;
;usage: ./palindrome string1 string2 .... stringn
bits 64
%include "unistd.inc"
global _start
section .bss
section .data
usage:
.start: db "Palindrome by Agguro.",10
db "usage: palindrome string1 string2 ...",10
.length: equ $-usage.start
txt:
.is: db " is "
.islength: equ $-txt.is
.no: db "not "
.nolength: equ $-txt.no
.yes: db "a palindrome.",10
.yeslength: equ $-txt.yes
section .text
_start:
pop rcx ;argc in RCX
cmp rcx,2 ;is there an argument?
jl .noArguments
pop rax ;pointer to command
dec rcx ;argc - 1 because of command
.repeat:
pop rsi ;get pointer to string
call String.length ;get length of string
mov rdx,rax ;lenght in rdx
call String.write
push rsi
mov rsi,txt.is
mov rdx,txt.islength
call String.write
pop rsi
call Palindrome.check
jnc .isPalindrome
mov rsi,txt.no
mov rdx,txt.nolength
call String.write
.isPalindrome:
mov rsi,txt.yes
mov rdx,txt.yeslength
call String.write
.until:
loop .repeat
jmp Exit
.noArguments:
mov rsi,usage
mov rdx,usage.length
call String.write
jmp Exit
Exit:
syscall exit, 0
Palindrome:
.check:
;RSI has the pointer to a zero terminated string. If the string is a palindrome then the
;subroutine returns with the carryflag cleared, otherwise the carryflag is set.
push rsi
push rdi
push rax
push rcx
;get length of stringz pointed by RSI
call String.length
;pointer to last character of string
mov rdi,rsi
add rdi,rax ;calculate pointer to last character in string
dec rdi
;calculate middle of string
shr rax,1 ;divide rax by 2
mov rcx,rax ;integer part of division in rcx
.repeat:
mov al,byte[rsi] ;read byte RCX from begin of string
mov ah,byte[rdi] ;read byte RCX from end of string
cmp al,ah
jne .noPalindrome
inc rsi ;move pointer to next byte position
dec rdi ;move pointer to previous byte position
dec rcx ;adjust counter
jnz .repeat
clc ;string is palindrome
jmp .done
.noPalindrome:
stc
.done:
pop rcx
pop rax
pop rdi
pop rsi
ret
String:
.length:
; RSI has the pointer to a zero terminated string
; the length will be returned in RAX, all registers except RAX are restored
push rsi ;store used registers
push rcx
xor rcx,rcx ;bytecounter
.repeat:
lodsb ;byte in AL
cmp al,0 ;if 0 then end of string
je .done
inc rcx ;else increment byte counter
jmp .repeat
.done:
mov rax,rcx ;string length in RAX
pop rcx ;restore used registers
pop rsi
ret
.write:
; show a string pointed by RSI and length RDX on STDOUT
; all registers are restored, rcx will be destroyed after the syscall
push rcx
syscall write, stdout
pop rcx
ret