Author Topic: need help with an exercise  (Read 10213 times)

Offline hdwrx

  • New Member
  • Posts: 1
need help with an exercise
« on: June 26, 2014, 03:44:16 PM »
Hi,
Im a new guy here on the forum and i need some help with nasm assembly for an exam.
Well what i need to do is create a program with a string with the size of 20 character and i have to count the number of occurrences of a word for example "a"
the code i have already is this:
Code: [Select]
section .data

str: dw "vitor hugo sousa",10,0
str2: dw 't'
tam_str equ 16
i: dd 1

section .bss


section .text

global main
main:


mov esi, str
mov edi, str2
cmpsb
je igual

mov ecx, str
lea ecx, [ecx+1]
mov ecx, [i]
inc ecx
mov [i], ecx


igual:

mov eax, 4
mov ebx,1
mov ecx,str
mov edx,tam_str
int 80h
jmp sair


sair:
mov eax,1
mov ebx,1
int 80h

Can someone help me?
thanks a lot.
cheers

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: need help with an exercise
« Reply #1 on: June 26, 2014, 08:05:44 PM »
Hi hdwrx,

Welcome to the Forum. We won't do your homework (exam) for you, but we will help you with it. The general rule is "the more they give us, the more we'll give them". You give us your "code so far", so we've got something we can work with.

The first thing is to understand the "specification" ("assignment" in this case). You seem to need a string of 20 characters. You have a string, but it isn't 20 characters. Perhaps that's the maximum?

The word "word" is a little ambiguous in assembly language. It could mean a "text unit" like "hello" or it could mean a 16 bit quantity. (it could also mean "native machine word size" which would be 32-bits, but to Nasm it means 16 bits) I'm guessing what you need is the number of occurances of a character ('t' in this case) in your string. Just trying to make sure I understand the "specification". Correct me if I'm wrong.

Let's look at what your code does (comments added but I've left your code alone).
Code: [Select]
section .data

str: dw "vitor hugo sousa",10,0
; you might want to declare this "db", not "dw"
; won't do much harm.

str2: dw 't'
; likewise.

tam_str equ 16
; this constant appears to be the length of your string,
; not counting the linefeed or the zero

i: dd 1
; I guess this is "count".

section .bss


section .text

global main
main:


mov esi, str ; address of str
mov edi, str2 ; address of str2 (our character)
cmpsb
; this compares the byte at [esi] with the byte at [edi]
; and increments both esi and edi.
; you probably do want to advance through "str"
; but probably not "str2" (we'll move past our character)

je igual
; these won't be equal (first time)
; so the jump is not taken
; we fall through to...

mov ecx, str ; address of str
lea ecx, [ecx+1] ; add one to it

; but then we overwrite ecx!
; fortunately, we didn't need it.
mov ecx, [i] ; 1, initially
inc ecx ; increment it to 2
mov [i], ecx ; and put it back in [i]
; you could also do the same thing with
; inc dword [i]

; we get here whether it was equal or not
igual:

mov eax, 4 ; sys_write
mov ebx,1 ; stdout
mov ecx,str ; address of str
mov edx,tam_str ; length of str - not counting linefeed
int 80h ; do it
jmp sair
; you don't really need this jump
; we're there anyway.
; won't do any harm.

sair:
mov eax,1 ; sys_exit
mov ebx,1 ; exit code - why 1?
int 80h  ; do it

As you can see, this doesn't really do what you want (yet). "cmpsb" is a nice short instruction - intended to compare two strings, a byte at a time. You could use it and "dec edi" each time - so edi continues to point to our one character.

Another handy "string instruction" is "lodsb". It loads a single character from [esi] into al, and increments esi to point to the next character. Doesn't do anything to edi - which might be what you want...
Code: [Select]
lodsb
cmp [edi], al
; or cmp [str2], al - and don't use edi at all
Now... what do we want to do if it's equal? What do we want to do if it's not equal? Seems to me that if it's not equal, we just want to go on to the next character. If it is equal, we want to increment our "count" () and them go on to the next character... until we get to the end of the string. Don't forget to exit the loop when we get to the end of the string, or it'll try to go on forever - eventually running into memory we don't "own", causing a segfault! Your string is zero-terminated, so you might look for that. Or you might look for the linefeed. You don't really need the zero terminator - sys_write won't pay any attention to it (it prints edx characters, regardless) and sys_read (if\when you get to it) won't give you a zero-terminated string (unless you take steps to make it so) but it will be linefeed-terminated. So you might be better off to look for the linefeed...

I imagine you'll want to display the count when you're done. This is the "how do I display a number?" question. We can get to that, but here's a "trick" for ya. We can display the exit code by typing "echo $?" after the program exits. If you exit with something like...
Code: [Select]
    mov eax, 1 ; sys_exit
    mov ebx, [i] ; make count the exit code
    int 80h
you can keep an eye on how you're doing as you go along. Worry about displaying it later. Holler if you need more help.

Best,
Frank