The beauty of a program is that we can carry out a number of different behaviors based on condition and state. For example, we can make a certain task repeat until a counter reaches a defined maximum. In C programming, the program's flow is controlled by instructions such as the if-then-else and for-loop statements. The following are common instructions used in assembly language, in conjunction with program control flow. The affected register in this is the index pointer IP/EIP, which holds the current address where the next instruction to execute is located.
JMP
Short for jump, this means that the operand is an address that it will go to. It sets the EIP to the next instruction line. There are two main variations for the address: direct and indirect.
A JMP using a direct address would literally jump to the given address. Consider as an example: JMP 00401000. This will set the EIP to 00401000h.
A JMP using an indirect address would jump to an address that can only be known when the jump is executed. The address has to be retrieved or calculated somehow prior to the JMP instruction. Here are some examples:
jmp eax
jmp dword ptr [00403000]
jmp dword ptr [eax+edx]
jmp dowrd ptr [eax]
jmp dword ptr [ebx*4+eax]
CALL and RET
Similar to JMP, this goes to the address stated in the operand, but stores the address of the next instruction to the stack after the CALL instruction. The address is stored in the stack and will be used by the RET instruction later to point EIP back to it. For example, consider the following:
Address Instruction
00401000 CALL 00401100
00401005 MOV ECX, EAX
00401007
...
00401100 MOV EAX, F00BF00B
00401105 RET
When the CALL happens at the address 00401000, the top of the stack will contain the value 00401005h, which will be the return address. The code passes it to the instruction at the address 00401100, where EAX is set to F00bF00Bh. Then the RET instruction retrieves the return address from the top of the stack and sets the EIP. A subroutine or procedure is the term used for the lines of instructions from the call.
The RET instruction can optionally have an operand. The operand is the number of stack DWORDs it will release before retrieving the return address. This is useful when the stack is used within the subroutine as it serves as a cleanup of the used stack.
Conditional jumps
These are jumps that depend on the flags and the counter register:
Instruction | Flags | Description |
JZ/JE | ZF = 1 | Jump if zero/Jump if equal |
JNZ/JNE | ZF = 0 | Jump if not zero/Jump if not equal |
JS | SF = 1 | Jump if sign |
JNS | SF = 0 | Jump if not sign |
JC/JB/JNAE | CF = 1 | Jump if carry/Jump if below/Jump if not above or equal |
JNC/JNB/JAE | CF = 0 | Jump if not carry/jump if not below/Jump if above or equal |
JO | OF = 1 | Jump if overflow |
JNO | OF = 0 | Jump if not overflow |
JA/JNBE | CF = 0 and ZF = 0 | Jump if above/Jump if not below or equal |
JNA/JBE | CF = 1 or ZF = 1 | Jump if not above/Jump if below or equal |
JG/JNLE | ZF = 0 and SF = OF | Jump if greater/Jump if not less or equal |
JNG/JLE | ZF = 1 or SF != OF | Jump if not greater/Jump if less or equal |
JL/JNGE | SF != OF | Jump if less/Jump if not greater or equal |
JNL/JGE | SF = OF | Jump if not less/Jump if greater or equal |
JP/JPE | PF = 1 | Jump if parity/Jump if parity is even |
JNP/JPO | PF = 0 | Jump if not parity/Jump if parity is odd |
JCXZ | CX = 0 | Jump if CX is zero. |
JECXZ | ECX = 0 | Jump if ECX is zero. |
LOOP | ECX > 0 | Jump if ECX is not zero. Decrements ECX. |
LOOPE | ECX > 0 and ZF = 1 | Jump if ECX is not zero and zero flag is set. Decrements ECX. |
LOOPNE | ECX > 0 and ZF = 0 | Jump if ECX is not zero and zero flag is not set. Decrements ECX. |
Flagging instructions
Besides the arithmetic, bit-wise operations, interrupts, and return values from functions, these instructions are also able to set flags.
CMP performs a SUB instruction on the first and second operands, but does not modify the registers or the immediate value. It only affects the flags.
TEST performs an AND instruction on the first and second operands, but does not modify the registers or the immediate value. It only affects the flags.