Changes from the Second Edition
The first edition of this book was published with a copyright of 2003,
while the second had a copyright of 2011. Considering the rapid
evolution of computer technology, the book content has held up
surprisingly well. Intel x86 machines running C programs under Linux
(and related operating systems) has proved to be a combination that
continues to encompass many systems today. However, changes in
hardware technology, compiler, program library interfaces, and the
experience of many instructors teaching the material have prompted a
The biggest overall change from the second edition is that we have
switched our presentation from one based on a mix of IA32 and x86-64
to one based exclusively on x86-64. This shift in focus affected the
contents of many of the chapters. Here is a summary of the significant
- Chapter 1: A Tour of Computer Systems.
We have moved the discussion of Amdahl's Law into this chapter.
- Chapter 2: Representing and Manipulating Data.
A consistent bit of feedback from readers and reviewers is that some
of the material in this chapter can be a bit overwhelming. So we have
tried to make the material more accessible by clarifying the points at
which we delve into a more mathematical style of presentation. This
enables readers to first skim over mathematical details to get a
high-level overview and then return for a more thorough reading.
- Chapter 3: Machine-Level Representation of Programs. We
have converted from the earlier presentation based on a mix of IA32
and x86-64 to one based entirely on x86-64. We have also updated for
the style of code generated by more recent versions of gcc.
The result is a substantial rewriting, including changing the order in
which some of the concepts are presented. We also have included, for
the first time, a presentation of the machine-level support for
programs operating on floating-point data. We have created a
aside describing IA32 machine code for legacy reasons. Once students
know x86-64, the step (back) to IA32 is fairly simple.
- Chapter 4: Processor Architecture. We have revised the
earlier processor design, based on a 32-bit architecture, to one that
supports 64-bit words and operations. We also rewrote all of the
machine code to use x86-64 procedure call conventions.
- Chapter 5: Optimizing Program Performance.
We have updated the material to reflect the performance capabilities
of recent generations of x86-64 processors. With the introduction of
more functional units and more sophisticated control logic, the
model of program performance we developed based on a data-flow
representation of programs has become an even more reliable predictor of
performance than it was before.
- Chapter 6: The Memory Hierarchy.
We have updated the material to reflect more recent technology.
- Chapter 7: Linking. We have rewritten this chapter for
x86-64, expanded the discussion of using the GOT and PLT to create
position-independent code, and added a new section on a powerful and
useful linking technique known as library interpositioning.
- Chapter 8: Exceptional Control Flow.
We have provided a cleaner and more precise description of process graphs.
We have also added a more rigorous treatment of signal handlers, including
async-signal-safe functions, specific guidelines for writing signal
handlers, and using sigsuspend to wait for handlers.
- Chapter 10: System-Level I/O.
We have added a new section on files and the file hierarchy.
- Chapter 11: Network Programming.
We have introduced techniques for protocol-independent and thread-safe
network programming using the modern getaddrinfo
and getnameinfo functions, which replace the obsolete and
non-reentrant gethostbyname and gethostbyaddr
- Chapter 12: Concurrent Programming.:
We have increased our
coverage of using thread-level parallelism to make programs run faster on