Can someone help me understand why this doesn't seem to be checking whether or not the sign flag is set? Any integer I enter returns and says that the integer is positive...I can't spot why it's doing this:
INCLUDE Irvine32.inc
.data
myInput WORD ?
str1 BYTE "Enter an integer:",0
str2 BYTE "Your number is negative",0
str3 BYTE "Your number is positive",0
str4 BYTE "That is the end of this project!",0
.code
main PROC
mov edx, OFFSET str1
call WriteString
call crlf
call ReadInt
mov myInput, ax
call dumpregs
call crlf
JS L1
JNS L2
mov edx, OFFSET str4
call WriteString
call crlf
main ENDP
L1 PROC
mov edx, OFFSET str2
call WriteString
call crlf
ret
L1 ENDP
L2 PROC
mov edx, OFFSET str3
call WriteString
call crlf
ret
L2 ENDP
exit
END main
you need to add the code to set/unset the sign flag
INCLUDE Irvine32.inc
.data
myInput WORD ?
str1 BYTE "Enter an integer:",0
str2 BYTE "Your number is negative",0
str3 BYTE "Your number is positive",0
str4 BYTE "That is the end of this project!",0
.code
main PROC
mov edx, OFFSET str1
call WriteString
call crlf
call ReadInt
mov myInput, ax
call crlf
cmp ax, 0 ;here
call DumpRegs
JS L1
JNS L2
mov edx, OFFSET str4
call WriteString
call crlf
main ENDP
L1 PROC
mov edx, OFFSET str2
call WriteString
call crlf
ret
L1 ENDP
you should also add a check for a zero value
another thing i've noticed, myInput should be of type SWORD
unktehi,
As is typical for procedures in 32-bit code, ReadInt returns a 32-bit value in EAX.
As brethren stated, to use JS/JNS to test the sign of a memory variable or register value, you must first execute an instruction that will set/reset the sign flag based on the sign of the memory variable or register value. The instruction should be one that affects the sign flag, and in this case one that does not change the value of the destination operand. For memory operands, typical examples would be:
or myInput, 0
add myInput, 0
sub myInput, 0
For register operands typical examples would be:
test eax, eax
or eax, eax
Since there are only two possibilities for the sign it's not necessary to check both conditions. If the first condition is not true, then the second must be true.
js L1
; code to handle positive inputs
jmp L2
L1:
; code to handle negative inputs
L2:
There are problems with your execution path. Execution starts in main then you enter one of the other procedures with a jump, so since there was no call instruction to place a return address on the stack, the return instruction at the end of the procedure terminates the program. The exit macro at the end is never executed.
Thanks, I think I understand. I'll play with it later after work tonight and let you know if I got it to work.
Just to clarify though, if ReadInt returns a 32-bit value in EAX wouldn't it be more appropriate to have this:
call ReadInt
mov myInput, eax (make sure I change myInput to SWORD)
call crlf
cmp eax, 0 ;here
call DumpRegs
JS L1
JNS L2
Michael W - Your right, I didn't think I needed two conditional statements (JS and JNS), I put those in there because I thought that might be the reason it wasn't working.
In regards to the ret, just to clarify - are the 'ret' instructions only used when working with the stack and/or pushing and popping?
mov myInput, eax (make sure I change myInput to SWORD)
eax is a 32 bit register, use SDWORD for myInput
QuoteIn regards to the ret, just to clarify - are the 'ret' instructions only used when working with the stack and/or pushing and popping?
The RET instruction is normally used to return from a procedure, and the CALL instruction is used to call a procedure. For the following, the "top" of the stack is the address that ESP points to, or put another way, the address of the value most recently pushed and next in line to be popped. The CALL instruction effectively pushes the address of the next instruction (next after the call instruction) and then jumps to the address specified by its operand. The RET instruction effectively pops the value at the top of the stack and then blindly uses it as a jump destination. For this to work the value at the top of the stack must be a legitimate return address. This is why the code in a procedure must "balance" the stack, effectively popping anything it pushed, before executing a RET.
I see now that my "the return instruction at the end of the procedure terminates the program" was not very clear. As I understand it, and I hope someone will correct me if I don't, when Windows launches a program it calls the program's entry point, and the program can end by simply returning from this call. So if a program executed a RET and the value at the top of the stack was the return address for the call to the entry point, the program would end. Since your L1 and L2 procedures are being entered with a jump instead of a CALL, when the RET at the end executes the value at the top of the stack is the return address for the call to the entry point, and your program ends.
Ok, it looks like I still have it wrong but I'm not sure where. I think I still don't grasp how to set the high part (the signed part of eax) :
INCLUDE Irvine32.inc
.data
myInput SDWORD ?
str1 BYTE "Enter an integer:",0
str2 BYTE "Your number is negative",0
str3 BYTE "Your number is positive",0
str4 BYTE "That is the end of this project!",0
.code
main PROC
mov edx, OFFSET str1
call WriteString
call crlf
call ReadInt
mov myInput, eax
call crlf
cmp ax, 0
(Isn't this the low part of eax? what's the higher part of eax?)
or myInput, 0
call dumpregs
JS L1
mov edx, OFFSET str4
call WriteString
call crlf
main ENDP
L1 PROC
mov edx, OFFSET str2
call WriteString
call crlf
L1 ENDP
L2 PROC
mov edx, OFFSET str3
call WriteString
call crlf
L2 ENDP
exit
END main
Quote
or myInput, 0
pushf ;maybe pushfd
call dumpregs
popf
JS L1
does your dumpregs modify EFLAGS?
or
call dumpregs
or myInput, 0
JS L1
The Irvine32 dumpregs procedure preserves everything.
Using your most recent code, if I enter the number +1 I get:
EAX=00000001 EBX=7FFDF000 ECX=00000101 EDX=00403004
ESI=00000000 EDI=00000000 EBP=0012FFF0 ESP=0012FFC4
EIP=0040102E EFL=00000202 CF=0 SF=0 ZF=0 OF=0
That is the end of this project!
Your number is negative
Your number is positive
And if I enter the number -1 I get:
EAX=FFFFFFFF EBX=7FFDF000 ECX=00000101 EDX=00403004
ESI=00000000 EDI=00000000 EBP=0012FFF0 ESP=0012FFC4
EIP=0040102E EFL=00000286 CF=0 SF=1 ZF=0 OF=0
Your number is negative
Your number is positive
And the problem is that you are not properly controlling the execution path. If a positive number is entered the JS L1 jump is not taken, so str4 is displayed, then execution continues in the L1 procedure which displays str2, then execution continues in the L2 procedure which displays str3. If a negative number is entered the JS L1 jump is taken, so the L1 procedure displays str2, then execution continues in the L2 procedure which displays str3. To correct the problem you need to control the execution path with some combination of jumps, calls, and returns. I think the logic you actually want is something like this:
if negative
display str2
else
display str3
end if
display str 4
exit
And this logic could be implemented as I showed above:
js L1
; display str3
jmp L2
L1:
; display str2
L2:
; display str4
exit
I would name the procedures IsNeg and IsPos, put a RET instruction at the end of each, and use the CALL instruction to enter the procedures. And since your main procedure is not functioning as a procedure, you should consider replacing it with just a label.
cmp ax, 0
(Isn't this the low part of eax? what's the higher part of eax?)
That instruction is not needed in your most recent version of your program as the next instruction is or myInput, 0 which sets the flags according to the value in myInput. anyway to answer your question
eax is 32 bit
ax lower 16bits of eax
ah upper 8 bits of ax
al lower 8 bits of ax
i really recommend you download ollydbg so you can step through your program one instruction at a time and watch the execution flow
That is what I thought. I originally removed the 'cmp ax, 0' instruction but it still didn't seem to work. It sounds like it isn't working probably because I failed to put a jmp instruction in and control the execution properly. I'll make changes tonight - hopefully that will do it for me.
Thanks for your help!
good look with your project, unktehi:) btw have you downloaded the IrvineLibHelp file from kip irvine's site? Its invaluable if you're using the link library often
heres a link
http://kipirvine.com/asm/files/IrvineLibHelp.exe
I got it to work. Thanks for your help!!
brethren - I downloaded OllyDbg, but it looks like it will only open .exe files. I'm not sure how to save my .asm file into an .exe file. Could you point me in the right direction? I'm using Visual C++ 2008 Express Edition for my project assignments.
Quotebrethren - I downloaded OllyDbg, but it looks like it will only open .exe files. I'm not sure how to save my .asm file into an .exe file. Could you point me in the right direction? I'm using Visual C++ 2008 Express Edition for my project assignments.
when you use an assembler on an asm file it produces an object file (obj), next you use the linker to create an executable file (exe). This is the file you load into ollydbg. The great thing about an interactive debugger like olly is that you have complete control of how your program runs ie. you can watch it run one instruction at a time and observe how the flags and registers change and all sorts of other things (like interactively changing the values of registers and flags while the program is running, setting breakpoints and even altering instructions)
Every assembly programmer needs to be able to use a debugger :wink
Note: For the Intel series of processors, data transfer instructions like MOV, LODSB doe not set the flags registers only arithmetic instructions or specific flags register instructions do TEST, OR, ADD and the like.
For other processors this is not always the case. For the VAX series of processors, data transfer operations do set the Z and S-flags! This caused quite an issue when I moved from VAX/PDP-11 MACRO programming to Intell 80XX programming.
As a general note, you should return a value from a procedure in EAX that when TEST EAX,EAX or CMP EAX,???? is executed, the flags register is set appropriately.