I am having an issue with this code snippet of a problem. My expected output is (after the intro):
Please enter an unsigned number: (user input)
.
.
.
Repeat ten times
The output that I am getting is :
Please enter an unsigned number: 10
10 <--- this is displaying instead of "Please enter an unsigned number: "
Any idea why this problem might be happening?
;getString should display a prompt, then get the user’s keyboard input into a memory location
getString MACRO buffer
push edx ;Save edx register
mov edx, OFFSET buffer
call WriteString
call ReadString
pop edx
ENDM
;displayString should the string stored in a specified memory location.
displayString MACRO buffer
push edx
mov edx, OFFSET buffer
call WriteString
call crlf
ENDM
.data
intro_1 BYTE "PROGRAMMING ASSIGNMENT 5: Designing low-level I/O procedures",0
intro_2 BYTE "Written by: Eric Walters",0
intro_3 BYTE "Please provide 10 unsigned decimal integers.",0
intro_4 BYTE "Each number needs to be small enough to fit inside a 32 bit register.",0
intro_5 BYTE "After you have finished inputting the raw numbers I will display a list",0
intro_6 BYTE "of the integers, their sum, and their average value.",0
data_1 BYTE "Please enter an unsigned number: ",0
array DWORD 10 DUP(?)
.code
main PROC
;Introduction
displayString intro_1
displayString intro_2
displayString intro_3
displayString intro_4
displayString intro_5
displayString intro_6
push OFFSET array
call getString1
;readVal
exit
main ENDP
getString1 PROC
push ebp
mov ebp, esp
mov ecx, 9
mov esi, [ebp + 8]
getString2:
getString data_1
mov [esi], eax
add esi, 4
call crlf
dec ecx
jmp getString2
ret
getString1 ENDP
END main
I suspect the problem is in some parameter being inadvertently passed into read string pointing at the address where data_1 is stored. For example, if edx is pointing at data_1 when you mov the OFFSET into it, and the WriteString is looking at edx for the address of the data to write, ReadString is looking at edx for the address to store the line in once it is read. So the ReadString is overwriting your sentence in data_1 with the number you entered and an end of line marker. Then the next time the WriteString PROC is called, it is reading in that number.
To fix this, create a .data? field called input_data or whatever you like, and point edx at it after the WriteString call but before the ReadString call.
Just an aside, but I also think you need to change your line after "dec ecx" to read "jnz getString2", not "jmp getString2". Otherwise I cannot see you ever escaping the loop no matter what value ecx reaches.
EDIT: Wait, I see, you have an array set up for that already. I think you just need to point to it before calling ReadString.
Related
The output for the given program should be 1--2--3--4--5--6--7--8.
However, mine keeps giving me 1--2--3--4--5--6--7-8--.I need to get rid of "--" after 8, but I couldn't figure out how to do it. Could someone help me, please?
INCLUDE Irvine32.inc
.data
arrayb byte 1,2,3,4,5,6,7,8
space byte "--",0
.code
main PROC
mov eax,0
mov edx,offset space
mov esi,offset arrayb
mov ecx, 8
printb:
mov al, [esi]
call writedec
call writestring
inc esi
mov eax, 8
loop printb
exit
main ENDP
end main
Your code (and loop specifically) currently does:
<init state>
counter = 8
printb:
output number
output "--"
loop to printb
<exit>
If you run through it in your head, it should be obvious why "--" is printed after last number.
There are many ways how to adjust that code, in real world code doing formatting I often either use some kind of join function which takes list and separator, and produces the formatted string, or if doing it manually, I would probably hardcode output of "1" ahead of loop, initialize the state to start loop as if starting from "2", and output "--" as first thing in the loop, i.e.:
<init state>
output number
advance state as if it was printed inside loop
counter = 8-1 ; one value is already out
printb:
output "--" ; the loop body starts with "--" output
output number
loop to printb
<exit>
I.e. in your code (with some modifications "improving" some things I didn't like :
...
mov edx,offset space
mov esi,offset arrayb
movzx eax, BYTE PTR [esi]
inc esi
call writedec
mov ecx, 8-1
printb:
call writestring
movzx eax, BYTE PTR [esi]
inc esi
call writedec
loop printb
exit
...
edit
The Peter Cordes idea from comments to make last item special case would maybe lead to better code in generic cases, where the amount of items is variable (with "8" fixed you know you can display first element and then 7 more will be looped).
Let's imagine such function in assembly, taking arguments in registers:
; esi = byte array to output
; ecx = amount of bytes
; will modify eax, ecx, edx, esi
OutputByteArray PROC
jecxz NoItemsToOutput ; if ecx=0
dec ecx
jz OutputLastItem ; if ecx=1, display only last item
; 1 < count, so "0 < ecx" here (ecx = count-1) => do the loop
mov edx,offset space
printb: ; output number and "--" "count-1" times
movzx eax, BYTE PTR [esi]
inc esi
call writedec
call writestring
loop printb
OutputLastItem:
movzx eax, BYTE PTR [esi]
call writedec
NoItemsToOutput:
ret
ENDP
I have some code in assembly which behaves a little bit strange. I have a C extern function that calls with asm another function from an .asm file. This C function puts on the stack three addresses used by my function from .asm file. All went well untill this appeared:
; Let's say we take from the stack first parameter from my C function.
; This parameter is a string of bytes that respect this format:
; - first 4 bytes are the sign representation of a big number
; - second 4 bytes are the length representation of a big number
; - following bytes are the actual big number
section .data
operand1 dd 0
section .text
global main
main:
push ebp
mov ebp, esp
mov eax, [ebp + 8] ; Here eax will contain the address where my big number begins.
lea eax, [eax + 8] ; Here eax will contain the address where
; my actual big number begins.
mov [operand1], eax
PRINT_STRING "[eax] is: "
PRINT_HEX 1, [eax] ; a SASM macro which prints a byte as HEX
NEWLINE
PRINT_STRING "[operand1] is: "
PRINT_HEX 1, [operand1]
NEWLINE
leave
ret
When running this code, I get at the terminal the correct output for [eax], and for [operand1] it keeps printing a number which will not change if I modify that first parameter of my C function. What am I doing wrong here?
I made an understandable mistake. When doing:
mov [operand1], eax
PRINT_STRING "[operand1] is: "
PRINT_HEX 1, [operand1]
NEWLINE
This code prints the first byte of the content (which is the address where my actual big number begins) contained at the address where this local variable (operand1) resides. In order to get the actual value which resides at [operand1] I had to do this:
mov ebx, [operand1]
PRINT_STRING "[operand1] is: "
PRINT_HEX 1, [ebx]
NEWLINE
When you are looping backwards in Assembly x86, what is currently happening in the memory (Can you try to be visual, thanks)? The following code is what I am currently wondering about:
INCLUDE Irvine32.inc
.data
arrayb byte 1,2,3,4,5,6 ;6-7 bytes
len dword lengthof arrayb
space byte " ",0
x dword 3
.code
main PROC
mov edx,offset space
mov eax,0 ; clear ecx of garbage
mov ecx, len
mov esi,offset arrayb ; start of the array's memory
add esi,len ;This causes the array value to start at 6
dec esi ; esi goes from esi+5,esi+4,...,esi
myloop2:
mov al,[esi]
call writedec
call writestring
dec esi
loop myloop2
call crlf
In particular, why did I have to add 1 to esi? When you add 1 to the high speed memory transfer register esi, it seems that it causes the array value to start at 6. Why is that?Thank you.
I'm currently presented with implementing a program that takes an input of a grade value (ex. 75) and then outputs a letter grade corresponding to it. I've implemented the following requested scale via an array / table:
.data
table BYTE 89d, 'A'
BYTE 79d, 'B'
BYTE 69d, 'C'
BYTE 59d, 'D'
BYTE 0d, 'F'
NumCols = 2
NumRows = 5
user_ip BYTE ?
message1 BYTE "Enter a grade value: ", 0h
message2 BYTE "The Grade of ", 0h
message3 BYTE " Yields A Letter Grade of ", 0h
I'm using the following code to sort through this array / table and output the letter grade.
mov edx, OFFSET message1
call WriteString
call readDec
mov user_ip, al
mov esi, OFFSET user_ip
mov edi, OFFSET table
mov ecx, NumRows
L1:
CMPSB
jae L2
add edi, NumCols
Loop L1
L2:
mov edx, OFFSET message2
call WriteString
mov al, user_ip
call WriteDec
mov edx, OFFSET message3
call WriteString
mov edx, edi
call WriteString
call Crlf
With an input of 75, I'm being presented with: "The Grade of 75 Yields A Letter Grade of EC;D". The Program also temporarily stops working.
I'm confident it has something to do with pointers and data sizes. My ideal goal is to store the value of the letter grade in a variable, but I can't seem to find a way to do it given the data size needed to use pointers. Any ideas of how to do this?
You are calling WriteString but the values in your table are characters not strings. The difference in this case is that they are not zero terminated. Either use WriteChar if you have that, or put a zero in your table but then don't forget to adjust NumCols too.
Also note that CMPSB increments both pointers which means your comparisons will be wrong. You should probably just use the non-string CMP especially since the user_ip is already in register AL.
PS: Finally somebody who uses a table :)
I am having a problem understanding why my cmp statements are not working correctly.
When I run this, I enter 0 in first and it goes to storeValue. I enter 0 in for the second value and it goes to the searchArray like it is supposed to.
I have breakpoints on my cmp and jump statements and a watch on AL so I don't understand why it's storing the first 0 when it should prompt for the search value at that point.
Thanks for looking.
.DATA
prompt1 BYTE "Enter a value to put in array or 0 to search array.", 0
prompt2 BYTE "Enter a value to search array for.",0
intArray DWORD ?
numElem DWORD 0
SearchVal DWORD ?
resultNope BYTE "Not in array.",0
.CODE
_MainProc PROC
lea ebx, intArray ;get the address of array.
start: input prompt1, intArray, 50 ;read in integer
atod intArray ;convert to int
mov al, [ebx] ;move int to register
cmp al, 0 ;if integer is positive - store it!
jg storeValue ;JUMP!
cmp al, 0 ;if 0 - time to search array!
je searchArray ;JUMP!
storeValue: add numElem, 1 ;Adds 1 to num of elements in array.
mov [ebx], al ;moves number into array.
add ebx, 1 ;increment to next array address.
jmp start ;get next number for array. JUMP!
searchArray:input prompt2, searchVal, 50 ;What are we searching array for?
atod searchVal ;convert to int
lea ebx, intArray ;get address of array.
mov ecx, 1 ;set loop counter to 1.
You have forgotten to show how input and atod work. Looking into my crystal ball, I guess that input expects a buffer to store the user input as text, and the argument 50 is presumably its size. Notice that you don't have such a buffer and you don't even have 50 bytes space. I also think that since atod apparently only takes 1 argument, which is the text buffer to convert, it presumably returns the value in eax. This is also reinforced by the fact that your storeValue writes from al which would make no sense otherwise.
Long story short:
allocate a buffer of the proper size for the text entered
pass this array to atod
do not clobber al after the call to atod
(Applies to the search part too.)