%include "MY_IO.h" STDIN: EQU 0 SYS_READ: EQU 0 ; const MAX_LENGTH{100} MAX_LENGTH equ 100 segment .data ; main routine prompts prompt db "Enter a phrase: ",0 promptLen equ $ - prompt ; for debugging highBoundary db "Above the array :",0 highLen equ $ - highBoundary lowBoundary db "Below the array :",0 lowLen equ $ - lowBoundary ; for printing the string. StringOutLabel1 db `The string is `,34,0 ; The literal quote messes up my ; editor. a quote is ascii 34. StringOutLen1 equ $ - StringOutLabel1 StringOutLabel2 db 34,0 StringOutLen2 equ $ - StringOutLabel2 StringOutLabel3 db "The string has ",0 StringOutLen3 equ $ - StringOutLabel3 StringOutLabel4 db " characters.",0 StringOutLen4 equ $ - StringOutLabel4 ; int length{MAX_LENGTH} phraseLength dq MAX_LENGTH segment .bss pre resd 1 ; char phrase[MAX_LENGTH] phrase resb MAX_LENGTH post resd 1 segment .text global _start ; Remove all non space characters from the string ; rdi is the address of the string ; rsi is the address of the string length. ; BOTH ARE PASS BY pointer STRIP_STRING: push rbp mov rbp, rsp push r15 ; the lcv push r14 ; base address holder push r13 ; length holder push r12 ; temporary mov r13, rsi mov r14, rdi mov r15, 0 mov r11, 0 ; savePos = 0 ; for (i =0; i < *length) { ; if string[i] >= 'a' and string[i] <= 'z' ; string[savePos] = string[i] ; ++ savePos ; } ; ++i ; } ; *length = savePos STRIP_STRING_TOP: cmp r15, [r13] je STRIP_STRING_DONE mov r12b, [r14+r15] cmp r12b, 'a' ; see Jorgensen page 113 jl STRIP_STRING_BOTTOM cmp r12b, 'z' jg STRIP_STRING_BOTTOM mov [r14+r11], r12b inc r11 STRIP_STRING_BOTTOM: inc r15 jmp STRIP_STRING_TOP STRIP_STRING_DONE: ; save the length of the stripped string mov [r13], r11 pop r12 pop r13 pop r14 pop r15 pop rbp ret ; ; Change all the letters in the word to lower case ; rdi will hold the address of the string ; rsi will hold the length of the string ; ; Note this is a pass by pointer and we will change the contents of the ; string TO_LOWER: push rbp mov rbp, rsp push r15 ; the lcv push r14 ; base address holder push r13 ; length holder push r12 ; temporary mov r13, rsi mov r14, rdi ; i = 0 mov r15, 0 ; i = 0 ; while (i < length) { ; if (string[i] >= 'A' and string[i] <= 'Z') { ; string[i] += 32 ; } ; } TO_LOWER_TOP: ; while i != length mov r12, r15 sub r12, r13 test r12, r12 jz TO_LOWER_LOOP_DONE ; r12b = string[i] ; or base addres of string + offset ; or r14 + r15 mov r12b, [r14+r15] ; if r12b >= 'A' cmp r12b, 'A' jl TO_LOWER_NOT_UPPER ; see Jorgensen page 113 ; and r12B =< 'Z' cmp r12b, 'Z' jg TO_LOWER_NOT_UPPER ; r12b += 32 add r12b, 32 mov [r14+r15], r12b TO_LOWER_NOT_UPPER: ; i++ inc r15 jmp TO_LOWER_TOP TO_LOWER_LOOP_DONE: ; all done, clean up. pop r12 pop r13 pop r14 pop r15 pop rbp ret ; ; the purpose of this function is to print values from either side of the ; array to make sure we have not overwritten them. BOUNDARY_CHECK: mov rdi, highBoundary mov rsi, highLen call PRINT_STRING mov rdi, [post] call PRINT_INT call PRINT_NEWLINE mov rdi, lowBoundary mov rsi, lowLen call PRINT_STRING mov rdi, [pre] call PRINT_INT call PRINT_NEWLINE ret ; This function will print a string ; rdi will hold the base address of the string ; rsi will hold the length of the string PRINT_STRING_INFO: push rbp mov rbp, rsp push r14 ; base address holder push r13 ; length holder ; save the register values so I can call functions with them mov r13, rsi mov r14, rdi mov rdi, StringOutLabel1 mov rsi, StringOutLen1 call PRINT_STRING mov rdi, r14 mov rsi, r13 call PRINT_STRING mov rdi, StringOutLabel2 mov rsi, StringOutLen2 call PRINT_STRING call PRINT_NEWLINE mov rdi, StringOutLabel3 mov rsi, StringOutLen3 call PRINT_STRING mov rdi, r13 call PRINT_INT mov rdi, StringOutLabel4 mov rsi, StringOutLen4 call PRINT_STRING call PRINT_NEWLINE ; put the stack back and exit. pop r13 pop r14 pop rbp ret _start: ; just to see if we overflow or not. mov dword [pre], 999 ; note that the dword is needed, ; the assembler does not know the size of the ; destination. mov dword [post], 999 ; byte, word, dword, qword ; jorgensen page 132 call BOUNDARY_CHECK ; cout << "Enter a phrase: " mov rdi, prompt mov rsi, promptLen ; note this is not a memory operation. call PRINT_STRING ; cin >> phrase mov rdi, STDIN mov rsi, phrase mov rax, SYS_READ mov rdx, MAX_LENGTH syscall ; rax holds the length, but this includes the newline ; decrement by 1 and save sub eax, 1 ; I marked phraseLength as a 32 bit word, so save the 32 bit register ; I am sloppy with register names, probably should be more careful mov [phraseLength], eax ; cout << endl; call PRINT_NEWLINE ; print information about the string. mov rdi, phrase ; I wasn't careful and was doing a ; mov rsi, rax ; why was this a bug? mov esi, [phraseLength] call PRINT_STRING_INFO call PRINT_NEWLINE ; phrase = ToLowerPhrase(phrase, length) mov rdi, phrase mov esi, [phraseLength] call TO_LOWER ; cout << phrase mov rdi, phrase mov esi, [phraseLength] call PRINT_STRING_INFO call PRINT_NEWLINE ; phrase = StripString(phrase, &length) mov rdi, phrase mov esi, phraseLength call STRIP_STRING ; cout << phrase mov rdi, phrase mov esi, [phraseLength] call PRINT_STRING_INFO call PRINT_NEWLINE ; check for overflow; call PRINT_NEWLINE call BOUNDARY_CHECK ; exit mov eax, SYS_EXIT mov edx, SUCCESS syscall