The MASM Forum Archive 2004 to 2012

General Forums => The Campus => Topic started by: unktehi on February 25, 2009, 06:04:08 AM

Title: Checking sign flag
Post by: unktehi on February 25, 2009, 06:04:08 AM
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
Title: Re: Checking sign flag
Post by: brethren on February 25, 2009, 09:08:50 AM
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
Title: Re: Checking sign flag
Post by: brethren on February 25, 2009, 09:13:01 AM
another thing i've noticed, myInput should be of type SWORD
Title: Re: Checking sign flag
Post by: MichaelW on February 25, 2009, 10:38:18 AM
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.
Title: Re: Checking sign flag
Post by: unktehi on February 25, 2009, 04:13:25 PM
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
Title: Re: Checking sign flag
Post by: unktehi on February 25, 2009, 04:15:16 PM
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?
Title: Re: Checking sign flag
Post by: brethren on February 25, 2009, 08:17:47 PM
mov   myInput, eax (make sure I change myInput to SWORD)

eax is a 32 bit register, use SDWORD for myInput
Title: Re: Checking sign flag
Post by: MichaelW on February 26, 2009, 12:19:05 AM
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.


Title: Re: Checking sign flag
Post by: unktehi on February 26, 2009, 05:17:47 AM
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
Title: Re: Checking sign flag
Post by: cmpxchg on February 26, 2009, 06:00:54 AM
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
Title: Re: Checking sign flag
Post by: MichaelW on February 26, 2009, 07:25:50 AM
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.
Title: Re: Checking sign flag
Post by: brethren on February 26, 2009, 08:59:25 AM
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
Title: Re: Checking sign flag
Post by: unktehi on February 26, 2009, 06:13:29 PM
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!
Title: Re: Checking sign flag
Post by: brethren on February 26, 2009, 06:57:59 PM
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
Title: Re: Checking sign flag
Post by: unktehi on February 27, 2009, 12:47:14 AM
I got it to work.  Thanks for your help!!
Title: Re: Checking sign flag
Post by: unktehi on February 27, 2009, 02:34:40 AM
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.
Title: Re: Checking sign flag
Post by: brethren on February 28, 2009, 08:05:04 PM
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
Title: Re: Checking sign flag
Post by: BATSoftware on March 01, 2009, 03:39:02 PM
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.