Change bold code snippets to inline code blocks
This commit is contained in:
parent
f658bfbb40
commit
3c76d884ef
185 changed files with 1772 additions and 1772 deletions
60
07-05.md
60
07-05.md
|
|
@ -80,25 +80,25 @@ BIT_PATTERN=BIT_PATTERN SHL 1
|
|||
|
||||
#### NOT Flips Bits—Not Flags {#Heading9}
|
||||
|
||||
The **NOT** instruction flips all the bits in the operand, from 0 to 1
|
||||
or from 1 to 0. That's as simple as could be, but **NOT** nonetheless
|
||||
The `NOT` instruction flips all the bits in the operand, from 0 to 1
|
||||
or from 1 to 0. That's as simple as could be, but `NOT` nonetheless
|
||||
has a minor but interesting talent: It doesn't affect the flags. That
|
||||
can be irritating; I once spent a good hour tracking down a bug caused
|
||||
by my unconscious assumption that **NOT** does set the flags. After all,
|
||||
by my unconscious assumption that `NOT` does set the flags. After all,
|
||||
every other arithmetic and logical instruction sets the flags; why not
|
||||
**NOT**? Probably because **NOT** isn't considered to be an arithmetic
|
||||
`NOT`? Probably because `NOT` isn't considered to be an arithmetic
|
||||
or logical instruction at all; rather, it's a data manipulation
|
||||
instruction, like **MOV** and the various rotates. (These are **RCR,
|
||||
RCL, ROR,** and **ROL,** which affect only the Carry and Overflow
|
||||
instruction, like `MOV` and the various rotates. (These are `RCR`,
|
||||
`RCL`, `ROR`, and `ROL`, which affect only the Carry and Overflow
|
||||
flags.) NOT is often used for tasks, such as flipping masks, where
|
||||
there's no reason to test the state of the result, and in that context
|
||||
it can be handy to keep the flags unmodified for later testing.
|
||||
|
||||
> 
|
||||
> Besides, if you want to **NOT** an operand and set the flags in the
|
||||
> process, you can just **XOR** it with -1. Put another way, the only
|
||||
> functional difference between **NOT AX** and **XOR AX,0FFFFH** is that
|
||||
> **XOR** modifies the flags and **NOT** doesn't.
|
||||
> Besides, if you want to `NOT` an operand and set the flags in the
|
||||
> process, you can just `XOR` it with -1. Put another way, the only
|
||||
> functional difference between `NOT AX` and `XOR AX,0FFFFH` is that
|
||||
> `XOR` modifies the flags and `NOT` doesn't.
|
||||
|
||||
The x86 instruction set offers many ways to accomplish almost any task.
|
||||
Understanding the subtle distinctions between the instructions—whether
|
||||
|
|
@ -109,17 +109,17 @@ you're trying to minimize branching.
|
|||
#### Incrementing with and without Carry {#Heading10}
|
||||
|
||||
Another case in which there are two slightly different ways to perform a
|
||||
task involves adding 1 to an operand. You can do this with **INC,** as
|
||||
in **INC AX,** or you can do it with **ADD,** as in **ADD AX,1.** What's
|
||||
the difference? The obvious difference is that **INC** is usually a byte
|
||||
or two shorter (the exception being **ADD AL,1,** which at two bytes is
|
||||
the same length as **INC AL**), and is faster on some processors. Less
|
||||
obvious, but no less important, is that **ADD** sets the Carry flag
|
||||
while **INC** leaves the Carry flag untouched.
|
||||
task involves adding 1 to an operand. You can do this with `INC`, as
|
||||
in `INC AX`, or you can do it with `ADD`, as in `ADD AX,1`. What's
|
||||
the difference? The obvious difference is that `INC` is usually a byte
|
||||
or two shorter (the exception being `ADD AL,1`, which at two bytes is
|
||||
the same length as `INC AL`), and is faster on some processors. Less
|
||||
obvious, but no less important, is that `ADD` sets the Carry flag
|
||||
while `INC` leaves the Carry flag untouched.
|
||||
|
||||
Why is that important? Because it allows **INC** to function as a data
|
||||
Why is that important? Because it allows `INC` to function as a data
|
||||
pointer manipulation instruction for multi-word arithmetic. You can use
|
||||
**INC** to advance the pointers in code like that shown in Listing 7.5
|
||||
`INC` to advance the pointers in code like that shown in Listing 7.5
|
||||
without having to do any work to preserve the Carry status from one
|
||||
addition to the next.
|
||||
|
||||
|
|
@ -137,7 +137,7 @@ LOOP_TOP:
|
|||
LOOP LOOP_TOP
|
||||
```
|
||||
|
||||
If **ADD** were used, the Carry flag would have to be saved between
|
||||
If `ADD` were used, the Carry flag would have to be saved between
|
||||
additions, with code along the lines shown in Listing 7.6.
|
||||
|
||||
**LISTING 7.6 L7-6.ASM**
|
||||
|
|
@ -158,38 +158,38 @@ It's not that the Listing 7.6 approach is necessarily better or worse;
|
|||
that depends on the processor and the situation. The Listing 7.6
|
||||
approach is *different,* and if you understand the differences, you'll
|
||||
be able to choose the best approach for whatever code you happen to
|
||||
write. (**DEC** has the same property of preserving the Carry flag, by
|
||||
write. (`DEC` has the same property of preserving the Carry flag, by
|
||||
the way.)
|
||||
|
||||
There are a couple of interesting aspects to the last example. First,
|
||||
note that **LOOP** doesn't affect any flags at all; this allows the
|
||||
note that `LOOP` doesn't affect any flags at all; this allows the
|
||||
Carry flag to remain unchanged from one addition to the next. Not
|
||||
altering the arithmetic flags is a common characteristic of program
|
||||
control instructions (as opposed to arithmetic and logical instructions
|
||||
like **SUB** and **AND,** which do alter the flags).
|
||||
like `SUB` and `AND`, which do alter the flags).
|
||||
|
||||
> 
|
||||
> The rule is not that the arithmetic flags change whenever the CPU
|
||||
> performs a calculation; rather, the flags change whenever you execute an
|
||||
> arithmetic, logical, or flag control (such as **CLC** to clear the Carry
|
||||
> arithmetic, logical, or flag control (such as `CLC` to clear the Carry
|
||||
> flag) instruction.
|
||||
|
||||
Not only do **LOOP** and **JCXZ** not alter the flags, but **REP MOVS**,
|
||||
Not only do `LOOP` and `JCXZ` not alter the flags, but `REP MOVS`,
|
||||
which counts down CX to 0, doesn't affect the flags either.
|
||||
|
||||
The other interesting point about the last example is the use of
|
||||
**LAHF** and **SAHF,** which transfer the low byte of the FLAGS register
|
||||
`LAHF` and `SAHF`, which transfer the low byte of the FLAGS register
|
||||
to and from AH, respectively. These instructions were created to help
|
||||
provide compatibility with the 8080's (that's *8080*, not *8088*)
|
||||
**PUSH** **PSW** and **POP PSW** instructions, but turn out to be
|
||||
`PUSH` `PSW` and `POP PSW` instructions, but turn out to be
|
||||
compact (one byte) instructions for saving and restoring the arithmetic
|
||||
flags. A word of caution, however: **SAHF** restores the Carry, Zero,
|
||||
flags. A word of caution, however: `SAHF` restores the Carry, Zero,
|
||||
Sign, Auxiliary Carry, and Parity flags—but *not* the Overflow flag,
|
||||
which resides in the high byte of the FLAGS register. Also, be aware
|
||||
that **LAHF** and **SAHF** provide a fast way to preserve the flags on
|
||||
that `LAHF` and `SAHF` provide a fast way to preserve the flags on
|
||||
an 8088 but are relatively slow instructions on the 486 and Pentium.
|
||||
|
||||
There are times when it's a clear liability that **INC** doesn't set the
|
||||
There are times when it's a clear liability that `INC` doesn't set the
|
||||
Carry flag. For instance
|
||||
|
||||
```nasm
|
||||
|
|
|
|||
Loading…
Reference in a new issue