Note: WriteString is a macro that writes the contends of edx to the console
Can someone help me understand why the values of the variables at the end of the application end up displaying the same value, when, right after their askInput macro the variables have the correct value?
.code
main PROC
askInput message1, messageSize1, var1
mov var1, edx
call WriteString
askInput message2, messageSize2, var2
mov var2, edx
call WriteString
mov edx, var1
call WriteString
mov edx, var2
call WriteString
;writeMessage label2, label2Size, var2, var2Size
;writeMessage label1, label1Size, var1, var1Size
INVOKE ExitProcess,0
main ENDP
END main
When this program runs, here is the sample output if I type in firstName for first name and lastName for last name:
Enter First Name:
firstName <-- my input
firstName <-- from WriteString after first askInput macro
Enter Last Name:
lastName <-- my input
lastName <-- from WriteString after 2nd askInput macro
lastName <-- WriteString var1?
lastName <-- WriteString var2?
shouldn't these last two strings be different?
not sure about this, actually, as i am fairly new to 32-bit, myself
but, try this................
.data
message1 DB "Enter First Name: ", 0dh, 0ah
messageSize1 DW ($ - message1)
var1 DW ?
var1Size DW ($-var1)+20
var2 DW ?
var2Size DW ($-var2)+20
Unless I'm not catching the other changes, are the only changes you made changing DWORD to DW, etc?
I believe those are legacy directives - I don't think changing those would make a difference.
I haven't used any of those, but I thought DW was used for word and DD was used for Doubleword?
Either way, I tried switching them to the legacy directives and it worked exactly the same way...
Looks like you are mixing up your handles. You are writing the value of STD_OUTPUT_HANDLE and STD_INPUT_HANDLE to the same variable, stdInHandle. Create a variable called stdOutHandle and place the value of STD_OUTPUT_HANDLE there and fix this:
stdInHandle, ; console output handle
Paul
I should probably change that anyway because that IS confusing. However, it doesn't appear to have made any affect on the behavior of the code.
Take the time and find the most simple and clear example of what do you think that it is not working in your program.
It takes too much time for people to browse more that a few lines of code especially when it is written in a confusing and not organized mode.
Hence please streamline your code to the minimum number of lines that clearey show what you think that it is going wrong.
This will help you getting help ;)
I've modified/taken out all of the code but the code that seems to be displaying strange results - hopefully this will help.
Quote from: unktehi on March 21, 2009, 11:55:24 PM
I've modified/taken out all of the code but the code that seems to be displaying strange results - hopefully this will help.
Unfortunately this is not what I wanted to teach you.
1) First of all when you make a mistake in the past and you do realize today that it was a mistake you DO NOT return in time in order to fix it ... Instead you improve yourself today.
In the same way you should have not edited your original message but instead you should have made a new post here at the end of this thread.
It is very non polite to edit a message (other than correcting errors) AFTER somebody has answered to it. In this way you are making their answers hard to understand and to follow. Also please not that this messages are not only for your understanding but can also serve for others to learn.
2) Suddenly big chunks of you code disappeared. yes it does make things smaller and slightly easier to understand BUT what if the error is exactly in the missing parts?
Both of WriteString procedure and askInput macro could contain errors. Well it is more likely that the error is in code that you have been written rather than in your book's / teacher's code.
Hence I find it amusing that you "document" the Write String procedure but you fail to document the askInput macro.
Then if you streamline some code it is still required to show all relevant parts that are needed to make it work. Data definitions and macros that you have written and it must compile and run as it is.
I did not say that it would be so easy as editing out some lines from your sample code.
3) What I wanted to teach you was different.
a) You should have streamlined your code to a minimum that is working as expected based on your current level of understanding.
b) Then you should have added new code in small steps ... one at a time ... until the "wrong" behavior would have emerged.
c) At that point you would have found a closer location of your problems and you would have a better chance of understanding where your mistake is.
IF after doing this kind of detective actions your still could not find the error then we would have had a much better explanation of what is going wrong and where you suspect that the error is in your code.
I never expected that you will cut relevant portions from your code or that you would edit your original message... mea culpa.
However based on this code:
.code
main PROC
askInput message1, messageSize1, var1
mov var1, edx
call WriteString
askInput message2, messageSize2, var2
mov var2, edx
call WriteString
mov edx, var1
call WriteString
mov edx, var2
call WriteString
INVOKE ExitProcess,0
main ENDP
END main
And assuming that WriteString is working "as expected" then it becomes obvious that the only possible error is inside "askInput" macro or in your data definitions.
I am curios: what is the purpose of sending "var1" (contents or offset?) as a parameter to your macro and then in the very same line you write EDX register contents to the "var1" location?
It looks strange to me but it is not possible to say without seeing the code for "askInput".
I'd agree with you except that after this line:
askInput message1, messageSize1, var1
WriteString writes out what is currently in edx - which is correct here. In this instance, I'm also moving the value of edx into var1 to store.
Then WriteString is also writing the correct value of edx after this line:
askInput message2, messageSize2, var2
Once a value is moved into edx using the mov directive, isn't the value completely replaced? At the end of my askInput macro I have the variable value being moved into edx.
So then, how would var1 change to the value of var2 in this area of my code?
mov edx, var1
call WriteString
mov edx, var2
call WriteString
The way I see it, my macro, other than storing a value in edx, should not touch var1. Var1 should not be touched after the first iteration of askInput.
Quote from: unktehi on March 22, 2009, 01:28:50 AM
I'd agree with you except that after this line:
askInput message1, messageSize1, var1
WriteString writes out what is currently in edx - which is correct here. In this instance, I'm also moving the value of edx into var1 to store.
Then WriteString is also writing the correct value of edx after this line:
askInput message2, messageSize2, var2
So far so good. But again I see no purpose for sending "var1" or "var2" as a parameter to your macro since the macro apparently returns the input value in EDX register...
Quote
Once a value is moved into edx using the mov directive, isn't the value completely replaced?
Of course it is... anything that was before in EDX is lost forever and ever...
Quote
At the end of my askInput macro I have the variable value being moved into edx.
This statement I find dubious...
Quote
So then, how would var1 change to the value of var2 in this area of my code?
mov edx, var1
call WriteString
mov edx, var2
call WriteString
yes it is quite "impossible" ... UNLESS you make an error somewhere else ;)
Quote
The way I see it, my macro, other than storing a value in edx, should not touch var1. Var1 should not be touched after the first iteration of askInput.
Of course... "the way YOU see it". However computers are notorious for not doing what you want or hope or "your way" but instead computers do EXACTLY as you INSTRUCT them to do... no matter how wrong and illogical your instructions might be.
Hence I still suspect that there is an error somewhere in you macro or maybe in your data definitions.
Your right, I originally had var1 passed as an argument because I was going to have the macro return a new value inside that variable. BUT, it is not needed with how I am approaching it now. I've deleted the the arguments of var1 and var2 from the askInput lines (and also modified my macro so it doesn't complain).
Changing that, although I can see was necessary for clarification, didn't change the behavior.
So then here, because I deleted it all from my original post, is the askInput macro:
askInput MACRO myCommand, messageSize
INVOKE GetStdHandle, STD_OUTPUT_HANDLE
mov stdInHandle,eax
INVOKE WriteConsole,
stdInHandle,
ADDR myCommand,
messageSize,
ADDR myBytes,
0
INVOKE GetStdHandle, STD_INPUT_HANDLE
mov stdInHandle, eax
INVOKE ReadConsole,
stdInHandle,
ADDR buffer,
BufSize - 2,
ADDR myBytes, 0
mov edx, OFFSET buffer
ENDM
Bufsize is set above as:
BufSize = 80
Here is the data definitions for these variables:
message1 BYTE "Enter First Name: ", 0dh, 0ah
messageSize1 DWORD ($ - message1)
buffer BYTE BufSize DUP(?),0dh,0ah
stdInHandle HANDLE ?
myBytes DWORD ? ; Number of bytes written or read
So... your macro is returning "OFFSET Buffer" in EDX ...
However it is the very same buffer each and every time :D
hence the very same buffer is re-used and made dirty after each macro instance.
1) First your var1 contents become "offset buffer"
you print this and it is OK
2) Your var2 contents also become "offset buffer"
You print this and it is OK
However at this time you can not print the initial buffer content because it was overwritten by the new input.
Hence at this time var1 is useless because it contains a pointer to the very same buffer where you have written your seccond input...
Got it?
Apparently what you fail to understand it that you must store the input string somewhere, each string into his own buffer or else you will lose them when you re-use the buffer.
As Bogdan is saying as as I said before. It is poor programming practice to do these type of things. You should not have one variable for two handles as I said before. How you code needs to be done in a logical way. Make separate variables for each specific usage and DO NOT share their usage. You will just confuse yourself and us. Same goes for strings.
Sorry to interrupt, Bogdan, but what he is doing is just wrong on too many levels.
Paul
Quote from: BogdanOntanu on March 22, 2009, 02:05:21 AM
So... your macro is returning "OFFSET Buffer" in EDX ...
However at this time you can not print the initial buffer content because it was overwritten by the new input.
Hence at this time var1 is useless because it contains a pointer to the very same buffer where you have written your seccond input...
Got it?
I think so, so if edx is returning the OFFSET of Buffer, then shouldn't I be able to derefence the edx by putting brackets around it. (According to the 'Introduction to Assembler' 'Addressing and Pointers' section, "Using square brackets around EAX gives access to the information at the address in EAX.") Then, by moving the derefenced value (the actual information) into either a variable name or another register, wouldn't it access the information at the new address of the new variable?
Quote from: PBrennick on March 22, 2009, 02:12:32 AM
As Bogdan is saying as as I said before. It is poor programming practice to do these type of things. You should not have one variable for two handles as I said before. How you code needs to be done in a logical way. Make separate variables for each specific usage and DO NOT share their usage. You will just confuse yourself and us. Same goes for strings.
Sorry to interrupt, Bogdan, but what he is doing is just wrong on too many levels.
Paul
Sure Paul, you are right...
Nobody can make that many mistakes in sequence unless he/she does it on purpose... I have suspected that much already ;)
However tonight Universe has chosen to express generosity by using me as a vehicle and it does not matter if there is nobody to receive this expression on the "other" side.
Quote from: PBrennick on March 22, 2009, 02:12:32 AM
You should not have one variable for two handles as I said before. How you code needs to be done in a logical way. Make separate variables for each specific usage and DO NOT share their usage.
Just FYI, I have changed the handles in the macros so that STD_OUTPUT_HANDLE are using stdOutHandle and all STD_OUTPUT_HANDLE are using stdInHandle. If you are suggesting a different handle for each usage, then am I to assume that these invoke statements shouldn't even be in macros because every instance would need a different handle name?
Quote
I think so, so if edx is returning the OFFSET of Buffer, then shouldn't I be able to derefence the edx by putting brackets around it. (According to the 'Introduction to Assembler' 'Addressing and Pointers' section, "Using square brackets around EAX gives access to the information at the address in EAX.") Then, by moving the derefenced value (the actual information) into either a variable name or another register, wouldn't it access the information at the new address of the new variable?
This is completely irrelevant. Where in this program are you using [] square brackets to dereference anything?
That issue is way too advanced for you. For now you seem to have huge problems with simple logic facts. For example the logical fact that you can not have the same glass full of water and full of oil at the very same time.
Once you had your buffer full with input1. In other words once you have your "glass" full of "watter".
Then you trow away the "watter" from your "glass" and fill your "glass" with "oil".
Or in other words you get your second input into the very same buffer.
And now you cry that you can not "drink" "watter" from the "glass" anymore! (ie you can not "print" the original contents that you yourself have thrown away (overwritten) from your buffer.
A pointer might be pointing towards buffer1 or towards buffer2 or towards something else BUT you have to HAVE something to point at "Oblio". If you have nothing to point at OR if all of you pointers point to the exact same location THEN is is kind of pointless to use pointers so to speak. (FYI "Oblio" was a cartoon about "pointers" that aired when I was still young)
"Dereference" is not the magic wand that will automatically solve your problems and do what you want. It will do what it does regardless of what you "want".
And NO you can not store an full buffer inside a small register. A register is only 32 bits. At maximum it could eventually hold 4 x 8 bit ASCII characters but not a longer string or buffer.
That is the reason why whenever we need to read mor ethan 4 characters (almost always) from the input we humans usually read into a large buffer and that can not fit inside a register...
When we need to use that buffer we can use it's address directly or via the offset operator IF we know it's location at compile time OR we could use a pointer to it if it is dynamic or we want to move around it.
But those are the very basics that you have asked about before a long time ago.
And still after such a long time you have not learned the basics yet. Now you are using macros when you have no clue what a variables is, what the address of a variable is, what the content of a variable is and what a pointer to a variable or a pointer to a buffer is...
Quote
Just FYI, I have changed the handles in the macros so that STD_OUTPUT_HANDLE are using stdOutHandle and all STD_OUTPUT_HANDLE are using stdInHandle. If you are suggesting a different handle for each usage, then am I to assume that these invoke statements shouldn't even be in macros because every instance would need a different handle name?
I suggest that you think for yourself and when we give a hint please do not assume something other that exactly what we say. Most likely what you will assume will be in the wrong direction. Paul never said that you should need a variable for every instance... it is funny and childish to even consider this.
He just said that because programming (esp in ASM) requires precision and attention to details and ability to think for yourself THEN when somebody makes such a bad choice as to use the very same variable for input and output handles... then the next action such a human does will most likely be "catastrophic" so to say...
For example: you need one input handle and one output handle. There is no purpose to obtain them every time at each macro instance.
You can simple obtain the handles once at the start of your program and you can release them once at the end of your program when you do not need them anymore.
During your program you can use the handles stored into nicely named variables.
This would be logical ... however why you choose to do otherwise is beyond "normal" comprehension.
Sorry if I am too harsh on you but I think you should put more energy and honest work into understanding the basics if you want to have a solid base for future achievements.
I think that for the time being, the program should be totally rewritten assigning unique names for each thing and I STRONGLY feel that the macros should be totally removed. They are too complex for your knowledge level at this point and will just serve to confuse you more. Do all the tasks in mainline code, get the app working. Once the app is working, then you can, one step at a time, add a macro, observe the results, etc.
This is a logical progression in the development cycle of an app.
Once you rewrite the app, post the _complete_ source so we can see how you did - this is important.
Remember, our _only_ goal is to see you succeed.
Paul
That's not the only goal Paul - lol
I wanna learn, too
- Dave
Hi dedndave,
As a rule I discourage the use of macros, the current collection of useless dribble that is offered is used mainly to try to make assembly language look and feel more like C in the mistaken belief that it will accelerate learning. To me they only obfuscate code by adding yet another layer of instructions and are of dubious value in making the finished product more readable. I tend to use only a few macros, mostly in debugging but a couple for release code (mainly CoInvoke & rgvarg) and I will only use macros that I have written myself or that I understand completely and are very predictable in the code they generate. From the standpoint of a beginner, Paul is correct, do not use macros except those that are intrinsic to your assembler, nothing at all third party or in the beginning not even those you have written yourself. It will help you to learn by doing things the long way at least at first, for example use cmp/jcc instead of .IF/.ENDIF and write your loop code manually instead of using the shortcuts (.WHILE/.ENDW). Once you understand what a loop or conditional block is doing then you can start to use macros to replace some of the more tedious coding, until then you are just learning to string together a bunch of bug injectors and calling it assembly language.
Edgar
Unktehi, are macros this chapter's lesson? If not, like the others have said, avoid them for now.
P.S. Don't be alarmed by the "serious" tone of some of these replies. Yes, it is critical to be able to find bugs... but everything in due time. Rome wasn't built in a day...
Often, when faced with such an obscure bug, the best idea is to (follow Paul's advice) and re-write the code as simply as possible. Get one thing working at a time, then add each piece until either the issue re-appears, or is resolved. Often, the issue is something simple that was overlooked or not considered fully. Happens all the time.
If it STILL doesn't work properly, post the entire source and executable. One of us will take a look at it and give some hints.
QuoteUnktehi, are macros this chapter's lesson?
Let's be more specific, here. If macros _are_ this chapter's lession, you are not ready for that lesson. Go back and redo the previous lessons using the advice you have received here. The way you are approaching variables and strings tells me you are developing bad programming habits that will mean you will re-invent these problems everytime you write an app.
About macros, one of the most deceptive things I have seen them do when troubleshooting other's work is that they were not aware that if they call an API in the macro some registers (especially, almost always eax) get destroyed. This can cause problems in your mainline code if you are not aware of this and have not taken the appropriate precautions. As Donkey so well said, they should be avoided almost always. The other thing is that error reporting in respect to macros is very vague. The error report will only reference the line that called it leaving you with what could be a complicated macro with an error and no way of knowing where the error is. That is in the instance of a syntaxical error. Soft errors (errors in logic) will usually assemble without a hitch but fail at runtime leaving you scratching your head.
Strings are not static or constants and _can_ be modified at runtime but strings that are being used as labels should not be modified. It is bad form. Advanced users will sometimes do things like that to save on program size but you should not consider that as a goal at this point. Make a separate string for each usage or prompt.
There is a reason why the Hello World program is so simply made. Use that as an example and build from it. Make a Hello World Console app. Get it working and then start adding other stuff to it.
... and never modify a code posting. At this point I have no way of looking at your problem in depth as the code is lost.
Paul