Assembly print a string - string

I'm having a problem printing a string which I read from the keyboard, if the string is the maximum length then it works but if I enter only 3 characters for example I got a blank black space, this is the code:
assume cs:code,ds:data
data segment
sir db 12 dup (?),'$'
mesaj db "Who`s your daddy?",13,10,"$"
data ends
code segment
start:
mov ax,data
mov ds,ax
mov dx,offset mesaj
mov ah,09h
int 21h
mov bx,offset sir
mov sir[0],11
mov dx,bx
mov ah,0ah
int 21h
mov dx,offset sir
mov ah,09h
int 21h
mov ah,01h
int 21h
mov ax,4c00h
int 21h
code ends
end start

If you change your sir db 12 dup (?), '$' to sir db 12 dup('$'),'$', and your mov dx, offset sir to mov dx, offset sir + 2 as someone else has suggested in comments, your code should work.
However, if you want to see the results clearly, you will need to print some newline characters.
This is because the 0ah routine (string input):
echoes your input to the terminal, including the carriage return (0dh) it picks up when you press Enter, but not the line feed (0ah) that would move the cursor to the next line
puts all your input including the carriage return in the specified memory location, but again no line feed.
This means that immediately after the input routine runs, your cursor is sitting at the beginning of the line you did your input on, which still contains your echoed input. So print a line feed character to make it go to the next line before you do anything else.
Next, when you print the string out, the carriage return at the end is picked up and the cursor is returned to the beginning of the line, but again there is no line feed. It is quite likely that whatever gets written afterwards (by your program, or any other program on the system) will overwrite what you have printed. So, again, print a line feed to make it go to the next line first.
Printing a line feed should be as simple as:
data segment
....
lf db 10, '$'
....
code segment
....
mov dx, offset lf
mov ah, 9
int 21h
....
mov dx, offset lf
mov ah, 9
int 21h
....

Related

Taking input string from keyboard and outputting a string in Assembly (8086)

I am trying to create a program that greets the user with their name. The user enters their name after a prompt and the they are greeted along with their name. I have already tried using this code but it fails and throws error on line 21.
The error message states:
(21) wrong parameters: LEA Dx,name
(21) probably no zero prefix for hex; or no 'h' suffix; or wrong addressing; or undefined var: name
Here's the code
.MODEL SMALL
.STACK 100
.DATA
msg db "Hello! Please enter your name:$"
newline db 13,10,'$'
greeting db "Wellcome!$"
name db 80, 0, 78 DUP('$')
.CODE
main PROC
; Prompt
MOV Ax,#DATA
MOV Ds,Ax
LEA Dx,msg
MOV Ah,09h
INT 21h
; Input
LEA Dx,name (throws error)
MOV AH,0AH
INT 21h
; Check if ENTER is pressed
CMP Al,13
JE Display
; Newline
LEA Dx,newline
MOV Ah,09h
INT 21h
; Print Greeting
Display: MOV AH,09h
LEA Dx,name+2
;MOV Dl,Al
INT 21H
Exit:
MOV Ah,4Ch
INT 21h
main ENDP
END main
it fails is not a useful description. When you want to use Int 21/AH=0Ah buffered input, the first buffer byte has to be initialized with its size, for instance
name db 80, 0, 78 DUP('$')
Also remove the instruction MOV Dl,Al which damages DX in ; Print Greeting.

How do i reverse a string on emu8086 assembly language [duplicate]

