Вопрос

I am attempting to learn how to write and understand x86 Assembly as well as how to use GDB and related tools effectively. To do this, I am using DDD as a front-end for GDB.

I am having trouble understanding what the condition flags (eflags?) are given that they appear to all be stored in the same register. I will post the register, the assembly code, and the related C code. Thank you for any assistance.

The register is displayed as follows at the given breakpoint: 0x293 [CF AF SF IF]

The following is the C code being run. (This is not an example of my coding style. I am trying to force GCC to use the compl operation.)

int main( int argc, char* argv[] )
{
  int a = 0;
  int b = 2;
  if( a == b ) // There is a breakpoint here!
    goto EQUAL;
  else
    goto NEQUAL;

  EQUAL:
    return 3;

  NEQUAL:
    return 1;
}

The following is the assembly my machine broke it down into:

Dump of assembler code for function main:
0x0000000000400474 <+0>:     push   %rbp
0x0000000000400475 <+1>:     mov    %rsp,%rbp
0x0000000000400478 <+4>:     mov    %edi,-0x14(%rbp)
0x000000000040047b <+7>:     mov    %rsi,-0x20(%rbp)
0x000000000040047f <+11>:    movl   $0x0,-0x8(%rbp)
0x0000000000400486 <+18>:    movl   $0x2,-0x4(%rbp)
0x000000000040048d <+25>:    mov    -0x8(%rbp),%eax
0x0000000000400490 <+28>:    cmp    -0x4(%rbp),%eax
0x0000000000400493 <+31>:    jne    0x40049d <main+41> # Break point here
0x0000000000400495 <+33>:    nop
0x0000000000400496 <+34>:    mov    $0x3,%eax
0x000000000040049b <+39>:    jmp    0x4004a3 <main+47>
0x000000000040049d <+41>:    nop
0x000000000040049e <+42>:    mov    $0x1,%eax
0x00000000004004a3 <+47>:    leaveq 
0x00000000004004a4 <+48>:    retq   
End of assembler dump.
Это было полезно?

Решение

The eflags register is made up of single bits, each being a flag.

When displaying the flags, they can be combined in a larger numeric entity (like 0x293 in your example), or each can have a symbol on its own (like in "[CF AF SF IF]" with the carry flag CF, adjust flag AF, sign flag SF and interrupt flag IF.

The Intel 64 and IA 32 Architecture Software Developer's Manual Vol. 1 describes the flags in detail in chapter 3.4.3.

The most important (for application developers) are:

bit | sym | name
------------------
  0 |  CF | carry
  1 |  -- | (always 1)
  2 |  PF | parity
  3 |  -- | (always 0)
  4 |  AF | adjust
  5 |  -- | (always 0)
  6 |  ZF | zero
  7 |  SF | sign
  8 |  TF | trap
  9 |  IF | interrupt
 10 |  DF | direction
 11 |  OF | overflow

Combining those in your example (CF AF SF IF) gives the binary value 1010010011, where the rightmost digit is the carry flag, and the leftmost the interrupt flag. Converted to hexadecimal it gives exactly 0x293.

Другие советы

The (R/E)FLAGS register contains the following condition flags:

OF (overflow flag) - it's used to determine overflow of integer arithmetic operations (e.g. ADD, ADC, SUB, SBB instructions) on signed operands. Conditional branches/jumps (the Jcc instruction) can directly examine this flag.

SF (sign flag) - it's used to determine whether the result of the last integer arithmetic operation is a negative value or not, SF is basically a copy of the sign bit (=most significant bit) of the result. Again, conditional branches/jumps can examine it directly.

ZF (zero flag) - it's used to determine whether the result of the last integer arithmetic or logical operation is 0 or not. Conditional branches/jumps can examine it directly as well.

CF (carry flag) - similarly to the overflow flag (OF) it can be used to determine overflow of integer arithmetic operations performed on unsigned operands. Note the difference: CF for unsigned, OF for signed. Also note that the CPU often calculates both CF and OF and it's the programmer's responsibility to examine the correct flag. In most cases the CPU cannot and does not distinguish between signed and unsigned operands because the result is calculated in the same way, and it's all data to the CPU. It's the programmer's responsibility to interpret values as signed or unsigned, not the CPU's. Conditional branches/jumps can examine CF directly as well.

Edit: there are also rotate through carry instructions (RCL and RCR), which use CF.

Integer comparison (with the CMP instruction) results in the four above flags set. If you intend to compare unsigned integers, you then examine ZF and/or CF. For signed integer comparison you need to examine ZF and/or the SF + OF pair. See the conditional branch/jump instructions (Jcc: JB, JNC, JE, JNGE, etc etc).

The parity flag, PF, and the auxiliary carry flag, AF, are the other condition flags, but they are used rarely.

The rest of the bits in (R/E)FLAGS are either system or control flags. Of them you probably want to know just two:

DF (direction flag) - it's used to set the direction of string instructions. String instructions are used for sequential accessing of memory for things like block memory copy, block memory comparison, block memory search, block memory fill (see MOVSB/W/D/Q, CMPSB/W/D/Q, SCASB/W/D/Q, STOSB/W/D/Q, LODSB/W/D/Q). The value of this flag tells whether the memory operand address(es) should be incremented or decremented after each iteration.

IF (interrupt flag) - it's used to enable or disable handling of hardware interrupts. If you get into very low-level programing (drivers, OS kernel and the like), you'll have to work with this flag.

That's about it. All the details are available in the official CPU documentation from Intel and AMD. Go, download the CPU manuals.

Edit: You may find these questions/answers useful: 1, 2.

Also useful to know is that:

  • not all instructions modify condition flags
  • some modify them always and set to 0 or 1
  • some set them to unspecified values and you can't rely on or expect a 0 or 1
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top