abrash-black-book/02-02.md
2013-12-30 20:26:41 +11:00

100 lines
No EOL
5.5 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#### Transformation Inefficiencies {#Heading5}
No matter how well an implementation is derived from the corresponding
design, however, high-level languages like C/C++ and Pascal inevitably
introduce additional transformation inefficiencies, as shown in Figure
2.1.
The process of turning a design into executable code by way of a
high-level language involves two transformations: one performed by the
programmer to generate source code, and another performed by the
compiler to turn source code into machine language instructions.
Consequently, the machine language code generated by compilers is
usually less than optimal given the requirements of the original design.
High-level languages provide artificial environments that lend
themselves relatively well to human programming skills, in order to ease
the transition from design to implementation. The price for this ease of
implementation is a considerable loss of efficiency in transforming
source code into machine language. This is particularly true given that
the x86 family in real and 16-bit protected mode, with its specialized
memory-addressing instructions and segmented memory architecture, does
not lend itself particularly well to compiler design. Even the 32-bit
mode of the 386 and its successors, with their more powerful addressing
modes, offer fewer registers than compilers would like.
![](images/02-01.jpg)\
**Figure 2.1**  *The high-level language transformation
inefficiencies.*
Assembly, on the other hand, is simply a human-oriented representation
of machine language. As a result, assembly provides a difficult
programming environment—the bare hardware and systems software of the
computer—*but properly constructed assembly programs suffer no
transformation loss*, as shown in Figure 2.2.
Only one transformation is required when creating an assembler program,
and that single transformation is completely under the programmer's
control. Assemblers perform no transformation from source code to
machine language; instead, they merely map assembler instructions to
machine language instructions on a one-to-one basis. As a result, the
programmer is able to produce machine language code that's precisely
tailored to the needs of each task a given application requires.
![](images/02-02.jpg)\
**Figure 2.2**  *Properly constructed assembly programs suffer no
transformation loss.*
The key, of course, is the programmer, since in assembly the programmer
must essentially perform the transformation from the application
specification to machine language entirely on his or her own. (The
assembler merely handles the *direct* translation from assembly to
machine language.)
#### Self-Reliance {#Heading6}
The first part of assembly language optimization, then, is self. An
assembler is nothing more than a tool to let you design machine-language
programs without having to think in hexadecimal codes. So assembly
language programmers—unlike all other programmers—must take full
responsibility for the quality of their code. Since assemblers provide
little help at any level higher than the generation of machine language,
the assembly programmer must be capable both of coding any programming
construct directly and of controlling the PC at the lowest practical
level—the operating system, the BIOS, even the hardware where necessary.
High-level languages handle most of this transparently to the
programmer, but in assembly everything is fair—and necessary—game, which
brings us to another aspect of assembly optimization: knowledge.
#### Knowledge {#Heading7}
In the PC world, you can never have enough knowledge, and every item you
add to your store will make your programs better. Thorough familiarity
with both the operating system APIs and BIOS interfaces is important;
since those interfaces are well-documented and reasonably
straightforward, my advice is to get a good book or two and bring
yourself up to speed. Similarly, familiarity with the PC hardware is
required. While that topic covers a lot of ground—display adapters,
keyboards, serial ports, printer ports, timer and DMA channels, memory
organization, and more—most of the hardware is well-documented, and
articles about programming major hardware components appear frequently
in the literature, so this sort of knowledge can be acquired readily
enough.
The single most critical aspect of the hardware, and the one about which
it is hardest to learn, is the CPU. The x86 family CPUs have a complex,
irregular instruction set, and, unlike most processors, they are neither
straightforward nor wellregarding true code performance. What's more,
assembly is so difficult to learn that most articles and books that
present assembly code settle for code that just works, rather than code
that pushes the CPU to its limits. In fact, since most articles and
books are written for inexperienced assembly programmers, there is very
little information of any sort available about how to generate
high-quality assembly code for the x86 family CPUs. As a result,
knowledge about programming them effectively is by far the hardest
knowledge to gather. A good portion of this book is devoted to seeking
out such knowledge.
------------------- ------------------------------------------------------------------------------------------------------------------------------
![](images/i.jpg) *Be forewarned, though: No matter how much you learn about programming the PC in assembly, there's always more to discover.*
------------------- ------------------------------------------------------------------------------------------------------------------------------