Loop to check lowercase letter in assembly

2019-07-20 10:36发布

问题:

I'm writing a loop as a part of a bigger program that checks if 2nd argument contains any uppercase letter (if yes, program quits). Here's what I have so far. I have marked the section of code I am having problems with.

%include "asm_io.inc"
SECTION .data
err1: db "Incorrect number of command line arguments",10,0
err2: db "2nd argument lenght more than 20",10,0
err3: db "Upper-case letter found!!!",10,0
strt: db "ho",10,0

SECTION .bss
N: resd 1

SECTION .text 
    global  asm_main

asm_main:
   enter 0,0
   pusha

   mov eax, dword [ebp+8]
   cmp eax, dword 2
   jne ERR1

   mov ebx, dword [ebp+12]   ; 24 to 37 calculates the length of 2nd argument
   mov eax, dword [ebx+4]
   mov edi, eax
   sub ecx, ecx
   sub al, al
   not ecx
   cld
   repne scasb
   not ecx 
   dec ecx
   mov eax, ecx
   cmp eax, dword 20
   ja ERR2

   mov [N], dword eax       ;line 39 to 54 makes sure that all letters are lowercase
   call print_int
   mov ebx, N
   call print_int
   mov ebx, dword [ebp+12]
   mov eax, dword [ebx+4]

;------------------------- Code that I am having problems with
LOOP: 
   mov bl, byte[eax]
   cmp bl, 0x61
   jb ERR3
   cmp bl, 0x7A
   jb ERR3
   add eax, 4
   add ecx,1
   cmp ecx, N
   jb LOOP
;---------------------------------------------------------------

   mov eax,  0
   mov eax, strt
   call print_nl
   call print_string
   jmp asm_main_end

 ERR1:
   mov eax, err1
   call print_string
   jmp asm_main_end

 ERR2:
   mov eax, err2
   call print_string
   jmp asm_main_end

 ERR3: 
   mov eax, err3
   call print_string
   jmp asm_main_end

 asm_main_end:
   call print_nl
   popa                  
   leave                     
   ret

But even if my 2nd argument is abcd, the loop still jumps to ERR3. Any ideas what I might be doing wrong? I'm running redhat-linux, nas 2.10.07. Edit: N is the length of the 2nd argument which is correct.

回答1:

I think you are looking for something like:

  xor ecx, ecx   ; Initialize the counter ECX to zero
LOOP:
  mov bl, byte[eax]
  cmp bl, 'A'
  jb .CONT       ; If we are below 'A' we are not a capital, continue to next char
  cmp bl, 'Z'    ; We are >= 'A' here, but we need to check if we are <= 'Z' 
  jbe ERR3       ; If we are <= 'Z' then we must be a capital so Goto ERR3
.CONT:           ; If there was no error we reach here
  inc eax        ; Goto next character
  inc ecx        ; We want to do another loop
  cmp ecx, [N]   ; Compare to what is variable [N], not its pointer
  jbe LOOP       ; Loop while ECX <= N (N = strlen not including nul terminator) 

I've placed comments into the code to explain. This code hasn't been streamlined, I'm trying to produce code in a similar fashion to the code you are currently writing.

The general idea is to compare between the range of 'A' and 'Z'. If we are in that range then we have an error. First compare if we are less than 'A'. If we are we can't be a capital letter, because there are no capitals below 'A' (in the ASCII table). If we were below 'A' we just continue to the next character. If we were not below 'A' we continue checking to see if we are in fact <= 'Z'. If we are then we must be a capital letter and then we produce an error. Otherwise we continue to the next character.


A more advanced method (one I alluded to above) is to subtract 'A' from BL and then compare that to 25('Z'-'A') using unsigned comparison. If BL is below or equal to 25 then BL was a capital letter. The code could have looked like this:

     xor ecx, ecx
   LOOP:
     mov bl, byte [eax]
     sub bl, 'A'              ; Normalize BL
     cmp bl, 'Z'-'A'          ; 'Z'-'A' = 25 (alphabet between 0 and 25 inclusive)
     jbe ERR3                 ; If BL <= 25 (unsigned comparison!) then BL 
                              ; was a capital letter

     inc eax
     inc ecx
     cmp ecx, [N]
     jbe LOOP