IN THE WAKE of the recent Meltdown and Spectre
vulnerabilities, it is worth spending some time looking
at root causes. Both of these vulnerabilities involved
processors speculatively executing instructions past
some kind of access check and allowing the attacker to
observe the results via a side channel. The features that
led to these vulnerabilities, along with several others,
were added to let C programmers continue to believe
they were programming in a low-level language, when
this hasn’t been the case for decades.
Processor vendors are not alone in this. Those of us
working on C/C++ compilers have also participated.
Computer science pioneer Alan Perlis defined low-level languages this way:
“A programming language is low level when its
programs require attention to the irrelevant.” 5
While, yes, this definition applies to C, it does not
capture what people desire in a low-level language.
Various attributes cause people to regard a language as
low level. Think of programming languages as belonging
on a continuum, with assembly at one
end and the interface to the Starship
Enterprise’s computer at the other.
Low-level languages are “close to the
metal,” whereas high-level languages
are closer to how humans think.
For a language to be “close to the
metal,” it must provide an abstract machine that maps easily to the abstractions exposed by the target platform.
It’s easy to argue that C was a low-level
language for the PDP- 11. They both described a model in which programs executed sequentially, in which memory
was a flat space, and even the pre- and
post-increment operators cleanly lined
up with the PDP- 11 addressing modes.
Fast PDP- 11 Emulators
The root cause of the Spectre and Meltdown vulnerabilities was that processor architects were trying to build not
just fast processors, but fast processors
that expose the same abstract machine
as a PDP- 11. This is essential because
it allows C programmers to continue in
the belief that their language is close to
the underlying hardware.
C code provides a mostly serial abstract machine (until C11, an entirely
serial machine if nonstandard vendor
extensions were excluded). Creating
a new thread is a library operation
known to be expensive, so processors wishing to keep their execution
units busy running C code rely on ILP
(instruction-level parallelism). They
inspect adjacent operations and issue
independent ones in parallel. This
adds a significant amount of complexity (and power consumption) to allow
programmers to write mostly sequential code. In contrast, GPUs achieve
very high performance without any of
this logic, at the expense of requiring
explicitly parallel programs.
The quest for high ILP was the direct cause of Spectre and Meltdown. A
modern Intel processor has up to 180
instructions in flight at a time (in stark
contrast to a sequential C abstract
machine, which expects each operation to complete before the next one
begins). A typical heuristic for C code
C Is Not
Article development led by
Your computer is not a fast PDP- 11.
BY DAVID CHISNALL