News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Checking sign flag

Started by unktehi, February 25, 2009, 06:04:08 AM

Previous topic - Next topic

unktehi

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

brethren

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

brethren

another thing i've noticed, myInput should be of type SWORD

MichaelW

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.
eschew obfuscation

unktehi

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

unktehi

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?

brethren

mov   myInput, eax (make sure I change myInput to SWORD)

eax is a 32 bit register, use SDWORD for myInput

MichaelW

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.


eschew obfuscation

unktehi

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

cmpxchg

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

MichaelW

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.
eschew obfuscation

brethren

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

unktehi

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!

brethren

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

unktehi

I got it to work.  Thanks for your help!!