I have to do a simple calculator in assembly using EMU8086, but every time I try to launch it EMU8086 gives this error:
INT 21h, AH=09h -
address: 170B5
byte 24h not found after 2000 bytes.
; correct example of INT 21h/9h:
mov dx, offset msg
mov ah, 9
int 21h
ret
msg db "Hello$"
I checked the other stuff, but there were no mistakes:
data segment
choice db ?
snum1 db 4 dup(?)
snum2 db 4 dup(?)
sres db 4 dup(?)
num1 db ?
num2 db ?
res db ?
;;menu1 db "Chose a function to procced", 10, 13, "Add [+]", 10, 13, "Sub [-]", 10, 13
;;menu2 db "Mul [*]", 10, 13, "Div [/]", 10, 13, "Mod [%]", 10, 13, "Pow [^]", 10, 13, "Exit [x]$"
messStr db "Enter Your Choice:",10,13,"",10,13,"Add --> +",10,13,"Sub --> -",10,13,"Mul --> *",10,13,"Div --> /",10,13,"Mod --> %",10,13,"Pow --> ^",10,13,"Exit --> X",10,13,"$"
msg1 db "Enter first number$"
msg2 db "Enter second number$"
msg3 db "Press any key to procced$"
msg4 db "The result is $"
ends
stack segment
dw 128 dup(0)
ends
code segment
assume cs:code, ds:data, ss:stack
newline proc ;; new line
push ax
push dx
mov ah, 2
mov DL, 10
int 21h
mov ah, 2
mov DL, 13
int 21h
pop dx
pop ax
ret
endp
printstr proc ;; print string
push BP
mov BP, SP
push dx
push ax
mov dx, [BP+4]
mov ah, 9
int 21h
pop ax
pop dx
pop BP
ret 2
endp
inputstr proc ;; collect input
push BP
mov BP, SP
push bx
push ax
mov bx, [BP+4]
k1:
mov ah, 1
int 21h
cmp al, 13
je sofk
mov [bx], al
inc bx
jmp k1
sofk:
mov byte ptr [bx], '$'
pop ax
pop bx
pop BP
ret 2
endp
getNums proc ;; get the numbers
call newline
push offset msg1
call printstr
call newline
push offset snum1
call inputstr
call newline
push offset msg2
call printstr
call newline
push offset snum2
call inputstr
ret
endp
start:
mov ax, data
mov ds, ax
mov ax, stack
mov ss, ax
;; print the main menu
call newline
push offset msg4
call printstr
;; collect the input
call newline
mov bx, offset choice
mov ah, 1
int 21h
mov [bx], al
;; check it
mov al, choice
cmp al, '+'
jne cexit
call getNums
jmp cont
cexit:
cmp al, 'x'
je cend
cont:
;; pause before going to the main menu
call newline
push offset msg3
call printstr
mov bx, offset choice
mov ah, 1
int 21h
call newline
call newline
call newline
jmp start
cend:
mov ax, 4c00h
int 21h
ends
end start
I cut most of the code segment because it wasn't important here.
After experimenting with the code I found that the problem was related to the lengths of the messages in the data segment. menu1 & menu2 were too long and any message after them can't be printed (msg1 & msg2 are printed, but nothing after them). I checked if I should merge menu1 & menu2, but it didn't help out. Please help me find out what is wrong with it.
The error message means you use int 21h / AH=09h on a string that didn't end with a $ (ASCII 24h). The system-call handler checked 2000 bytes without finding one.
Often, that means your code or data is buggy, e.g. in a fixed string you forgot a $ at the end, or if copying bytes into a buffer then you maybe overwrote or never stored a '$' in the first place.
But in this case, it appears that EMU8086 has a bug assembling push offset msg4. (In a way that truncates the 00B5h 16-bit address to 8-bit, and sign-extends back to 16, creating a wrong pointer that points past where any $ characters are in your data.)
Based on the error message below I know you are using EMU8086 as your development environment.
INT 21h, AH=09h -
address: 170B5
byte 24h not found after 2000 bytes.
; correct example of INT 21h/9h:
mov dx, offset msg
mov ah, 9
int 21h
ret
msg db "Hello$"
I'm no expert on EMU8086 by any stretch of the imagination. I do know why your offsets don't work. I can't tell you if there is a proper way to resolve this, or if it's an EMU8086 bug. Someone with a better background on this emulator would know.
You have created a data segment with some variables. It seems okay to me (but I may be missing something). I decided to load up EMU8086 to actually try this code. It assembled without error. Using the debugger I single stepped to the push offset msg1 line near the beginning of the program. I knew right away from the instruction encoding what was going on. This is the decoded instruction I saw:
It shows the instruction was encoded as push 0b5h where 0b5h is the offset. The trouble is that it is encoded as a push imm8 . The two highlighted bytes on the left hand pane show it was encoded with these bytes:
6A B5
If you review an instruction set reference you'll find the encodings for PUSH instruction encoded with 6A is listed as:
Opcode* Instruction Op/En 64-Bit Mode Compat/Leg Mode Description
6A ib PUSH imm8 I Valid Valid Push imm8.
You may say that B5 fits within a byte (imm8) so what is the problem? The smallest value that can be pushed onto the stack with push in 16-bit mode is a 16-bit word. Since a byte is smaller than a word, the processor takes the byte and sign extends it to make a 16-bit value. The instruction set reference actually says this:
If the source operand is an immediate of size less than the operand size, a sign-extended value is pushed on the stack
B5 is binary 10110101 . The sign bit is the left most bit. Since it is 1 the upper 8 bits placed onto the stack will be 11111111b (FF). If the sign bit is 0 then then 00000000b is placed in the upper 8 bits. The emulator didn't place 00B5 onto the stack, it placed FFB5. That is incorrect! This can be confirmed if I step through the push 0b5h instruction and review the stack. This is what I saw:
Observe that the value placed on the stack is FFB5. I could not find an appropriate syntax (even using the word modifier) to force EMU8086 to encode this as push imm16. A push imm16 would be able to encode the entire word as push 00b5 which would work.
Two things you can do. You can place 256 bytes of dummy data in your data segment like this:
data segment
db 256 dup(?)
choice db ?
... rest of data
Why does this work? Every variable defined after the dummy data will be an offset that can't be represented in a single byte. Because of this EMU8086 is forced to encode push offset msg1 as a word push.
The cleaner solution is to use the LEA instruction. This is the load effective address instruction. It takes a memory operand and computes the address (in this case the offset relative to the data segment). You can replace all your code that uses offset with something like:
lea ax, [msg1]
push ax
AX can be any of the general purpose 16-bit registers. Once in a register, push the 16-bit register onto the stack.
Someone may have a better solution for this, or know a way to resolve this. If so please feel free to comment.
Given the information above, you may ask why did it seem to work when you moved the data around? The reason is that the way you reorganized all the strings (placing the long one last) caused all the variables to start with offsets that were less than < 128. Because of this the PUSH of an 8-bit immediate offset sign extended a 0 in the top bits when placed on the stack. The offsets would be correct. Once the offsets are >= 128 (and < 256) the sign bit is 1 and the value placed on the stack sign will have an upper 8 bits of 1 rather than 0.
There are other bugs in your program, I'm concentrating on the issue directly related to the error you are receiving.
I reviewed your code and concentrated on the following sequence of instructions:
mov bx, offset choice ; here you set BX to the address of 'choice'
mov ah, 1
int 21h ; here you 'READ CHARACTER FROM STANDARD INPUT, WITH ECHO'
mov [bx], al ; because INT 21h does preserve BX, you are writing back the result of the interrupt call (AL) back to the memory location at BX, which is named 'choice'
;; check it
mov al, choice ; HERE you are moving a BYTE variable named 'choice' to AL, overwriting the result of the last INT 21h call
cmp al, '+' ; ... and compare this variable to the ASCII value of '+'
jne cexit ; if this variable is unequal to '+' you jump to 'cexit'
call getNums ; otherwise you try to get another number from the input/STANDARD CONSOLE
So your sequence
mov bx, offset choice ; here you set BX to the address of 'choice'
...
mov [bx], al ; because INT 21h does preserve BX, you ...
...
mov al, choice
essentially means, that you are setting BX to the address of 'choice', then setting 'choice'([BX]) to AL and copying it back to AL.
This is redundant.
After that, you compare that char to '+' and...
if that char equals to '+', you get the next char with call getNums and then continue with cont:.
if that char does not equal to '+', you compare it to 'x', the exit-char. If it's not 'x', you fall through to cont:
No error here.
So your problem with menu1 and menu2 may stem from some escape characters included in your strings like %,/,\. For example, % is a MACRO character in some assemblers which may create problems.
simple solution is that your strings should always end in '$'
change DUP(?) to DUP('$') and all other strings end with ,'$'

