HI, Im new to assembly programming.

i know how to enter character and print it, but i dont know how to input string?

can anyone help me? :sad:
Posted on 2010-01-29 18:15:03 by exzibi23
Loop the chars into a buffer, terminate the string and display it.

Special Agent Oso: "Three special steps, that's all you need. Three special steps, and you'll succeed." :)
Posted on 2010-01-29 18:40:22 by JimmyClif
can you show me how?

pls?
Posted on 2010-01-29 19:24:23 by exzibi23
nope... you'll need to show a little effort here...

show your working code so far _then_ add a buffer to it and drop the char (which you have in al) in the buffer.

then we'll go step by step :)
Posted on 2010-01-29 20:45:53 by JimmyClif
JimmyClif left out an important step. Do not overfow the buffer!!!

If you're entering a character at a time and adding it to a buffer, you'll need to think about this. Your OS may provide a string input function, which will probably ask for "maximum to input", which will help with this - just don't ask for more than you provide room for in the buffer! If you're entering a single character sucessfully, I have a pretty good idea which OS that is. Surprisingly (I find it surprising), entering a single character in Linux (and Windows?) is harder than entering a string!

To be sure, why don't you show us how you do a single character? Maybe write comments on how you think you'd put it in a buffer, and move on to put the next one in the next position in the buffer (don't overflow it!). How will you know when the user is done? Where will you check for that? Do you want that character in the string? Don't forget to terminate the string, as JimmyClif points out! Or... it might be useful to return (this is gonna be a subroutine, right?) the number of characters entered...

Writing the comments first can help a lot.

Or you could look for an OS-provided routine...

Best,
Frank

Posted on 2010-01-30 00:06:54 by fbkotler
.model small
.stack
.data
msg1 db "Input Name: $",13,10
fname db 50 dup(?)

.code

main proc

        mov ax, @data
        mov ds,ax

        mov dx, offset msg1
        mov ah,9
        int 21h

        loop1:
        mov bl,0dh
        mov cx,0
        mov ah,1
        int 21h
        cmp al,bl
        je done
        mov ,al
        loop loop1

        done:
        mov ax,@data
        mov ds,ax
        mov dx,offset fname
        mov ax,seg fname
        mov ds,ax

        mov ah,9
        int 21h

        mov ah,4ch
        mov al,0
        int 21h

main endp
end main

Here is whaat ive done.. and i got error..
Posted on 2010-01-30 02:24:51 by exzibi23
Let's examine the loop part:


loop1:
        mov bl,0dh
        mov cx,0
        mov ah,1
        int 21h
        cmp al,bl
        je done
        mov ,al
        loop loop1


Have a seat and read a minute over this page: Asmloops. Ignoring the spelling mistakes I believe whoever wrote it had a you in mind. ;)

Set up cx with the amount of maximum iterations you'd like it to loop before the loop starts.

Also you write the char over and over into the same spot in your buffer. Before you enter the loop put your buffer into ds:di (mov di, offset buffer), write al into and inc the di after every letter.

After you get out of the loop, write one last char into ... the terminator and display it.




Or you could look for an OS-provided routine...


totally :)
Posted on 2010-01-30 09:18:33 by JimmyClif
You might want to mention what error you got, exzibi23. As JimmyClif mentions, you've got problems with the "loop" section. Nice reference to "asmloops"! They don't mention explicitly what happens if cx=0. Loop doesn't execute at all? Nope! Since the "loop" instruction decrements cx first, and then checks for zero, it'll execute the whole 64k times. By setting cx to zero - or any value - inside the loop, you've guaranteed an "infinite loop". But since you've got an exit from the loop, that should actually work okay, even if it isn't "right". Putting every character you get into the first byte in the "fname" buffer is a problem! You want to increment di!

At the beginning of your program, you do "mov ax, @data"/"mov ds, ax" to set ds to your data segment. Correct. Later, you reset ds again. This shouldn't hurt, but since "fname" is in your data segment, you shouldn't need to.

There's a neat instruction, "stosb". which will store al in and increment di all in one go, but there's a catch. "stosb" puts al in es:, not ds:. If, back at the beginning of your program when you had "@data" in ax, you did "mov es, ax" as well as the "mov ds, ax", you would be able to use this instruction. No great advantage to it - it's short (1 byte), and used to be fast in the olden days. Now, it's faster to do "mov , al"/"inc di"... probably even faster to do "add di, 1"... In 32-bit code, this segmented folderol is gone - I don't think anyone misses it! :)

If your error is simply that it's not printing anything, the "inc di" should fix it. If you're hanging forever in the input loop... you must not be checking the exit condition properly. Is "0Dh" correct for dos? In Linux, I'd look for "0Ah" when the victim... I mean "user" hits enter. I forget how dos does it, and I'm too lazy to check. :)

Really a pretty good job, for a "first draft". You'll have it working soon, I predict.

Best,
Frank

Posted on 2010-01-30 15:05:35 by fbkotler
Nice reference to "asmloops"!


Oh, if you had my sources ;) The jealousy !!!
Posted on 2010-01-30 21:34:00 by JimmyClif
sorry for my mistakes.. im just a beginner in assembly.. thanks for those who answer.. :)

check out my code.. my question is, how can i print it?

.model small
.stack
.data
msg1 db "Input Name: $",13,10
fname db 50 dup(?)

.code

main proc

        mov ax, @data
        mov ds,ax

        mov dx, offset msg1
        mov ah,9
        int 21h

        mov di,offset fname

        loop1:
        mov bl,0dh
        mov ah,1
        int 21h
        cmp al,bl
        mov ,al
        inc di
        je done
        jmp loop1

        done:
        mov ax,@data
        mov ds,ax
        mov dx,offset fname
        mov ax,seg fname
        mov ds,ax

        mov ah,9
        int 21h


        mov ah,4ch
        mov al,0
        int 21h

main endp
end main


i remove the loop loop1..

i replace it with jmp loop1.. if the user hits enter, it will terminate.. :)
Posted on 2010-01-30 23:32:35 by exzibi23
Here's my REVISED CODE.. it has no error.. after i press ENTER, it should PRINT the Name.. but nothing is printed..

Here is my Code..

.model small
.stack
.data
msg1 db "Input Name:",13,10,'$'
msg2 db "My Name is:",13,10,'$'
fname db 50 dup(?)

.code

main proc

        mov ax, @data
        mov ds,ax

        mov dx, offset msg1
        mov ah,9
        int 21h

        mov cx,2
        mov di,0
        mov di, offset fname

        loop1:
        mov ah,01h
        mov bh,0dh
        cmp bh,al
        je done
        mov ,al
        inc di
        int 21h
        jmp loop1

        done:
 
        mov dx,offset msg2

        mov ah,09h
        int 21h


        mov ah,4ch
        mov al,0
        int 21h

main endp
end main


and i want to know why should I use

mov di,0
          mov di, offset fname


mov ,al


what's the purpose of DI? i dont want just to copy the codes from you, and then I use it. NO!. I want to understand WHY and HOW's that happen.. So please.. Teach me.. Thanks..
Posted on 2010-01-31 08:15:30 by exzibi23
The names of the registers have meanings.

The ones with 'x' are the regular registers:
ax - Accumulator
bx - Base
cx - Counter
dx - Data

The 'i' stands for Index register:
si - Source index
di - Destination index

The 'p' stands for Pointer register:
bp - Base pointer
sp - Stack pointer

For various instructions, you cannot choose all the operands. For example, lodsw will always use the si register as the source address, and always load into ax. And stosw will always store ax to the destination address in di.
Therefore it is common to use di when storing data.

As for the mov di, 0, I think that's just a mistake. It has no meaning when di is overwritten with offset fname in the next line.
Posted on 2010-01-31 08:41:22 by Scali
exzibi23,

You wrote code for output of "Input Name:" and program does it.
You wrote code for input of fname and program does it.
You wrote code for output of "My Name is:" and program does it.
You didn't write code for output of fname and program doesn't output it.

Clean up your code, add some comments and you'll see.
Posted on 2010-01-31 09:19:32 by baldr
Yeah! Told you to write comments! :)

Go back to what JimmyClif told you in the first place:

"Loop the chars into a buffer, terminate the string and display it."

Which part have you left out?

Here's your latest(?) main loop...

You can call this label anything, but if you use a "meaningful name" it'll make your code easier to read. Say "what it's for"...

    get_next_char:
;        loop1:
        mov ah,01h ; "get character" subfunction of int 21h
        mov bh,0dh ; character to watch for to end input
        cmp bh,al  ; is user finished yet?

Now you've got a litttle problem. You havent "got" the character yet! You need to do the int 21h before you can compare the character to carriage-return... or store it. Incidentally, you don't have to put 0Dh in a register to do the comparison - "cmp al, 0Dh" would work...

        je done
        mov ,al ; store the character in our buffer
        inc di  ; advance to next location in the buffer

        int 21h  ; call dos - this wants to be done earlier!

;        jmp loop1
    jmp get_next_char ; see, it's all commented! :)

        done:

You might even want to call this "done_getting_input:", but "done:" is pretty clear. Now you need to terminate the string. Zero is a commonly used terminator, but int 21h/9 expects a $-terminated string (this is unusual - you won't see it in other OSen... or even elsewhere in dos!). I'm not sue I've got Tasm syntax right, but I think:

    mov byte ptr , '$' ; terminate the string

; print "my name is"
        mov dx,offset msg2
        mov ah,09h
        int 21h

; uh, was there something else you wanted to do here? :) :) :)

; exit the program
        mov ah,4ch
        mov al,0
        int 21h

Now at this point, the user can enter as much as he likes, and possibly overflow the buffer. Professionals do this. Every new version of (unnamed OS) that comes out has got new "exploits" in it. Often, buffer overruns. Amateurs should not do this!!!

If you were to go back to "loop" instead of "jmp", and load cx with a value *before* the top of you loop, that would prevent it. When you think about what value you want to have in cx before your loop, don't forget that we need one more byte for the '$'!!! Get it working first, if you want, but think about this! If you develop better habits than the "professionals" have got, the world will thank you! (except antivirus vendors) Sorry to be obsessive about this, but it really bugs me that they keep doin' it - year after year, decade after decade. It isn't as if this is a newly discovered problem!

Okay, okay, I'll calm down... To add a little to what Scali said about "why di?"... The rules for addressing in 16-bit code are quite restrictive: an (optional) offset, plus an (optional) index register (si, di), plus an (optional) base register (bx, bp). That's it! In 32-bit code, you can do stuff like   - you'll love it!

Further information about addressing: all x86 addresses involve a segment and an offset. In 32-bit code, the rules are different (we can usually ignore segment registers - whew!) - the segment register value (a "selector") is an index into an array of "descriptors". In 16-bit code, the value in the segment register is multiplied by 16 (shifted left by four) and added to the offset, to find the "linear address". (this is neccessary because a 16-bit register can only hold up to 65535, and that isn't enough memory for HLL programmers :)

The cs register is used to determine where our code can be found. Usually, ds is used to locate our data - but sometimes es. As you might expect, ss is used for the stack. This default behavior can be overwritten. For example, bp is a "base register", but unlike  bx, si, and di, it defaults to using ss. "mov , al" would be a legal way to store our character, but it would go in the stack segment instead of the data segment where we want it. "mov ds:" would work.

Anyway... ya gotta print your string before it'll print. :) This is what makes assembly... not "hard", but "tedious". You've got to tell the CPU every... single... thing! They're just not good at figuring out what we want.

Best,
Frank

Posted on 2010-01-31 12:37:48 by fbkotler
Yeeeepeeee! Thanks for thos who help me.. :)

my program is now working..

.model small
.stack
.data
msg1 db "Input Name:$"
msg2 db "My Name is:$"
crlf db 13,10,'$'
fname db 50

.code

main proc

       mov ax, @data
       mov ds,ax

       mov dx, offset msg1
       mov ah,9
       int 21h

       mov di, offset fname

   loop1:
       mov ah,01h  ;Get Character
       int 21h     ; Call Interrupt, Subfunction 1

       cmp al,0dh  ;Compare if Enter is press
       je done     ;Goto done if Enter is Press
       mov ,al ;store character
       inc di      ;increase di
   jmp loop1

       done:

       mov byte ptr ,'$' ;terminate fname with '$'

       mov dx, offset crlf
       mov ah,09h
       int 21h
 
       mov dx,offset msg2
       mov ah,09h
       int 21h

       mov dx,offset fname
       mov ah,09h
       int 21h

       mov ah,4ch
       mov al,0
       int 21h

main endp
end main


Thanks a lot..  By the Way, what assembler do you use? Im using TASM..
Posted on 2010-01-31 17:31:54 by exzibi23
Yeah... says that in the subject. :) Nasm, here.

Good job! (but you still allow a buffer overrun)

Now that you've figured out what's involved, take a look at int 21h/0Ah...

Best,
Frank

Posted on 2010-01-31 18:01:50 by fbkotler
exzibi23,

fname db 50 dup(?) somehow mutates into fname db 50, thus your buffer for name is 1 byte in length. Definitely buffer overrun. Reorder dbs as shown and you'll see what happens:

msg1 db "Input Name:$"
fname db 50
msg2 db "My Name is:$"
crlf db 13,10,'$'
Posted on 2010-01-31 18:54:45 by baldr
Whoa! Good catch baldr! I didn't notice that. Do you understand the difference, exzibi23? Important, so check it out!

Best,
Frank

Posted on 2010-02-01 01:58:54 by fbkotler
I dont get it.. Is fname db 50 differ from fname db 50 dup(?)??

and whats the purpose of reordering them? I mean, its all the same.. :sad:
Posted on 2010-02-01 03:12:46 by exzibi23
exzibi23,

fname db 50 reserves only one byte. Next one belongs to msg2 if reordered, or to uninitialized memory that follows fname. In your case it belongs to 4-byte padding of data segment, then stack segment (TASM specific), so no harm is done, yet.
Posted on 2010-02-01 03:53:33 by baldr