Assembly Program to handle Escape Characters
<p>edit 10/2/16 - it's no longer segfaulting but the lowercase characters are not converting - here's what I changed in the lowercase label:</p>

<pre><code>lowercase:
        cmp     ax, 'a'                  ; is it a?
        jb      slashprint               ; jump out if it's below a
        cmp     ax, 'z'                  ; is it z?
        ja      slashprint               ; jump out if it's above z
        mov     eax, [esi]               ; move the char to eax to index
        mov     ebx, mappings            ; point to the mappings array
        sub     eax, 97                  ; convert the lower case letter to decimal
        mov     ax, [ebx + eax]          ; indexed addressing done here
        jmp     done  
</code></pre>

<p>I'm working on a program that will allow me to take a string from a user, detect escape sequences and properly output the converted message. I know already that I need to clean up some of the logic inside the subroutine handle_ESC but I'm attempting to test and debug one situation at a time. My issue is that every time I return from the subroutine and go to add the character I modified to the new string stored in edi (on the first line of label L1_cont), I get a segfault. So far I've just been focused on getting it to accept the lower case escape sequences. edit: changed a few things around. Now I'm not segfaulting when typing 2 slashes, but it also doesn't do what I want it to do. It doesn't print anything. Still segfaulting when looking at a lowercase letter from the same line. With the changes I made it should never reach that instruction.</p>

<pre><code>%define STDIN 0
%define STDOUT 1
%define SYSCALL_EXIT  1
%define SYSCALL_READ  3
%define SYSCALL_WRITE 4
%define BUFLEN 256


        SECTION .data                   ; initialized data section

msg1:   db "Enter string: "             ; user prompt
len1:   equ $-msg1                      ; length of first message

msg2:   db "Original: "                 ; original string label
len2:   equ $-msg2                      ; length of second message

msg3:   db "Convert:  "                 ; converted string label
len3:   equ $-msg3

msg4:   db 10, "Read error", 10         ; error message
len4:   equ $-msg4

msg5:   db 10, "Error: unknown escape sequence", 10 ; unknown escape error (not sure this works)
len5:   equ $-msg5

msg6:   db 10, "Error: octal value overflow!", 10 ; overflow error
len6:   equ $-msg6

; Declare the array using mappings.
mappings: db 7, 8, -1, -1, -1, 12, -1, -1, -1, -1, -1, -1, -1, 10, -1, -1, -1, 13, -1, 9, -1, 11, -1, -1, -1, -1


        SECTION .bss                    ; uninitialized data section
buf:    resb BUFLEN                     ; buffer for read
newstr: resb BUFLEN                     ; converted string
rlen:   resb 4                          ; length


        SECTION .text                   ; Code section.
        global  _start                  ; let loader see entry point

_start: nop                             ; Entry point.
start:                                  ; address for gdb

        ; prompt user for input
        ;
        mov     eax, SYSCALL_WRITE      ; write function
        mov     ebx, STDOUT             ; Arg1: file descriptor
        mov     ecx, msg1               ; Arg2: addr of message
        mov     edx, len1               ; Arg3: length of message
        int     080h                    ; ask kernel to write

        ; read user input
        ;
        mov     eax, SYSCALL_READ       ; read function
        mov     ebx, STDIN              ; Arg 1: file descriptor
        mov     ecx, buf                ; Arg 2: address of buffer
        mov     edx, BUFLEN             ; Arg 3: buffer length
        mov     [ecx + edx], byte 0     ; null terminate the read buffer
        sub     edx, 1                  ; make sure the buffer length is 1 less than BUFLEN
        int     080h

        ; error check
        ;
        mov     [rlen], eax             ; save length of string read
        cmp     eax, 0                  ; check if any chars read
        jg      read_OK                 ; &gt;0 chars read = OK
        mov     eax, SYSCALL_WRITE      ; ow print error mesg
        mov     ebx, STDOUT
        mov     ecx, msg4
        mov     edx, len4
        int     080h
        jmp     exit                    ; skip over rest
read_OK:


        ; Loop for iterating over string

L1_init:
        mov     esi, buf                ; point to start of buffer
        mov     edi, newstr             ; point to start of new string
        mov     bx, [mappings]          ; point to the mappings array