8086 Write a program that takes one string from the input and inserts white space between every two letters

8086 Write a program that takes one string from the input and inserts white space between every two letters
using nasm and MSDOS
i have do following code but it is not working
start:
mov ax,data
mov ds, ax
mov es, ax
mov cx, size;cx will contain size,we need it to
; check if we have got 10 inputs from key board
lea dx, Enter_string;it will display a text on screen to enter text
mov ah, 9
int 21h
call get_string;input string from keyboard
mov ax, 4ch;terminating
int 21h
get_string:
mov si, 0; si will be used as index
mov bx, offset string
get_char:
mov ah, 1; get a char from keyboard
int 21h
mov [bx][si], al; saving input in string
inc si
cmp si,cx;if si=7 than, no need to take more input
jne get_char
ret
. You should prefer the simplicity of .COM programs while learning. They already start with all the segment registers pointing to the program.
. The DOS exit function expects the function number in AH.
. On NASM you don't use mov bx, offset string. Just write mov bx, string.
. It's easy to combine the tasks of inputting a string and interjecting space characters. See below code:
org 256 ;.COM programs have CS=DS=ES=SS
start:
mov cx, size ;cx will contain size,we need it to
; check if we have got 10 inputs from key board
mov dx, Enter_string ;it will display a text on screen to enter text
mov ah, 9
int 21h
call get_string ;input string from keyboard
mov ax, 4C00h ;terminating
int 21h
get_string:
push cx
mov si, 0 ; si will be used as index
get_char:
mov ah, 1 ; get a char from keyboard
int 21h
mov ah, " "
mov [string+si], ax ; saving input in string PLUS THE SPACE CHARACTER
add si, 2
dec cx ;if si=7 than, no need to take more input
jnz get_char
pop cx
ret
Remember that you don't actually need the last space character. Just overwrite it with the string terminator that you normally would add to this string!

