简体   繁体   中英

Input a string of characters and output to uppercase

I'm trying to write a program which will convert a lowercase string of characters to uppercase, using a buffer to store the initial string. The problem that I'm experiencing is that my program will print out an infinite loop of characters which have to resemblence to the string I've given it.

Other problems that I believe exist in the code are as follows:

  • Some subroutines use ret at the end of the call. The problem that I'm having trouble with is figuring out which of these subroutines do not actually need a ret , and are better used with jmp . To be honest, I'm a little confused here between the semantics of the two. For example, does a subroutine called with ja need to be ret 'ed at the end of the call?

  • I'm also trying to print out the number of iterations that occur within each iteration of the loop used to convert the values. For whatever reason, I'll inc the counter and resolve to print it with a PrintNumIter routine, which, alas, doesn't do anything unfortunately.

The complete program is as follows.

Codez

bits 32

[section .bss]

        buf: resb 1024                  ;allocate 1024 bytes of memory to buf

[section .data]

        ;*************
        ;* CONSTANTS *
        ;*************

        ;ASCII comparison/conversion

        LowercaseA:     equ 0x61
        LowercaseZ:     equ 0x7A
        SubToUppercase: equ 0x20

        ;IO specifiers/descriptors

        EOF:            equ 0x0

        sys_read:       equ 0x3
        sys_write:      equ 0x4

        stdin:          equ 0x0
        stdout:         equ 0x1
        stderr:         equ 0x2

        ;Kernel Commands/Program Directives

        _exit:          equ 0x1
        exit_success:   equ 0x0
        execute_cmd:    equ 0x80

        ;Memory Usage

        buflen:         equ 0x400   ;1KB of memory


        ;*****************
        ;* NON-CONSTANTS *
        ;*****************

        iteration_count:    db 0
        query :             db "Please enter a string of lowercase characters, and I will output them for you in uppercase ^.^: ", 10   
        querylen :          equ $-query

[section .text]

    global _start
;===========================================
;             Entry Point
;===========================================

_start:
        nop                                         ;keep GDB from complaining
        call    AskUser 
        call    Read
        call    SetupBuf
        call    Scan
        call    Write
        jmp     Exit

;===========================================
;           IO Instructions
;===========================================

Read:
        mov     eax, sys_read                       ;we're going to read in something
        mov     ebx, stdin                          ;where we obtain this is from stdin
        mov     ecx, buf                            ;read data into buf
        mov     edx, buflen                         ;amount of data to read

        int     execute_cmd                         ;invoke kernel to do its bidding
        ret

Write:
        mov     eax, sys_write                      ;we're going to write something
        mov     ebx, stdout                         ;where we output this is going to be in stdout
        mov     ecx, buf                            ;buf goes into ecx; thus, whatever is in ecx gets written out to
        mov     edx, buflen                         ;write the entire buf

        int     execute_cmd                         ;invoke kernel to do its bidding
        ret

AskUser:
        mov     eax, sys_write
        mov     ebx, stdout
        mov     ecx, query
        mov     edx, querylen   

        int     execute_cmd
        ret

PrintNumIter:
        mov     eax, sys_write
        mov     ebx, stdout
        push    ecx                                 ;save ecx's address
        mov     ecx, iteration_count                ;print the value of iteration_count
        mov     edx, 4                              ;print 4 bytes of data

        int     execute_cmd
        pop     ecx                                 ;grab the value back in
        ret
;===========================================
;           Program Preperation
;===========================================

SetupBuf:
        mov     ecx, esi                        ;place the number of bytes read into ecx
        mov     ebp, buf                        ;place the address of buf into ebp
        dec     ebp                             ;decrement buf by 1 to prevent "off by one" error
        ret                                         

;===========================================
;           Conversion Routines     
;===========================================

ToUpper:
        sub     dword [ebp + ecx], SubToLowercase   ;grab the address of buf and sub its value to create uppercase character


Scan:
        call    PrintNumIter                        ;print the current iteration within the loop

        cmp     dword [ebp + ecx], LowercaseA       ;Test input char against lowercase 'a'
        jb      ToUpper                             ;If below 'a' in ASCII, then is not lowercase - goto ToLower

        cmp     dword [ebp + ecx], LowercaseZ       ;Test input char against lowercase 'z'
        ja      ToUpper                             ;If above 'z' in ASCII, then is not lowercase - goto ToLower

        dec     ecx                                 ;decrement ecx by one, so we can get the next character
        inc     byte [iteration_count]              ;increment the __value__ in iteration count by 1
        jnz     Scan                                ;if ecx != 0, then continue the process
        ret

;===========================================

;Next:
;       dec     ecx                             ;decrement ecx by one
;       jnz     Scan                            ;if ecx != 0 scan
;       ret

;===========================================

Exit:
        mov     eax, _exit
        mov     ebx, exit_success

        int     execute_cmd

Your problem is directly attributed to the fact that you never append a nul terminator to the end of your string buffer once you are done processing it (from what I remember, the read syscall doesn't read back a null).

unfortunately this is a little bit harder to do due to your odd control flow, but changing SetupBuf should do the trick (note, you should probably check that you haven't overflowed buf , but with 1KB, I doubt you'd need to worry for a learning program):

SetupBuf:
        mov     ecx, esi                        
        mov     ebp, buf
        mov     [ebp+ecx],0  ;make sure the string is nul terminated            
        dec     ebp                             
        ret

Just note

On to another issue that seems to plague your code (which you have aptly noticed), your odd control flow. So simple guidelines (note: not rules, just guidelines) that hopefully help you on your way to less spagetti code:

  • JMP (and the conditional jumps) should only be used to go to lables in the same procedure, else you start getting in a bind because you cannot unwind back. the only other time you can use jumps is for tail-calls, but at this stage you shouldn't worry about that, its more confusion.

  • Always use CALL when you are going to another procedure, this allows you to return to the call site correctly with the RETN / RET instruction, making the control flow more logical.

A simple example:

print_num: ;PROC: num to print in ecx, ecx is caller preserved
    push ecx
    push num_format ; "%d\n" 
    call _printf
    sub esp,8 ;cleanup for printf
    retn

print_loop_count: ;PROC: takes no args
    mov ecx,0x10 ;loop 16 times

do_loop: ;LABEL: used as a jump target for the loop
         ;good idea to prefix jump lables with "." to differentiate them
   push ecx ;save ecx
   call print_num ;value to print is already in ecx
   pop ecx ;restore ecx
   dec ecx
   jnz do_loop ;again?

   retn

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM