all strings are printing on the console at the same time in assembly language 8086 - string

I am having a problem with my assembly code I was making a linear search program and in that program i have initializes two strings; the string when user is asked to input a number and other when there is a positive result but the problem is that when i run my program, all strings are printing at the same time on the console.
note: there are some other errors also but please ignore them at this time.
include irvine32.inc
.data
searchArr WORD 1, 4, 7, 14, 299, 156, 3, 63, 29, 300, 20
user_input word ?
search_str byte "enter the number you want to search",0ah,0dh
yes_str byte "the number is in given array",0ah,0dh
.code
main proc
mov edx,offset search_str
call writestring
mov edx,0
; asking the number from user
call readint
mov user_input , ax
mov eax,0
;seacrhing the array
mov ecx, (lengthof searchArr)
mov esi,0
search:
mov bx,searchArr[esi * type searchArr]
cmp bx,user_input
je yes
inc esi
loop search
yes:
mov edx,0
mov edx,offset yes_str
call writestring
exit
main endp
end main

Related

Moving string between variables

I am writing a MASM program using the Irvine32 Library from my textbook. I want to line up my printed columns, but I couldn't finds anything on how to terminate a string with a tab-stop, /t for C/C++, so I made a procedure that determines how many decimal places the number has and assigns the spacer string variable accordingly.
My issue is when trying to assign spacer a new string, I get assembling errors. I have tried
mov spacer, "New String",0
and
mov spacer, "New String"
as well as assigning "New String" to a variable and assigning spacer that variable as well as that variables OFFSET. I now have it where the variables OFFSET is moved into edx but I can't move edx into the other variable.
I would greatly appreciate the help and any information to help be better understand why this doesn't work in assembly or MASM in particular. Thanks
Procedure in question:
; Define the spacer based on the places in x
spacer_choice proc
cmp x, 10
JB SC1
cmp x, 100
JB SC2
mov edx, OFFSET hundo_spacer
JMP SC3
SC1:
mov edx, OFFSET one_spacer
JMP SC3
SC2:
mov edx, OFFSET ten_spacer
JMP SC3
SC3:
mov spacer, OFFSET edx
RET
spacer_choice endp
Output:
1>------ Build started: Project: MASM4, Configuration: Debug Win32 ------
1> Assembling composite.asm...
1>composite.asm(209): error A2032: invalid use of register
1>C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V140\BuildCustomizations\masm.targets(50,5): error MSB3721: The command "ml.exe /c /nologo /Sg /Zi /Fo"Debug\composite.obj" /Fl"MASM4.lst" /I "c:\Irvine" /W3 /errorReport:prompt /Tacomposite.asm" exited with code 1.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Full Code:
INCLUDE Irvine32.inc
.data
; ----- GLOBALS
n_comps DWORD ?
; ----- INTRO VALUES
; Greeting the User
title_prompt BYTE "Welcome to Prog. 4, my name is Zach", 10, 13, 0
name_prompt BYTE "What should I call you?: ", 0
username BYTE 21 DUP(0)
user_greet BYTE "Hello, ", 0
; Instructing the User
one_instruct BYTE "We are going to calculate all the composite numbers from 1 to n.", 10, 13, 0
two_instruct BYTE "N is the number you enter. That number has to be an integer,", 10, 13, 0
three_instruct BYTE "and in the range of 1 to 400.", 10, 13, 0
; ----- INPUT VALUES
; Prompts
int_prompt BYTE "How many composite numbers do you want to display? 1 to 400: ", 0
bad_prompt BYTE "Your Input was bad, try again", 10, 13, 0
; Constants
MAX_VAL = 400
MIN_VAL = 1
; ----- CALCULATE
x DWORD ?
spacer BYTE ?
count DWORD ?
; ----- SPACER_CHOICE
one_spacer BYTE ", ", 0
ten_spacer BYTE ", ", 0
hundo_spacer BYTE ", ", 0
; ----- OUTRO
farewell BYTE "Hope you've had fun printing composites! Goodbye, ", 0
.code
main proc
call intro
call input
call calculate
call outro
invoke ExitProcess, 0
main endp
; Greet the User and get their name
intro proc
; Greet
mov edx, OFFSET title_prompt
call WriteString
; Prompt for username
mov edx, OFFSET name_prompt
call WriteString
mov edx, OFFSET username
mov ecx, SIZEOF username
call ReadString
mov edx, OFFSET user_greet
call WriteString
mov edx, OFFSET username
call WriteString
call Crlf
; Intruct the User
mov edx, OFFSET one_instruct
call WriteString
mov edx, OFFSET two_instruct
call WriteString
mov edx, OFFSET three_instruct
call WriteString
intro endp
; Get User's Input. Validate if Between Min and Max
input proc
; Prompt for user input
I1:
mov edx, OFFSET int_prompt
call WriteString
mov eax, 0
call ReadInt
call Crlf
; Check if less than MAX_VAL
cmp eax, MAX_VAL
JA I4
JMP I3
I3:
; Check if greater than MIN_VAL
cmp eax, MIN_VAL
JB I4
JMP I2
I4:
; EAX is incorrect
; Loop
mov edx, OFFSET bad_prompt
call WriteString
loop I1
; Good Input
; Set n_comps to eax
I2:
mov n_comps, eax
mov eax, 0
RET
input endp
; X is not divisible by 2 or 3, is prime
calculate proc
mov ecx, 400
mov x, 1
C1:
; Check if X is less than, or equal to, 3
cmp x, 3
JBE C2
C4:
; Check if X is divisible by 2
mov edx, 0
mov eax, x
mov ebx, 2
div ebx
cmp edx, 0
JE C3
; Check if X is divisible by 3
mov edx, 0
mov eax, x
mov ebx, 3
div ebx
cmp edx, 0
JNE C2
C3:
; Is composite, Print number
mov eax, x
cmp count, 10
JNE C5
call Crlf
mov count, 0
C5:
call WriteInt
call spacer_choice
mov edx, OFFSET spacer
call WriteString
add count, 1
C2:
; RET if X == N
mov eax, n_comps
cmp x, eax
JNE C6
RET
C6:
; Increment and LOOP
add x, 1
LOOP C1
calculate endp
; Define the spacer based on the places in x
spacer_choice proc
cmp x, 10
JB SC1
cmp x, 100
JB SC2
mov edx, OFFSET hundo_spacer
JMP SC3
SC1:
mov edx, OFFSET one_spacer
JMP SC3
SC2:
mov edx, OFFSET ten_spacer
JMP SC3
SC3:
mov spacer, OFFSET edx
RET
spacer_choice endp
; Say Goodbye
outro proc
mov edx, OFFSET farewell
call WriteString
mov edx, OFFSET username
call WriteString
call Crlf
outro endp
end main
I added the ASCII horizontal tab, 9, to the end of spacer, and that removed the need for the spacer_choice procedure.
Spacer now is declared as: spacer BYTE ",", 9, 0