Why is it not displaying the exact string I typed when it is not 10 letter word?

im using tasm 1.4 assembly language. This really bugs me, whenever I accept 10 maximum letter word, if the user typed only 5 letter, nothing will displayed on screen. But when the user typed 6 letter word like "aaaaaa" the output will be " aa". There is 4 spaces at the beginning. if the user typed 8 letter word like "aaaaaaaa", the output will be " aaaaaa". Lastly, but if the user typed 10 letter word like "aaaaaaaaaa", the output will be the same.
The question is, why is there spaces at the beginning if the user input less than 10 letter word?
.model small
.stack 120h
.data
aname label byte
asize db 11
aactual db ?
atext db 11 dup (" "),"$"
ent db 13,10, "Enter a 10 letter word: $"
.code
mov ax,#data
mov ds,ax
mov ax,03
int 10h
;displaying the prompt message
mov ah,09
lea dx,ent
int 21h
;accepting input strings
mov ah,10
lea dx,aname
int 21h
;moving the text below to so that it dont overlap with the prompt message
mov ah,02
mov bx,0
mov dl,0
mov dh,2
int 10h
;displaying the user input
mov ah,09
lea dx,atext
int 21h
mov ah,4ch
int 21h
end

Length of input string in assembly language

I want to do two things:
1) Take a string from user
2) Find the length of that string
I tried the following code:
.model small
.stack 100h
.data
MAXLEN DB 100
ACT_LEN DB 0 ;Actual length of the string
ACT_DATA DB 100 DUP('$') ;String will be stored in ACT_DATA
MSG1 DB 10,13,'ENTER STRING : $'
.CODE
START:
MOV AX,#data
MOV DS,AX
;Normal printing
LEA DX,MSG1
MOV AH,09H
INT 21H
;Cant understand code from here!
LEA DX,ACT_DATA
MOV AH,0AH
MOV DX,OFFSET MAXLEN
INT 21H
LEA SI,ACT_DATA
MOV CL,ACT_LEN
;AND THEH SOME OPERATIONS
END START
But I am confused how the length is stored in CL register, i.e. how the ACT_LEN value is incremented? And what actually does mov AH,0A has relation with length?
Int 21/AH=0Ah
Format of DOS input buffer:
Offset Size Description (Table 01344)
00h BYTE maximum characters buffer can hold (MAXLEN)
01h BYTE (call) number of chars from last input which may be recalled (ACT_LEN)
(ret) number of characters actually read, excluding CR
02h N BYTEs actual characters read, including the final carriage return (ACT_DATA)
The buffered input interrupt will fill in these values.
LEA DX,ACT_DATA
MOV AH,0AH
MOV DX,OFFSET MAXLEN
INT 21H
You do not need LEA DX,ACT_DATA
mov AH,0A is the number of the interrupt to call. Ralph Brown has a big list of interrupts with descriptions and what goes in/comes out.

Resources