L1_top:
        mov     al, [esi]               ; get a character
        inc     esi                     ; point to the next character
        cmp     al, '\'                 ; is current char a backslash?
        je      escapectrl              ; if so, run the subroutine
        jmp     L1_cont                 ; if not, jump to L1_cont and add the char

escapectrl:
        call    handle_ESC              ; run subroutine
        inc     edi
        cmp     [esi], byte 0
        je      L1_end
        jmp     L1_top

L1_cont:
        mov     [edi], al               ; store char in new string
        inc     edi                     ; update dest pointer
        cmp     [esi], byte 0           ; if not null, keep looping
        je      L1_end                  ; end loop if null
        jmp     L1_top                  ; loop if there are more chars



L1_end:


        ; print out user input for feedback
        ;
        mov     eax, SYSCALL_WRITE      ; write message
        mov     ebx, STDOUT
        mov     ecx, msg2
        mov     edx, len2
        int     080h

        mov     eax, SYSCALL_WRITE      ; write user input
        mov     ebx, STDOUT
        mov     ecx, buf
        mov     edx, [rlen]
        int     080h

        ; print out converted string
        ;
        mov     eax, SYSCALL_WRITE      ; write message
        mov     ebx, STDOUT
        mov     ecx, msg3
        mov     edx, len3
        int     080h

        mov     eax, SYSCALL_WRITE      ; write out string
        mov     ebx, STDOUT
        mov     ecx, newstr
        mov     edx, [rlen]
        int     080h


        ; final exit
        ;
exit:   mov     eax, SYSCALL_EXIT       ; exit function
        mov     ebx, 0                  ; exit code, 0=normal
        int     080h                    ; ask kernel to take over

        ; Subroutine begins here.

handle_ESC:

        mov     di, [esi]               ; take a copy of the current char
        inc     esi                     ; point to the next char

        cmp     di, '7'                 ; is it above 7?
        ja      lowercase               ; if so, skip octal check

        cmp     di, '0'                 ; is it below zero?
        jb      lowercase               ; if so, skip octal check

octalinit:
        mov     bl, 0                   ; holds the total for the digit
        mov     cl, 3                   ; count for how many times the loop should run if it's octal
        mov     dh, 8                   ; holds the octal multiple

octalloop:
        mov     ah, [di]                ; store the new char in ah for operations
        sub     ah, 48                  ; convert char to integer
        mul     dl                      ; multiply the octal value by 8
        add     ax, dx                  ; update the total value
        mov     di, [esi]               ; store the next character in di for consideration
        inc     esi                     ; point to the character after that
        cmp     di, '0'                 ; is it below 0?
        jb      lowercase               ; if below, jump out
        cmp     di, '7'                 ; is it above 7?
        ja      lowercase               ; if above, jump out
        dec     cl                      ; count down
        jnz     octalloop               ; loop if needed
        dec     esi                     ; undo the prefetch if no longer looping
        jo      octaloverflow           ; if the overflow flag was set, handle the overflow
        mov     al, bl                  ; stores the finalized value in al
        jmp     done                    ; exit


octaloverflow:
        mov     [edi], byte 32          ; makes the second char blank due to error
        jmp     done                     ; not sure if this part is gonna work right

lowercase:
        cmp     di, 'a'                  ; is it a?
        jb      slashprint               ; jump out if it's below a
        cmp     di, 'z'                  ; is it z?
        ja      slashprint               ; jump out if it's above z
        sub     di, 97                   ; convert the lower case letter to decimal
        mov     cl, [bx + di]            ; indexed addressing done here
        cmp     cl, -1                   ; is it -1?
        mov     [edi], cl                ; store the converted char in the string
        inc     esi                      ; point to the spot after
        inc     edi                      ; point to the next entry in the new string
        mov     [edi], byte 32           ; add a blank space in the new string where the lowercase letter was
        jmp     done                  

slashprint:
        cmp     di, '\'                  ; is it another slash?
        jne     errormsg                 ; jump and print an error message
        mov     [edi], byte 92           ; store a slash in the new string
        inc     edi                      ; move to the next position of the new string
        mov     [edi], byte 32           ; make the second char blank since both are slashes
        jmp     done                     ; return

errormsg:
        inc     esi                     ; skip over the character after the slash


done:
        ret

         ; end Subroutine.
</code></pre>