Created
July 6, 2019 16:28
-
-
Save sertraline/58132e63af8a7dc40dec4b80092f4b14 to your computer and use it in GitHub Desktop.
NASM: find odd and even characters in the string, save and print them
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; NASM i386 | |
; nasm -f elf print_odd_even.asm | |
; ld -m elf_i386 print_odd_even.o -o print_odd_even | |
; | |
; EXAMPLE | |
; bash# ./print_odd_even | |
; Enter the string: The quick brown fox jumps over the lazy dog | |
; Odd: | |
; Teqikbonfxjmsoe h aydg | |
; Even: | |
; h uc rw o up vrtelz o | |
; | |
; Your input: | |
; The quick brown fox jumps over the lazy dog | |
SECTION .bss ; non-initialized variables | |
inp: resb 255 ; user input | |
out_o: resb 255 ; out_odd | |
out_e: resb 255 ; out_even | |
SECTION .data | |
msg db "Enter the string: ", 0h | |
msg1 db "Odd: ", 0Ah, 0h | |
msg2 db "Even: ", 0Ah, 0h | |
msg3 db "Your input: ", 0Ah, 0h | |
SECTION .text | |
global _start | |
_start: | |
mov eax, msg | |
call stprint ; print the greeting message | |
mov edx, 255 ; - take 255 characters from user input | |
mov ecx, inp ; | ecx accepts address of the variable to store input | |
mov ebx, 0 ; | ebx, 0 == write to STDIN file | |
mov eax, 3 ; | eax, 3 == SYS.READ | |
int 80h ; - kernel interrupt | |
call findeven ; the function itself | |
mov eax, msg1 ; print 1st message ("Odd: ") | |
call stprint | |
mov ecx, out_o ; - print OUT_O (out_odd) data | |
mov edx, 254 ; | which contains odd characters | |
mov ebx, 1 ; | ebx, 1 == write to STDOUT | |
mov eax, 4 ; | eax, 4 == SYS.WRITE | |
int 80h ; - edx contains size of the variable | |
; ^ we know the exact size of the variable (255 characters) so we won't call stprint | |
; function for out_o and out_e variables, it is unnecessary. | |
push 0Ah ; - | |
mov eax, esp ; | print 0Ah | |
call stprint ; | (newline character, '\n') | |
add esp, 4 ; - | |
mov eax, msg2 ; print 2nd message ("Even: ") | |
call stprint | |
mov ecx, out_e ; print OUT_E (out_even) data | |
mov edx, 254 ; same as above. | |
mov ebx, 1 | |
mov eax, 4 | |
int 80h | |
push 0Ah ; - | |
mov eax, esp ; | print 0Ah | |
call stprint ; | (newline character, '\n') | |
add esp, 4 ; - | |
mov eax, msg3 ; print 3rd message ("Your input: ") | |
call stprint | |
mov eax, inp | |
call stprint ; print original string (user input) | |
mov ebx, 0 ; exit | |
mov eax, 1 | |
int 80h | |
findeven: | |
push eax ; preserve some registers | |
push esi | |
push ebx | |
mov esi, -1 ; initialize counter with -1, since it will be increased immediately. | |
mov eax, inp ; move user input string to eax | |
.iterstring: | |
inc esi ; counter += 1 | |
cmp byte [eax+esi], 0 ; eax contains original line (input) | |
jz .finish ; if line ends with zero (end of the line) -> finish | |
test esi, 1 ; else check if counter is odd/even | |
; 'test, 1' instruction masks off all bits of a value in the register | |
; except for the least significant bit (the far right bit). | |
; | |
; 00000011 equals 3 in binary. | |
; test 00000011, 1 will give us 00000001. | |
; | |
; 00000100 equals 4 in binary. | |
; test 00000100, 1 will give us 00000000. | |
; | |
; Least significant bit is always 0 if it's even number, and always 1 if it's odd number. | |
; | |
; The value of comparison (binary AND) is stored in the zero flag register. | |
; JZ (jump zero) instruction jumps to the pointed address if zero flag register | |
; contains zero, and does nothing if ZF contains anything else. | |
jz .itsodd ; if character is odd (zero flag set), jump to .itsodd | |
; Here we jump to .itsodd if zero flag is set, however zero flag is set by 'test' if the value is EVEN. | |
; Our counter is EVEN while the character it points to is ODD. | |
; Hence why we reverse that: computers start counting from 0, but as humans we start counting from 1. | |
jmp .itseven ; if even, jump to .itseven | |
.itseven: | |
push ebx ; preserve ebx on the stack | |
mov ebx, 0 ; initialize ebx | |
mov bl, byte [eax+esi] ; move single byte to bl (lower ebx) | |
mov byte [out_e+esi], bl ; move bl to the corresponding memory location of OUT variable | |
pop ebx ; restore ebx | |
jmp .iterstring ; continue loop | |
; So let's assume we have 'line' as an input string. 'i' and 'e' are even. | |
; We're taking byte [line+counter]: | |
; byte [line+0] contains 'l' | |
; byte [line+1] contains 'i' | |
; and so on. 'i' is even, so program should move it to [out+counter]. | |
; If we would use [out] without counter we would replace the very first character | |
; with a new one. | |
.itsodd: | |
push ebx ; same as above | |
mov ebx, 0 | |
mov bl, byte [eax+esi] | |
mov byte [out_o+esi], bl | |
pop ebx | |
jmp .iterstring | |
.finish: | |
pop eax | |
pop esi | |
pop ebx | |
ret | |
stprint: | |
push edx ; string print function, taken from | |
push ecx ; asmtutor.com | |
push ebx | |
push eax | |
call stlen | |
mov edx, eax | |
pop eax | |
mov ecx, eax | |
mov ebx, 1 | |
mov eax, 4 | |
int 80h | |
pop ebx | |
pop ecx | |
pop edx | |
ret | |
stlen: | |
push ebx | |
mov ebx, eax | |
nextch: | |
cmp byte [eax], 0 | |
jz finish | |
inc eax | |
jmp nextch | |
finish: | |
sub eax, ebx | |
pop ebx | |
ret |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment