0

I'm trying to check if a certain char shows up in a string. If it does, I want to update a counter, then eventually print that counter.

For example, if my comparison char is "a", and I'm checking the string "haha", I should have a counter with the value 2.

From my understanding, we want to load the address of the string into a register, check the memory location (a Byte) at that address against a comparison char, then increment the address to look at the next Byte. And so on.

I've spent hours on this problem. I feel I'm on the right track (I hope), but a little guidance on how to (re-)think this problem would be wonderful.

My biggest issue, so far that I can understand, is comparing a single char from my string to my comparison char, which is "a". I'm struggling with the interaction rules, as it were, between registers -- what can be moved to what, and so on.

Thanks kindly for considering my question.

Here's my code so far:

SECTION .data               ; Initialize data
    cmp_char db "a", 0h
    word1    db "harp", 0h
    word2    db "haha" , 0h

SECTION .text
    global _start           ; Initialize starting point for program

_start:                     ; Program entry point
    jmp check_for_vowel     ; Jumps to "check_for_vowel" function

check_for_vowel:
    push EDX                ; Preserve EDX on the stack; restore after function runs
    push ECX                ; Preserve ECX on the stack; restore after function runs
    push EBX                ; Preserve EBX on the stack; restore after function runs
    push EAX                ; Preserve EAX on the stack; restore after function runs

    mov EDX, 0              ; Initialize char counter

    mov AH, [cmp_char]      ; Load value of "cmp_char" into AH, an 8-bit subsection of EAX
    mov EBX, word1          ; Move address of word1 to EBX.

loop_counter:
    mov AL, Byte [EBX]      ; Move value of BX into AL, an 8-bit subregister of EAX
    cmp AL, 0h              ; Check if value in AL is 0...
    jz finished             ; ... and if it is, jump to "finished" function.

    cmp AL, AH              ; Else, compare the Bytes in AL and AH...
    jz match                ; ... and if they match, jump to the "match" function.
    
    inc ECX                 ; Otherwise, increment the loop counter...
    inc EBX                 ; ... and loop to the next character in the string...
    jmp loop_counter        ; ... and start the loop over again.

match:
    inc EDX                 ; Increment the char counter.
    inc EBX                 ; Loop to the next character in the string.
    jmp loop_counter        ; Jump back to the loop_counter.

finished:
    ret

Edit 1: fix -- incremented EBX under "loop_counter"; originally EX.

  • You want `inc EBX` not `inc BX`. The comparison itself is fine. – Jester Nov 20 '22 at 22:43
  • Thank you, @Jester. I'll give that a try. Appreciate the reply. – user14178703 Nov 21 '22 at 02:05
  • Okay, I made that change, but I'm receiving a "Command terminated by signal 11". I suspect I'm doing something wrong in the loop_counter, but I'm not sure what. For reference, I'm testing this on JDoodle's online NASM compiler: https://www.jdoodle.com/compile-assembler-nasm-online/ – user14178703 Nov 21 '22 at 02:12
  • There's your problem. You need a dev environment with a debugger that lets you single-step and watch register values change. And so you can see which instruction faults if there is a segfault. As you've found out, writing asm without that (especially as a beginner) is very slow going and full of difficult guesswork. I don't know of any 32-bit x86 NASM online IDEs; https://onlinegdb.com/ has x86-64 GAS where you could use `.intel_syntax noprefix`, but 64-bit mode uses 64-bit pointers so you couldn't use this code. Best to set up a Linux VM or emulator locally. – Peter Cordes Nov 21 '22 at 08:18
  • You have 4 pushes that you never pop, and you try to `ret` from `_start` which can't work. [Nasm segmentation fault on RET in \_start](https://stackoverflow.com/q/19760002) – Peter Cordes Nov 21 '22 at 08:20
  • BTW, to do this *efficiently* for longer strings / buffers, you'd want to count 16 or 32 bytes in parallel, as with [How can I count the occurrence of a byte in array using SIMD?](https://stackoverflow.com/a/49568584) / [How to count character occurrences using SIMD](https://stackoverflow.com/q/54541129) – Peter Cordes Nov 21 '22 at 08:22
  • Thank you, @PeterCordes, for your detailed reply. I’ll review and adjust based on your input. Thanks kindly. – user14178703 Nov 21 '22 at 16:37
  • If this was Amstrad CPC you could `ret` back to BASIC, unfortunately this isn't. Chances are you're using Linux, Windows, or MS-DOS, and so you'll need the proper `int` code (not to be confused with the `int` data type in C) to exit your program. As for your actual program logic, it seems fine, just a bit slow (there's a more efficient way to do what you're trying to do but you can learn about it in due time.) – puppydrum64 Nov 23 '22 at 15:53

0 Answers0