x86 Assembly: Part Two-- Flags
CS 301 Lecture, Dr. Lawlor, 2005/09/26
The one thing you need to be able to do HW3 is the ability to
collect input from the user. I've added a "read_input" subroutine
to NetRun that should allow you to enter input. To use it,
- Say "call read_input" as the FIRST LINE in your assembly program.
This routine may trash (i.e., change) all other registers, so be sure
to call it before doing anything else! read_input, like any subroutine, returns its value in the %eax register.
- Use %eax and do whatever computation you need to do.
- In the NetRun GUI, click "Input Data": "Enabled" to display the input data edit box.
- Enter the program's input data--just numbers--in the input data edit box.
- Hit "Run!". The program will read the input you've typed in.
You can call "read_input" from C or C++, too--it takes no parameters, and returns the integer read in.
EFLAGS
The "EFLAGS" register on x86 stores a bunch of flags, as shown on page 37 of the Intel arch manual Volume
1. The important flags include:
- ZF-- The "zero flag". Set whenever the previous arithmetic result
was zero. Can be used by the "jz" (jump if last result was zero) or
"jnz" instructions. "je" (jump if equal) and "jne" (jump if not equal)
are just aliases of jz & jnz, because if the difference is zero,
then the two values are equal. For example, this code checks if the input is equal to 4:
call read_input
cmp $4,%eax
je equal
add $20, %eax # If not equal, add
equal: # If equal, just return
- CF--The "carry flag". Set to
indicate the bit that carries out of an addition or subtraction.
Can be used by the "jc" (jump if carry flag is set) instruction.
Set by all the arithmetic instructions.
Can be added into another arithmetic operation with "adc" (add with
carry). For example, you can preserve the bit overflowing out of
a big add like this:
mov $0x8000ff00,%eax
add %eax,%eax
mov $0,%eax
adc %eax,%eax
"adc" is used in the compiler's implementation of the 64-bit "long
long" datatype, and in general in "multiple precision arithmetic"
software, like the GNU Multiple Precision Arithmetic Library. It'd also be used to implement overflow checking in a careful compiler, like
The carry and zero flags are also used by the unsigned comparison
instructions: "jb" (jump if unsigned below), "jbe" (jump if unsigned
below or equal), "ja" (jump if unsigned above), and "jae" (jump if
unsigned above or equal) in the usual way.
- SF-- The "sign flag", which indicates a negative signed result. Used together with OF to implement signed comparison.
- OF-- The "overflow flag". Set by subtract, add, and compare, and
used in the signed comparison instructions "jl" (jump if less than),
"jle" (jump if less than or equal to), "jg" (jump if greater than), and
"jge" (jump if greater than or equal to) instructions. If you
stare at it hard enough, you can read the definitions, work out exactly
what SF and OF do, and convince yourself they do the right thing.
They do.
You've also got to be aware of which instructions set which
flags. For example, the "cmp", "and" (bitwise AND), "sub", and
"add" instructions set all the flags; "inc" (increment by 1) and "dec"
(decrement by 1) set everything but CF; while "mov" and all the jump
instructions don't mess with the flags. It's easy to accidentally
overwrite flags you care about if there's too much stuff between the
time the flag is set and the time it's read!
You can actually look at the flags with the "lahf" instruction, which
copies the important bits of EFLAGS into %ah (bits 8-16 of eax
get EFLAGS(SF:ZF:0:AF:0:PF:1:CF)):
call read_input
cmp $-3,%eax
mov $0,%eax
lahf
Note there's NO way to get at the flags, or to directly call the flag-using instructions in C! None!