How to convert a DWORD into a DB

I want to display a score in a game that I built in MASM32, and I have a problem, how do I convert a DWORD to a DB (string).
There is the function crt__itoa to convert a dword to an integer , but for some reason it doesn't work (do i need to include an other lib ? ).
There is the function TextOutA to display a score, but again I cant print it out because I don't have a string so it can print it from.
do i need to include an other lib? - Probably. You need msvcrt.inc and msvcrt.lib for crt__itoa.
masm32rt.inc is the Swiss Army Knife for such cases. Here is a working example:
include c:\masm32\include\masm32rt.inc
.DATA
fmt db "%s",10,0
num dd 1234567
num_str db 16 dup (?)
.CODE
main PROC
; with CALL:
push 10
push OFFSET num_str
push num
call crt__itoa
add esp, 12
push OFFSET num_str
push OFFSET fmt
call crt_printf
add esp, 8
; or with INVOKE:
invoke crt__itoa, num, OFFSET num_str, 10
invoke crt_printf, OFFSET fmt, OFFSET num_str
invoke ExitProcess, 0
main ENDP
END main
The program does not stop. If you don't call it in an extra command prompt window it will open a window and close it immediately. In Qeditor I suggest to insert a line "Run & Pause" into menus.ini:
...
&Run Program,"{b}.exe"
Run && Pause,cmd.exe /C"{b}.exe" & pause
...
Now you have a new item under "Project".
Next is a method made with Visual Studio 2010 C++ that manually converts EAX into a string (it doesn't need any library, just copy-paste and use). It takes a number as parameter, assign it to EAX, convert it to string and display the string :
void number2string ( int value ) {
char buf[11];
__asm { ;EXTRACT DIGITS ONE BY ONE AND PUSH THEM INTO STACK.
mov eax, value
mov ebx, 10 ;DIGITS ARE EXTRACTED DIVIDING BY 10.
mov cx, 0 ;COUNTER FOR EXTRACTED DIGITS.
cycle1:
mov edx, 0 ;NECESSARY TO DIVIDE BY EBX.
div ebx ;EDX:EAX / 10 = EAX:QUOTIENT EDX:REMAINDER.
push dx ;PRESERVE DIGIT EXTRACTED (DL) FOR LATER.
inc cx ;INCREASE COUNTER FOR EVERY DIGIT EXTRACTED.
cmp eax, 0 ;IF NUMBER IS
jne cycle1 ;NOT ZERO, LOOP.
;NOW RETRIEVE PUSHED DIGITS IN REVERSE ORDER.
mov esi, 0 ;POINTER TO STRING'S CHARACTERS.
cycle2:
pop dx ;GET A DIGIT.
add dl, 48 ;CONVERT DIGIT TO CHARACTER.
mov buf[ esi ], dl
inc esi ;NEXT POSITION IN STRING.
loop cycle2
mov buf[ esi ], 0 ;MAKE IT ASCIIZ STRING.
}
printf( buf );
scanf( "%s",buf ); // TO STOP PROGRAM AND LET US SEE RESULT.
}
Pay attention : previous method is a "void", so you call it as usual :
number2string( 1234567890 ); // CONVERT THIS BIG NUMBER IN STRING AND DISPLAY.
You can modify the method to return the string or to do anything you want.
Now (for those who are tough enough) the same previous procedure for pure assembler, made with GUI Turbo Assembler x64 (http://sourceforge.net/projects/guitasm8086/), this full program shows how it works :
.model small
.586
.stack 100h
.data
buf db 11 dup (?) ;STRING.
.code
start:
;INITIALIZE DATA SEGMENT.
mov ax, #data
mov ds, ax
;CONVERT EAX TO STRING.
call dollars ;FILL BUF WITH '$', NECESSARY TO DISPLAY.
mov eax, 1234567890
call number2string ;PARAMETER:EAX. RETURN:VARIABLE BUF.
;DISPLAY BUF (EAX CONVERTED TO STRING).
mov ah, 9
mov dx, offset buf
int 21h
;WAIT UNTIL USER PRESS ANY KEY.
mov ah, 7
int 21h
;FINISH PROGRAM.
mov ax, 4c00h
int 21h
;------------------------------------------
;NUMBER TO CONVERT MUST ENTER IN EAX.
;ALGORITHM : EXTRACT DIGITS ONE BY ONE, STORE
;THEM IN STACK, THEN EXTRACT THEM IN REVERSE
;ORDER TO CONSTRUCT STRING (BUF).
number2string proc
mov ebx, 10 ;DIGITS ARE EXTRACTED DIVIDING BY 10.
mov cx, 0 ;COUNTER FOR EXTRACTED DIGITS.
cycle1:
mov edx, 0 ;NECESSARY TO DIVIDE BY EBX.
div ebx ;EDX:EAX / 10 = EAX:QUOTIENT EDX:REMAINDER.
push dx ;PRESERVE DIGIT EXTRACTED (DL) FOR LATER.
inc cx ;INCREASE COUNTER FOR EVERY DIGIT EXTRACTED.
cmp eax, 0 ;IF NUMBER IS
jne cycle1 ;NOT ZERO, LOOP.
;NOW RETRIEVE PUSHED DIGITS.
mov si, offset buf
cycle2:
pop dx
add dl, 48 ;CONVERT DIGIT TO CHARACTER.
mov [ si ], dl
inc si
loop cycle2
ret
number2string endp
;------------------------------------------
;FILLS VARIABLE BUF WITH '$'.
;USED BEFORE CONVERT NUMBERS TO STRING, BECAUSE
;THE STRING WILL BE DISPLAYED.
dollars proc
mov si, offset buf
mov cx, 11
six_dollars:
mov bl, '$'
mov [ si ], bl
inc si
loop six_dollars
ret
dollars endp
end start

Joining two strings together in NASM

I looked all over google for ways to do this, I found some but I really found them to be overly complex for what I need. For starters, I need this to be done through a loop, the place where I'm putting my strings is also initially empty, so I'm sure that is bound to create some issues.
Anyway this is my code:
%include "io.mac"
.DATA
filename_msg db 'Enter the file name: ', 0
number_prompt_msg db 'Enter the number of bases: ',0 ;asks for the number of bases to be used
finish_msg db 'Operation completed, DNA file generated',0 ;tells the user when the file is complete
error_msg db 'Operation failed, please try again', 10
base_A db 'A',0
base_C db 'C',0
base_G db 'G',0
base_T db 'T',0
base_length equ $ - base_A
;----------------------------------------------------------------------------------------------------
.UDATA
number_of_bases rest 1 ;defined by the user
random_number resb 1
filename: resd 20 ;defined by the user
base rest 1
file_descriptor resd 1 ;used to generate the file
characters_to_write rest 1
;-------------------------------------------------------------------
;start of code, and message prompts for the user
.CODE
.STARTUP
;asks user for filename
ask_details:
PutStr filename_msg
GetStr filename, 300
;asks user for the number of bases
PutStr number_prompt_msg
GetLInt [number_of_bases]
;------------------------------------------------------------
;file creation
mov EAX, 8 ;creates the file
mov EBX, filename
mov ECX, 644O ;octal instruction
int 80h ;kernel interrupt
cmp EAX,0 ;throws error if something is amiss
jbe error
mov [file_descriptor],EAX
mov ECX,[number_of_bases]
;-------------------------------------------------------------
;randomization of base numbers
writing_loop:
rdtsc
mov EAX, EDX
mov EDX, 0
div ECX
mov EDX, 0
mov EBX, 4
div EBX
mov [random_number], EDX
mov EDX, 0
mov EAX,[random_number]
cmp EAX,0
je assignment_A
cmp EAX,1
je assignment_C
cmp EAX,2
je assignment_G
cmp EAX,3
je assignment_T
join_char:
mov [base + EBX],EBX
loop writing_loop
PutStr base
.EXIT
;------------------------------------------------------------
;file generation error message
error:
PutStr error_msg
jmp ask_details
;------------------------------------------------------------
;assignments
assignment_A:
mov EBX, [base_A]
jmp join_char
assignment_C:
mov EBX, [base_C]
jmp join_char
assignment_T:
mov EBX, [base_T]
jmp join_char
assignment_G:
mov EBX, [base_G]
jmp join_char
First it compares some random numbers I obtained with rdtsc, depending on what comes up, it will assign a letter to EBX this letter(base_A,base_C,base_T or base_G) is then supposed to go into base. I tried using
mov [base + EBX],EBX but that just printed an empty space, I used this because it seemed to work in the examples I looked at, but I'm not really sure how concatenating works in NASM. I don't know if anyone knows any simple methods to concatenate those characters together, if it is possible. This is really minor, so I'm hoping I don't have to add a lot of code, the only thing I need this string for is to write it in a file later. I would do that without the string but I need all my registers to write to the file so I can't do it letter by letter.
EDIT: What I need to know how to do is how to join each letter once it has been picked. Base is empty for example, then after a letter is picked, it gets thrown in there, however after the loop runs again, another letter will be picked, and I need to add it to base after all that's done.

NASM INTEGER INPUT AND PRINTING INTEGER AFTER MANIPULATION

I am new to nasm, and i am trying to do the following in nasm i am using mac osx. Regardless of that fact just guide me to how to read integer from console
.data
_num word 0
_sum word 0
_msg1 byte "Enter a number: ", 0
_msg2 byte "The sum is: ", 0
.code
main proc
mov edx, offset _msg1
call writestring
call readint
mov [_num], eax
call writestring
call readint
add eax, [_num]
mov [_sum], eax
call writestring
call readint
sub [_sum], eax
mov eax, [_sum]
call writeint
exit
main endp
end main

How can I read one integer each time?

I'm using an assembly library to make a program that reads three integers from standard input. When the reading is done in the console it works perfectly, but when I use a file as input, it reads the three integers at once.
This is the strace for console:
read(0, "3000\n", 512) = 5
read(0, "2000\n", 512) = 5
read(0, "1000\n", 512) = 5
And this from input file:
read(0, "3000\n2000\n1000\n", 512) = 15
read(0, "", 512) = 0
read(0, "", 512) = 0
Here are the procedures:
;--------------------------------------------------------
ReadInt:
;
; Reads a 32-bit signed decimal integer from standard
; input, stopping when the Enter key is pressed.
; All valid digits occurring before a non-numeric character
; are converted to the integer value. Leading spaces are
; ignored, and an optional leading + or - sign is permitted.
; All spaces return a valid integer, value zero.
; Receives: nothing
; Returns: If CF=0, the integer is valid, and EAX = binary value.
; If CF=1, the integer is invalid and EAX = 0.
;--------------------------------------------------------
push edx
push ecx
; Input a signed decimal string.
mov edx,digitBuffer
mov ecx,MAX_DIGITS
call ReadString
mov ecx,eax ; save length in ECX
; Convert to binary (EDX -> string, ECX = length)
call ParseInteger32 ; returns EAX, CF
pop ecx
pop edx
ret
;--------------- End of ReadInt ------------------------
;--------------------------------------------------------
ReadString:
;
; Reads a string from the keyboard and places the characters
; in a buffer.
; Receives: EDX offset of the input buffer
; ECX = maximum characters to input (including terminal null)
; Returns: EAX = size of the input string.
; Comments: Stops when Enter key (0Dh,0Ah) is pressed. If the user
; types more characters than (ECX-1), the excess characters
; are ignored.
; Written by Kip Irvine and Gerald Cahill
; Modified by Curtis Wong
;--------------------------------------------------------
enter 8, 0 ; bufSize: ebp - 4
; bytesRead: ebp - 8
pushad
mov edi,edx ; set EDI to buffer offset
mov dword [ebp - 4],ecx ; save buffer size
call ReadKeys
mov dword [ebp - 8], eax
cmp eax,0
jz .L5 ; skip move if zero chars input
cld ; search forward
mov ecx, dword [ebp - 4] ; repetition count for SCASB
dec ecx
mov al,NL ; scan for 0Ah (Line Feed) terminal character
repne scasb
jne .L1 ; if not found, jump to L1
;if we reach this line, length of input string <= (bufsize - 2)
dec dword [ebp - 8] ; second adjustment to bytesRead
dec edi ; 0Ah found: back up two positions
cmp edi,edx ; don't back up to before the user's buffer
jae .L2
mov edi,edx ; 0Ah must be the only byte in the buffer
jmp .L2 ; and jump to L2
.L1: mov edi,edx ; point to last byte in buffer
add edi,dword [ebp - 4]
dec edi
mov byte [edi],0 ; insert null byte
; Clear excess characters from the buffer, 1 byte at a time
.L6: call BufferFlush
jmp .L5
.L2: mov byte [edi],0 ; insert null byte
.L5: popad
mov eax, dword [ebp - 8]
leave
ret
;--------------- End of ReadString --------------------
You will need to buffer the input and split it because the console and files behave slightly different. A console will send you data as soon as someone presses Return, that is line by line.
Files will send you as much data as possible per call to read().
To make your code work, you will have to write a readline() function that reads the input byte by byte and returns when it sees a line feed.
Or you can use an internal buffer, fill it with as much data as possible, find the first line, return that, repeat until the buffer is empty, try to read more data, return EOF when there is no more data from the input.
As Aaron points out, the problem is that sys_read behaves differently when stdin is redirected. You could fix it as he suggests. or you could use Along32's ReadString and use a "homemade" atoi.
;--------------------
atoi:
push ebx
mov edx, [esp + 8] ; pointer to string
xor ebx, ebx ; assume not negative
cmp byte [edx], '-'
jnz notneg
inc ebx ; indicate negative
inc edx ; move past the '-'
notneg:
xor eax, eax ; clear "result"
.top:
movzx ecx, byte [edx]
inc edx
cmp ecx, byte '0'
jb .done
cmp ecx, byte '9'
ja .done
; we have a valid character - multiply
; result-so-far by 10, subtract '0'
; from the character to convert it to
; a number, and add it to result.
lea eax, [eax + eax * 4]
lea eax, [eax * 2 + ecx - '0']
jmp short .top
.done:
test ebx, ebx
jz notminus
neg eax
notminus:
pop ebx
ret
;------------------------
That expects the address of the string to be pushed on the stack and "removed" after, but I think you could just comment out that second line, and pass the address in edx (not tested!). More like the rest of the Along32 code that way. Unlike Along32's code, it returns with edx pointed to the next byte, and ecx (just cl, really) containing the "invalid" byte that stopped processing. I think you could call it repeatedly on the string returned by ReadString, saving the integer (in eax) and calling it again (without touching edx) if ecx is LF. When ecx is zero, you're done. Hope you find it helpful.

Resources