Sorry if this question is really simple, but I tried all that I know and coudn't figure it out.
I'm trying to make a simple procedure which takes a string and a Count from the console and print the string number of times specified by the Count.
Everything is fine, but when I mov the Count to eax for a loop, the value get's messed up and I end up with an infinite loop of print.
I tried to change the Count to DWORD with atodw, but didn't work.
here's the code :
PrintString PROTO :DWORD, :DWORD
.data
String db 100 DUP(0)
Count db 10 DUP(0)
.code
start:
;1- get user input
invoke StdIn, addr String, 99
invoke StdIn, addr Count, 10
;2- Remove the CRLF from count
invoke StripLF, addr Count
;3- Convert the count to DWORD
invoke atodw, addr InputCount
mov Counter, eax
;4- Call the Printer function
invoke Printer, addr String, addr Count
Printer PROC StringToPrint:DWORD, count:DWORD
mov eax,count ;;;;;; This is the problem I think
Looppp:
push eax
invoke StdOut, StringToPrint
pop eax
dec eax
jnz Looppp
ret
Printer endp
You’re passing addr Count – the address of the string – as the second argument to Printer. But it expects an integer, so you want to pass Counter instead.
Since you’re using a language without type checking, adopting a naming convention such as Hungarian notation for your identifiers could help you see and avoid this kind of problem. With the variables here named strCount and dwCount, for example, it would be more obvious that you were using the wrong one.
As an aside, eax must eventually reach zero so your printing loop won’t be infinite – just rather longer than you intended…
Related
I need to read a bunch of strings from command line in assembly, however only one call to scanf seems to take place. I'm pretty sure the problem is related to the scanf format. If I replace what I've currently got with a simple "%s" it works fine, thing is I have to read whole lines including spaces, so "%s" won't do. "%[^c]s" should keep reading characters until it encounters c, but there's 2 problems with this:
I actually have to input the characters \ and n for the scanning to stop.
As I said, it only reads one string. After that, all the prompts for the remaining strings get instantly printed at the program ends.
I've seen that people usually suggest using fread, however I'm not really sure how to access stdin in assembly.
Here's my code:
bits 32
global start
extern exit, scanf, printf
import exit msvcrt.dll
import scanf msvcrt.dll
import printf msvcrt.dll
segment data use32 class=data
msg DB "Enter a value for n", 13, 10, 0
s_msg DB "Enter a string", 13, 10, 0
n_format DB "%d", 0
s_format DB "%[^\n]s", 0
segment bss use32 class=bss
n DD 0
s RESB 1000
segment code use32 class=code
start:
push dword msg
call [printf]
add ESP, 4 * 1
push dword n
push dword n_format
call [scanf]
add ESP, 4 * 2
mov ECX, [n]
read_strings:
pushad
push dword s_msg
call [printf]
add ESP, 4 * 1
push dword s
push dword s_format
call [scanf]
add ESP, 4 * 2
popad
loop read_strings
push dword 0
call [exit]
I have a code that has 3 procedures, one to get an input from the user, one to display a multiplication result, and lastly one for an error message. I am trying to implement the PUSH and POP operations and get my code in to the stack. It will seem long but it makes sense to me, here it is...
.data
line BYTE "The answer is ",0
line2 BYTE "Enter a number",0
kline3 BYTE Wrong.",0
int SWORD ?
.code
Val PROC
call ReadInt
mov int,edx
cmp int, 10000
jl 1
jmp end
L1: cmp intVal1, -10000
jg 2
call error
jmp end
2: ret
Val ENDP
main PROC
call Val
call Val
imul val, val
exit
main ENDP
END main
All this simply does it call to get 2 inputs twice and then call to display the the multiplied result. My question is how do you implement push and pop in to here to have it all make sense?
I would assume that you need to push in the GetValue procedure to put in input in to the stack and then pop it after each call in the main procedure and maybe do the same with the display procedure?
I am just struggling to figure it out so any help would be great!
PS. This code is an asm file in visual studio 2010
Your first call to GetValue stores its result in intVal. But then your second call to GetValue also stores its result in intVal, so the first result is forever lost.
Your MultiplyAndDisplay function expects one of the operands in intVal, and the other operand in eax. So, what you need to do is push [intVal] after the first call to GetValue, and pop eax after the second call to GetValue.
Note that the square brackets in push [intVal] are in some notation that actually makes sense, but if I remember correctly the microsoft assembler does not support that notation which actually makes sense, so you might have to code push intVal instead, or push dword ptr intVal, or something nonsensical like that to get it to work.
Because your question is tagged MASM, this is a MASM answer:
Your code can be restructured in a way that uses the MASM directive PROC with parameters and the INVOKE directive for parameter passing:
MultiplyAndDisplay PROC val1: SDWORD, val2: SDWORD
mov eax, val1
imul eax, val2 ; signed multiply of val1 by val2
mov edx, OFFSET prompt
call WriteString ; Writes the prompt in edx
call WriteDec ; Writes the value in eax
ret
MultiplyAndDisplay ENDP
main PROC
call GetValue
push [intVal] ; PUSH firstParam to the stack
call GetValue
pop eax ; POP previous param/intVal to EAX
invoke MultiplyAndDisplay, eax, intVal ; MultiplyAndDisplay, firstParam(EAX), secondParam(intVal)
exit
main ENDP
See full code here.
I have filled a buffer (malloc'd) with an fread call and it is a success. I am now trying to iterate over the buffer and commence parsing the input. I'm trying to start really simple by walking the buffer and output each char to the screen. But my loop is just outputting the entire input. Here is the loop portion of the code:
mov ecx, 0
mov ebx, buffer
.readByte:
push DWORD [ebx + 1 * ecx]
push DWORD ecx
push DWORD char
call _printf
add esp, 12
incr ecx
cmp ecx, [fsz]
jge .endRead
jmp .readByte
The contents of the source file that is read in (s1.txt) is:
1 + 2;
My goal is to simply output:
1
+
2
;
Since you used %s format, which indicates a string, and that without a length specifier, why did you expect it to print just a single character? You should try %c format and something like movzx eax, byte [ebx + ecx]; push eax to pass the argument. A %.1s format specifier could also work and then you can keep your argument passing. Don't forget to add a newline too, if you want that. You could also just use putchar of course.
Oh, and ecx is a caller-saved register, as such any function you call may destroy its value. So if you want to keep using that, you need to save and restore it yourself.
I recently figured out how to write to stdout in assembly but am now having trouble reading from stdin, and outputting what I read back to stdout. This is the code I have so far:
.386
.model flat, stdcall
WriteFile PROTO STDCALL:DWORD, :PTR, :DWORD, :PTR DWORD, :PTR OVERLAPPED
ReadFile PROTO STDCALL:DWORD, :PTR, :DWORD, :PTR DWORD, :PTR OVERLAPPED
GetStdHandle PROTO STDCALL:DWORD
.data
.data?
input DW ?
input_size DD ?
read DD ?
.code
main:
INVOKE GetStdHandle, -10
INVOKE ReadFile, eax, OFFSET input, input_size, read, 0
INVOKE GetStdHandle, -11
INVOKE WriteFile, eax, OFFSET input, OFFSET input_size, read, 0
RET
END main
I'm pretty sure I'm reading it wrong. I am pretty sure that input_size and read are not behaving as expected (if I replace input_size with a number it displays a space number times) which is contributing to my problem (when I enter my input and hit return it simply displays nothing).
I have fumbled around with this for quite some time and would appreciate any help. (I am doing this just to learn this is not homework).
My question essentialy is what am I doing wrong?
You are allocating only two bytes for the input buffer:
input DW ?
Your input size is zero, causing ReadFile to read a maximum of 0 bytes:
input_size DD ?
nNumberOfBytesToRead should be passed as a value and not a pointer. And you want to write as many bytes as were input in the Readfile:
INVOKE WriteFile, eax, OFFSET input, OFFSET input_size, read, 0
INVOKE WriteFile, eax, OFFSET input, read, read, 0
I'm working on learning some Assembly Language (x86 Irvine.32 windows7) and had a question about how to input from a user. The book I have doesn't go over it too in depth. I would like to prompt the user:
myfirst BYTE "Welcome! This program calculates the sum of a list of numbers.", 0dh, 0ah, 0dh, 0ah ; greeting
BYTE "How many integers will be added? : "
then the user will input X. How do I read what the user inputs and put it into a variable?
is it as simple as:
INVOKE ReadConsole, SomeVairable
Where SomeVairable is defined up in .data as a byte?
edit:
INCLUDE Irvine32.inc
BufSize = 80
.data
buffer BYTE BufSize DUP(?)
stdInHandle HANDLE ?
bytesRead DWORD ?
myfirst BYTE "Welcome! This program calculates the sum of a list of numbers.", 0dh, 0ah, 0dh, 0ah ; greeting
BYTE "How many integers will be added? : "
mysecond BYTE "Please enter the "
.code
main PROC
mov edx, OFFSET myfirst ;move the location of myfirst into edx
call WriteString
; Get handle to standard input
INVOKE GetStdHandle, STD_INPUT_HANDLE
mov stdInHandle,eax
; Wait for user input
INVOKE ReadConsole, stdInHandle, ADDR buffer,
BufSize, ADDR bytesRead, 0
exit
main ENDP
END main
No, it's not (at least usually) that simple.
What the user enters will be read as a string, not a number. You'll typically have to read the string (which will usually be more than one byte long), then convert it to an integer. You may want to verify that all the characters in the string are digits before you do the conversion, or you may want to combine conversion with verification.
Looking specifically at the ReadConsole call, there are two things to keep in mind. First, you need to retrieve a handle to the console, normally with GetStdHandle. Then, you need to supply ReadConsole with all of the half dozen or so parameters it expects.`