Please indicate the source if you want to reprint: http://blog.csdn.net/gaoxiangnumber1.
3.6 Control
Machine code provides two basic low-level mechanisms for implementing conditional behavior: it tests data values and then either alters the control flow or the data flow based on the result of these tests.
3.6.1 Condition Codes
CPU maintains a set of single-bit condition code registers describing attributes of the most recent arithmetic or logical operation. These registers can then be tested to perform conditional branches.
The most useful condition codes are:
CF: Carry Flag. The most recent operation generated a carry out of the most significant bit. Used to detect overflow for unsigned operations.
ZF: Zero Flag. The most recent operation yielded zero.
SF: Sign Flag. The most recent operation yielded a negative value.
OF: Overflow Flag. The most recent operation caused a two’s-complement overflow—either negative or positive.
Suppose we used one of the add instructions to perform the equivalent of the C assignment t=a+b, where variables a, b, and t are integers. Then the condition codes would be set according to the following C expressions:
The leal instruction does not alter any condition codes, since it is intended to be used in address computations. Otherwise, all of the instructions listed in Figure 3.7 cause the condition codes to be set.
Two instruction classes (having 8, 16, and 32-bit forms) set condition codes without altering any other registers:
The cmp instructions set the condition codes according to the differences of their two operands. They behave in the same way as the sub instructions, except that they set the condition codes without updating their destinations. With ATT format, the operands are listed in reverse order, making the code difficult to read. These instructions set the zero flag if the two operands are equal. The other flags can be used to determine ordering relations between the two operands.
The test instructions behave in the same manner as the and instructions, except that they set the condition codes without altering their destinations. Typically, the same operand is repeated (e.g., testl %eax,%eax to see whether %eax is negative, zero, or positive), or one of the operands is a mask indicating which bits should be tested.
3.6.2 Accessing the Condition Codes
There are three common ways of using the condition codes:
(1) we can set a single byte to 0 or 1 depending on some combination of the condition codes.
(2) we can conditionally jump to some other part of the program.
(3) we can conditionally transfer data.
The set instructions differ from one another based on which combinations of condition codes they consider, as indicated by the different suffixes for the instruction names. The suffixes denote different conditions and not different operand sizes.
A set instruction has either one of the eight single-byte register elements or a single-byte memory location as its destination, setting this byte to either 0 or 1.
To generate a 32-bit result, we must also clear the high-order 24 bits. A typical instruction sequence to compute the C expression a < b, where a and b are both of type int, proceeds as follows:
ZF: Zero Flag. The most recent operation yielded zero.
SF: Sign Flag. The most recent operation yielded a negative value.
OF: Overflow Flag. The most recent operation caused a two’s-complement
Unlike in C, machine code does not associate a data type with each program value. Instead, it mostly uses the same instructions for the two cases, because many arithmetic operations have the same bit-level behavior for unsigned and two’s-complement arithmetic. Some circumstances require different instructions to handle signed and unsigned operations, such as using different versions of right shifts, division and multiplication instructions, and different combinations of condition codes.
3.6.3 Jump Instructions and Their Encodings
A jump instruction can cause the execution to switch to a completely new position in the program. These jump destinations are generally indicated in assembly code by a label.
The instruction jmp .L1 will cause the program to skip over the movl instruction and instead resume execution with the popl instruction.
In generating the object-code file, the assembler determines the addresses of all labeled instructions and encodes the jump targets (the addresses of the destination instructions) as part of the jump instructions.
The jmp instruction jumps unconditionally. It can be either a direct jump, where the jump target is encoded as part of the instruction, or an indirect jump, where the jump target is read from a register or a memory location.
Direct jumps are written in assembly by giving a label as the jump target, e.g., the label “.L1” in the code shown.
Indirect jumps are written using ‘*’ followed by an operand specifier using one of the formats described in following table.
E.g.:
The instruction “jmp %eax” uses the value in register %eax as the jump target, and the instruction “jmp (%eax)” reads the jump target from memory, using the value in %eax as the read address.
There are several different encodings for jumps:
***PC relative addressing: encode the difference between the address of the target instruction and the address of the instruction immediately following the jump. These offsets can be encoded using 1, 2, or 4 bytes.
***Give an “absolute” address: using 4 bytes to directly specify the target.
The assembler and linker select the appropriate encodings of the jump destinations.
An example of PC-relative addressing: the jle instruction on line 1 jumps forward to a higher address, while the jg instruction on line 8 jumps back to a lower one.
The disassembled version of the “.o” format generated by the assembler is as follows:
On the right, the jump targets are indicated as 0x17 for the jump instruction on line 1 and 0xa for the jump instruction on line 7.
The target of the first jump instruction is encoded (in the second byte) as 0xd (decimal 13). Adding this to 0xa (decimal 10, the address of the following instruction), we get jump target address 0x17 (decimal 23), the address of the instruction on line 8.
The target of the second jump instruction is encoded as 0xf3 (decimal −13) using a single-byte, two’s-complement representation. Adding this to 0x17 (decimal 23), the address of the instruction on line 8, we get 0xa (decimal 10), the address of the instruction on line 2.
The value of the program counter when performing PC-relative addressing is the address of the instruction following the jump, not that of the jump itself.
The following shows the disassembled version of the program after linking:
The instructions have been relocated to different addresses, but the encodings of the jump targets in lines 1 and 7 remain unchanged. By using a PC-relative encoding of the jump targets, the instructions can be compactly encoded (requiring just 2 bytes), and the object code can be shifted to different positions in memory without alteration.
Please indicate the source if you want to reprint: http://blog.csdn.net/gaoxiangnumber1.
Chapter 3-03
最新推荐文章于 2024-08-28 23:00:35 发布