1

Augury: Using Data Memory-Dependent
Prefetchers to Leak Data at Rest
Jose Rodrigo Sanchez Vicarte1∗ , Michael Flanders1† , Riccardo Paccagnella∗ , Grant Garrett-Grossman∗ ,Adam Morrison‡ , Christopher W. Fletcher∗ , David Kohlbrenner†∗ University of Illinois Urbana-Champaign, ‡ Tel Aviv University, † University of Washington{josers2, rp8, grantlg2, cwfletch}@illinois.edu, mad@cs.tau.ac.il, {mkf727, dkohlbre}@cs.washington.edu

Abstract—Microarchitectural side-channel attacks are enjoying a time of explosive growth, mostly fueled by novel transient
execution vulnerabilities. These attacks are capable of leaking
arbitrary data, as long as it is possible for the adversary to readthat data into the processor core using transient instructions.
In this paper, we present the first microarchitectural attack
that leaks data at rest in the memory system, i.e., never directly
read into the core speculatively or non-speculatively. This technique is enabled by a previously unreported class of prefetcher: adata memory-dependent prefetcher (DMP). These prefetchers aredesigned to allow prefetching of irregular address patterns suchas pointer chases. As such, DMPs examine and use the contentsof memory directly to determine which addresses to prefetch.
Our experiments demonstrate the existence of a pointerchasing DMP on recent Apple processors, including the A14
and M1. We then reverse engineer the details of this DMP
to determine the opportunities for and restrictions it places on
attackers using it. Finally, we demonstrate several basic attack
primitives capable of leaking pointer values using the DMP.

I. I NTRODUCTION
As the demand for performance gains in general purpose
CPUs continues and the gains from Moore’s scaling dwindle, microarchitects have consistently delivered surprising andpowerful optimizations. However, these optimizations comewith drawbacks, notably in how they inadvertently leak information via microarchitectural side channels.
Today’s microarchitectural side channels are only capableof leaking data in use. That is, data is speculatively or nonspeculatively architecturally accessed and then transmitted
through an “unsafe instruction”. For example, data might
be read into an architectural register and then acted on by
an instruction that changes hardware resource usage in an
operand-dependent fashion [29, 30]. This restriction to data
in use limits attacks in situations where victim programs
lack access or transmit gadgets or when the programs are
specifically written to not contain such gadgets as in constanttime programming [13, 14, 16, 19, 49].
Yet, there has recently been speculation that we are standing
on a precipice, about to face an even more insidious threat:
microarchitectural side channels that leak data at rest [44, 45].
These attacks are brought on by exotic microarchitectural optimizations such as silent stores [32], cache compression [37]and data memory-dependent prefetchers [50] all of which canleak data even if it is never brought into the processor core.
Consider for example a processor that implements a data
1 The two first authors contributed equally to the paper.

memory-dependent prefetcher (DMP). Unlike well-known andwidely implemented prefetchers whose behavior is “just” afunction of a program’s address pattern (limiting their leakage
to program address pattern/control flow [17, 20, 42]), DMPs
read and initiate cache fills based on the contents of program
data memory directly.
This immediately puts all of program memory at risk.
For example, Vicarte et al. [45] point out how a specificproposed DMP called the indirect-memory prefetcher [50, 51]
can be coerced into leaking all of program memory, similar toSpectre/Meltdown but without relying on transient instruction
execution. Making matters worse, as the DMP lives in thememory system, it accomplishes this without the secret data
ever being read from the cache into the processor core, rendering current constant-time programming techniques ineffective.
Fortunately for defenders, data-at-rest attacks have been
purely theoretical. While there is a rich literature on DMPs,
there has been no evidence to suggest they have ever been
implemented in commercial processors.
In this paper, we demonstrate for the first time the existence,and resulting security implications, of a DMP in the wild. By
extension, this shows that microarchitecture leaking data at
rest is real. We refer to our techniques as Augury due to theirreliance on interpreting what the prefetcher believes about the
future.
Specifically, we found that the Apple M1, M1 Max, M1
Pro, and A14 processors possess an Array-of-Pointers (AoP)
prefetcher that recognizes streaming and striding reads anddereferences over an array of pointers, and then prefetches
the result of dereferencing future pointers. To see the difference from conventional prefetchers, suppose a program islooping from i=0...N and has allocated an array A whichis indexed by i. A conventional prefetcher would prefetch
an access pattern such as A[i] or A[stride*i]. The
M1’s AoP DMP prefetches access patterns such as *A[i]or *A[stride*i].
As the AoP DMP operates only on a stream of memory
accesses, and does not have any concept of array bounds, thisprefetcher can overshoot the legal set of pointers to accessand attempt a prefetch of unrelated memory addresses up to
its prefetch depth. This act of dereferencing the out-of-bounds
pointer (potentially even if it is not actually a pointer!) createsa memory side channel that an attacker can use to learn
the pointer. In fact, we show that this pattern recognition isrelatively robust, can operate at large strides, and can trigger
even if all memory accesses are speculative and eventually2squashed. Together, these capabilities enable the attacker totarget and leak pointer values across much of memory.
There have been many proposed DMP patterns, and sincenone have previously been found, there is little in the way ofguideposts for understanding DMP behaviors. As there is no
documentation for even the existence of the M1 AoP DMP,
simply finding the activation pattern is a non-trivial matter.1
Even then, knowing that an AoP DMP exists does not clearlylay out a plan for attack primitives or for software mitigations.
To aid in this, we present a detailed analysis of the AoP
DMP behavior and we also provide guidance for the reverse
engineering and security analysis of any DMP system.
For attackers, this prefetcher opens up new, previously unconsidered exploitation scenarios. For defenders, the existenceof this prefetcher, and the attacks it enables, is a call to action
for developing new approaches for programming techniquesthat can protect data not even being operated on.
Contributions. Our major contributions are:
• We analyze the security relevant design factors for DMPs.
• We demonstrate the existence of the first known data-

memory prefetcher in a commercial processor family.
reverse-engineer the activation criteria, depth ofprefetch, and other features of the M1 DMP.
• We demonstrate that this prefetcher can be used to cause
unexpected pointer de-references, putting data at risk.
• We demonstrate the first microarchitectural attacks ondata at rest by using the M1 DMP to construct exploit
primitives that leak pointer values.
• We

Disclosure. We coordinated with Apple on disclosure andmitigation prior to publication.
Release of tools. Following disclosure, we have made ourtools for investigating DMP behavior on ARM and x86 chips,
as well as our proof-of-concept attack primitives available at:https://github.com/FPSG-UIUC/augury.
II. BACKGROUND AND M OTIVATION
A. Classical prefetchers
We now review how hardware prefetchers work, and theirstatus from a security perspective.
Core / Li cacheaddrCore / Li cache

data

addr

1
3

3

PF
addr

2

data
1

DMP
addr

Core / Li+1 cache

2

data

Li+1 cache / DRAM

Fig. 1: A high-level architecture for classical prefetchers/PFs (left) and data
memory-dependent prefetchers/DMPs (right).
1 We thank Anandtech for their analysis of the A14 processor that speculated

a “pointer-chase prefetch mechanism” [22] might exist in that processor.

To start, we review what we call classical prefetchers(prefetchers for short). These are widely deployed in commercial processors. For example, both Intel and AMD reportmultiple distinct prefetchers in their recent processors [2, 4].
Like prefetchers, caches are present in multiple forms
and levels on nearly all modern processors. Generally, eachprocessor core will have at least 1 level of private cache, split
into an instruction and data cache. Below this, there is at least
one level of shared cross-core cache, generally storing bothdata and instructions. By default, caches will exploit temporal
locality to hide the latency of repeated accesses to memory bystoring data recently used by the core.
Prefetchers are next-in-sequence address predictors thatproactively fetch data into the cache to help hide memory
latency. Figure 1 (left) gives a high-level overview. In Step ❶(training), the prefetcher records whether the address sequence
coming from the core matches a specific pattern. In Step ❷(prefetching), if a pattern was recognized with sufficientconfidence, the prefetcher autonomously makes accesses tomemory to fill the cache with cache lines that it thinks will
be requested in the near future. In Step ❸ (validation), theprefetcher checks whether its predictions were correct bychecking the core’s subsequent requests. Note, we separate theabove steps to ease explanation; similar to a branch predictor,
train/prefetch/validate all occur concurrently and continuously.
For example, a typical address pattern that can be captured
by a prefetcher is a stride through an array, e.g.,
int A[M];... // e.g., initialize A
for (i = 0 ... M) A[k*i];for some constant stride k. Upon observing the core request addresses &A[0], &A[k], ..., &A[k*N], the prefetcher
predicts that the core will request &A[k*(N+1)], ...,
&A[k*(N+delta)] in the near future and proactively issues
cache fills for those cache lines. Here, N is the confidence
threshold: how many accesses must be seen before theprefetcher activates. delta is the depth: how far ahead theprefetcher prefetches once it activates. Depth is often directly
correlated to the confidence: As more accesses are made, theprefetcher will fetch proportionally farther ahead.
Importantly, prefetchers live in the memory system and aresoftware transparent. For example, they might live between
the core and level 1 (L1) cache, or between two lowerlevels (L2+) of cache. As such, they are unaware of program
semantics: they only see the program address pattern and try
to predict the next address. In the above code snippet, theprefetcher is unaware of the array A, its base or its bound.
Thus, the prefetcher will prefetch data out of bounds of A, i.e.,
up to address &A[M+k*delta], before it realizes throughsubsequent failed validations that the program doesn’t intend
to access beyond the array bounds. This will have important
security implications later on.
B. Classical prefetcher security implications
Several recent papers have studied prefetchers in a security
context [17, 20, 42]. We also note Gruss et al.’s [25] workon vulnerabilities in software prefetch instructions, which we

3consider out of scope. At a high level, prefetcher attacks
work in a similar fashion to branch predictor- and cachebased attacks [8, 35]. Specifically, when a victim program
unknowingly interacts with a prefetcher, these interactions
create microarchitectural persistent state changes such as in
the cache or the prefetcher’s internal state. An attacker (receiver) can use techniques like cache-based side-channels tomeasure these changes. Interestingly, prior work has shownhow this can increase leakage beyond normal cache attacks.
For example, many cache attacks leak the address pattern ata coarse, e.g., cache line- or page-granularity [35, 47]. The
prefetcher, however, stores address pattern information at afiner, e.g., byte, granularity.
Despite the above, leakage through the prefetcher is limited
to the victim’s address pattern. This means that prefetcher
attacks can be mitigated through constant-time programming
practices that ensure that the memory address pattern iscompletely independent of secret data [13, 14, 16, 19, 49].
C. Data memory-dependent prefetchers (DMPs)
Beyond classical prefetchers, there is significant work in
the computer architecture literature [9, 10, 18, 21, 40, 50] andseveral industry patents [41, 51] on what we refer to as data
memory-dependent prefetchers (DMPs). These are designed toprefetch irregular address patterns such as pointer chases orindirections that cannot be predicted without understanding
dependencies between the address pattern and the contents ofmemory itself [9, 50].
See Figure 1 (right) for an overview. Similar to a classicalprefetcher, a DMP trains ❶, prefetches ❷, and validates its
predictions ❸. During the train phase, the DMP monitors thedata returned to the core as well as subsequent addresses andtries to determine whether the address stream is a specificfunction of the data returned. For example, in a pointer chasedata will be directly used as an address. In the prefetch phase,the prefetcher will initiate reads to memory that follow thepredicted pattern. This, crucially, requires the prefetcher toexamine and act on the contents of data memory directly. Fora pointer chase, the prefetcher will read a cache line that it
believes contains a pointer and then dereference the pointer.
Depending on the address pattern, this can be a complex
multi-interactive procedure. The common proposed patterns
are shown in Figure 2, and discussed in more detail in
Section IV-B. For example, the DMP in [50] patented byIntel [51] is capable of prefetching through address patterns
such as shown in Figure 2d with L = 2. This requires thatthe DMP not only perform multiple levels of indirection
autonomously—each of which may require virtual-to-physicaladdress translations/direct interactions with the TLB—but alsoinfer each array’s base address through relations between dataand subsequent accesses. Recall, the DMP only sees data
returned to the core and subsequent addresses sent by the core.
Specifically, the DMP only sees physical (post-translation)
addresses. In this example, the data returned to the core in
the first stage of the indirection is A[k*i] – an offset into
array B – and the subsequent address sent back to the memory
system is &B[A[k*i]]. Thus, to predict the indirection into

1
2
3
4

arr A;1# Fill A with pointers
2for ( i = 0; i < len(A); i++) 3
4*A[k*i];arr A;# Fill A with pointers
for ( i = 0; i < len(A); i++)*(...) **A[k*i];(a) 1-level pointer-chasing.

(b) L-level pointer-chasing.
1
2

1
2
3
4
5

arr A;
arr B;# Fill A with offsetsfor ( i = 0; i < len(A); i++)B[A[k*i ]];(c) 1-level indirection-based.

3
4
5
6
7

arr A;... # Many such arrays
arr Y;
arr Z;# Fill arr A−Y with offsetsfor ( i = 0; i < len(A); i++)Z[Y [(...) A[k*i ]]];(d) L-level indirection-based.

Fig. 2: Examples of types of DMP expected access patterns. k is the constant
stride. L is the number of pointer dereferences that occur ignoring streamingover A. The left column is the explicit L = 1 case. L is a DMP design decision.
We discovered a 1-Level Pointer Chasing DMP (a) on the Apple M1.

B for future k*(i+delta), the DMP must use the data andaddresses it has seen so far to infer &B[0]. Note, A[k*i] is
an offset into an array in the program’s virtual address space,
whereas &B[A[k*i]] is likely a physical address. So, theDMP must autonomously perform virtual to physical addresstranslations to identify data-address correspondences.
D. DMP security implications
To our knowledge, prior to this paper, there has been no
evidence to suggest that any DMP is implemented in any
commercial processor. Nor (by extension) has there been
analysis of the security implications of DMPs in the wild.
Vicarte et al. [45] did recently perform an analysis of the
security implications of proposed microarchitecture, including DMPs, but these were not known to be implemented.
While their work was theoretical, it points out how DMPs
have potentially disastrous security implications. For example,
consider an indirection-based DMP that prefetches the pattern
C[B[A[k*i]] similar to the one in Figure 2d. Misused, thisDMP can be coerced to leak all of program memory, similar
to Spectre and Meltdown [30, 33]. To see this, suppose thatthe DMP was used in a sandbox setting. In that case, theattacker controls the program and can therefore easily force
the DMP to activate. The attack proceeds as follows. 1) the
attacker specifies a value (call it j) stored off the end of array
A. j will correspond to the address of the value in memory theattacker wants to learn. 2) the DMP erroneously reads j andaccesses memory to read C[B[j]]. Recall from Section II-A,
prefetchers do not know array bounds. Thus, B[j] can referto the data at any memory location. Finally, C[B[j]] serves
as the transmitter in a memory side channel: B[j] is a secretand C[B[j]] turns that secret into an address to memory.
E. Apple Silicon
Modern Macs no longer use Intel processors, but instead use
the new (ARM) M1 line. As the M1 is very similar to previous
Apple processors, vulnerabilities in it may affect millions ofconsumers. We have confirmed that our findings apply to theA14 (iPhone 12) and the new M1 Max at a minimum.

4

The M1 has eight cores: four high-performance Firestorm
and four energy-efficient Icestorm cores [12]. As we find the
DMP to only be present on the Firestorm cores, we focus
on the relevant Firestorm details. Each core has a private L1
cache, and there are two large L2 caches shared between coresof the same type. The four Firestorm cores share a 12 MiB
L2, and the Icestorm cores share 4 MiB. Each Firestorm core
has a private 192 KiB L1 instruction cache and 128 KiB L1
data cache [11]. While there is no official information on theassociativity or cacheline size, we found that L2 lines are 128
bytes, and L1 lines are 64 bytes.
When filling L1d lines,
two adjacent L1d lines are brought in at a time, and bothare independently evictable. We also believe that the L1 is
8-way associative and the L2 is 16-way associative from ourexperience building eviction sets (Section VII-C).
A major complication for reverse engineering is reports that
the M1 DRAM controller performs frequency scaling [34].
This matches our observations that a cache miss to DRAM canreturn in a wide range of times. We find that increasing thepressure on DRAM can reduce the average access time morethan amortizing measurement costs would anticipate. The net
effect is that we observe otherwise inexplicable decreases inmemory access times for longer experiments.
Other relevant aspects of the M1 include that it can havean unusually large number of instructions in flight to exploit
instruction level parallelism [28], and does not support any
form of Simultaneous Multi-Threading (SMT).
III. T HREAT M ODEL AND ATTACKER O BJECTIVES
There are two main threat models we consider for the M1
DMP: adversarial unprivileged (or sandboxed) code, and latent
gadgets in benign code. This is similar to prior microarchitectural vulnerability research that exploits unprivileged attacker
code as well as cases of privileged programs containing
speculative gadgets [30]. The M1 does not support any formof simultaneous multithreading and so it is not considered.
A. Sandboxed Adversarial CodeIn this model, we assume a standard microarchitectural
sandboxed attacker: the adversary is able to run arbitrary sandboxed code on a system that does not trust the sandboxed code.
The adversary is attempting to perform memory reads outside
the sandbox and will leverage microarchitectural details of theprocessor to achieve this. This is a scenario commonly seen
with JavaScript sandboxes in browsers, the kernel sandbox for
eBPF code, NaCl modules, and more.
As we assume the sandbox model, the adversary will control
the training pattern that will eventually activate the DMP.
The training pattern is the series of legal, in-sandbox memory
accesses made by the adversary that will cause the DMP to
activate and fetch data based on the predicted next accesses
after the training pattern. The adversary leverages this behavior
to cause the DMP to read outside of the sandbox, and thenleak that information back to the adversary.
We additionally assume that the adversary can use standard
cache side channels to retrieve information about the cachestate. We demonstrate specifically using Prime+Probe on the

M1 in Section VII-C, but these include Prime+Probe [35, 38],
Flush+Reload [48], and other similar styles of attack. The
attacker will use these techniques to receive the secrets transmitted via cache state by the DMP.
B. Latent DMP Gadgets
Like with other microarchitectural attacks, it may be thecase that a victim program already contains the necessarycode patterns an adversary can use to induce an adversarial
training pattern. This is not unlikely, as during our reverse
engineering we found it easy to unintentionally activate the
DMP by accessing stack variables that are pointers and causing
the DMP to prefetch other pointers on the stack.
In this model, we assume the adversary at most has control
over a set of inputs to the program, and must leverage anexisting set of memory operations. This model can facilitate
an attack, e.g., if the memory operations’ access pattern is afunction of the attacker input. It is also possible for a program
to, without any adversarial interaction, cause a DMP to activateand leak information.
One possible example of the former would be a syscallthat dereferences userspace-defined pointers, such as readv
or writev. In these situations, the adversary may be able
to induce activation of the DMP during kernel execution andcause the DMP to leak data near the kernel buffer containing
data copied from userspace.
For the latter, consider a program that accesses (unconditionally) addresses X, A, B, and C, where X is the address ofan attacker controlled string buffer. If the buffer contains thevalues “A,B,C,Z” then it is possible the DMP will interpret
X as an Array-of-Pointers currently being iterated over anddereferenced, and then (attempt) to prefetch Z.
IV. T HE DANGERS OF DMP S
As part of our study of the DMP present in Apple CPUs,
we first had to consider the possible design dimensions of
a DMP, and the relevant security impact of each. Whileany DMP will have security implications, understanding theimplementation of a specific DMP is necessary for making
definite claims about the vulnerability of real programs and toformulate platform-specific software defenses. For example, a
DMP using a prefetch buffer (see Section IV-D) may not evenprovide an advantage over standard cache side channels!
A DMP performs several important actions during operationthat allow for the use of side channels to determine secrets.
We will use the terminology of access-transmit-receive fordiscussing the leakage of secrets [29]. After activating, any
data read by the DMP to determine addresses for prefetchingis considered accessed. The DMP is then considered to havetransmitted that data when it performs a prefetch to an address
which is a function of the data. Finally, the adversary uses
some side-channel attack (cache occupancy, cache contention,etc.) to receive that data.
Below, we explore the possible design space for a DMP
through a security lens. This analysis is driven by our surveyof existing DMP and prefetcher literature, existing prefetcher
reverse engineering, and questions that arose while working on

5this paper. As real DMPs have not previously been evaluatedfor security impact, this is an unexplored area useful forframing both the M1’s DMP as well as any future DMP
analysis. Relevant axes of interest are:• What are the preconditions for DMP activation?
• What memory is accessed to inform prefetching?
• What function of memory values is transmitted?
• How can the adversary receive the transmitted values?
A. Preconditions for a DMP to activate
Like classical prefetchers, a DMP must track memory
accesses made by programs and decide when to activate. Basedon previous prefetcher designs, we know that this may track
only address suffixes, may organize tracking entries by PID,
may organize memory accesses by the instruction address they
originate from, and may rely on another non-DMP prefetcher
to retrieve data. Each of these possibilities has significant
impact on what an attacker can do with that DMP.
If, like the Intel L1i prefetcher [17], the DMP only tracks
address suffixes, then it is vulnerable to aliasing attacks.
This allows an adversary to train the prefetcher using noncontiguous memory accesses that only appear to be contiguouswhen the upper bits of the address are ignored. For example,
an adversary could train a DMP over a sandboxed memory
region but a safe access outside of the sandbox that aliases tothe same pattern could activate prefetches outside the sandbox.
Instruction-pointer (IP) tagged pattern tracking on the other
hand limits attacker capabilities by restricting the code performing dereferences to loops. Without IP tagging, the memory access pattern can originate from any series of instructions
that perform memory accesses. These instructions may noteven intentionally be referencing related memory, and may
simply appear to the DMP to be a contiguous streaming access.
Like general DMP address tracking, IP tagging may only
track address suffixes [31]. Once again, this will allow anadversary to perform aliasing attacks where two distinct instructions that share an address suffix will be conflated by the
DMP as the same originating address.
Process ID (PID) tagging, like IP tagging, limits the adversary by forcing all accesses and prefetches to occur in thesame process. Without PID tagging an adversary may be able
to train the DMP on one process, and then allow the unrelated
victim accesses to cause DMP prefetches.
Finally, it may be the case that the DMP follows someclassical prefetcher on the system. This would mean that the
DMP’s top-level activation criteria and restrictions are thesame as that classical prefetcher’s.
B. Data access patterns for DMPs
The most important feature to the attacker is which values
the DMP will access to inform prefetching.
The first concern is if the DMP is single or multi-layer (seeFigure 2). A single layer DMP performs only one (effective)
memory dereference per-prefetch. An N-layer DMP will perform N dereferences per-prefetch. As an example, a prefetcherthat simply prefetches the memory backing all pointers in
an array-of-pointers (*arr[n+1]) is a single-layer DMP. A

prefetcher that fetches not only the data backing a pointerin memory, but also interprets that data as a pointer anddereferences again (**arr[n+1]) is a two-layer prefetcher.
Multi-layer DMPs are exceptionally powerful for an attacker
and most other design decisions become irrelevant if the
DMP is multi-layer. The reason is that the attacker can
precondition the first value being accessed (e.g., arr[n+1])
to refer to an arbitrary memory location, meaning the DMP
can subsequently access arbitrary program memory. This iswell demonstrated in Vicarte et al. [45] which shows how
to use the 2-level Indirect Memory Prefetcher (IMP) [50] toconstruct a Universal Read Gadget and transmit the contentsof all of virtual memory. For the rest of this section we assume
a single-layer DMP.
As with classical prefetchers, a DMP is likely capable ofdetecting a stride pattern where the access pattern touches
non-adjacent items in memory. Stride detection will havesome maximum distance within which sequential accesses
are considered part of the pattern. This maximum stride will
determine the maximum distance from the end of the training
pattern that the DMP will prefetch from.
Any prefetcher will also have a maximum number of
elements that it is willing to prefetch, generally increasing withhigher confidence. This is the effective depth of the prefetcher.
Fundamentally, the furthest value that can be targeted by
a DMP is (max stride × depth) + end o f training address.
We will refer to max stride × depth as the maximum prefetch
distance (in bytes).
As we will see with the M1 AoP DMP, there can be otherunusual restrictions on what memory the DMP can access.
These don’t follow any particular set of rules.
C. Function of data transmitted by a DMP
A DMP can be either a pointer-chasing prefetcher or it canbe an indirection based prefetcher (see Figure 2).
A pointer-chasing DMP dereferences pointers in memory
and prefetches the cache lines found there. Thus, an attacker
that controls the train pattern can trick the DMP into dereferencing a secret value as if it were a pointer. These DMPs
allow an adversary in control of the training pattern to cause
a secret memory location to be treated as an address, and toattempt a load of that address. If the secret value is a valid
pointer, this will transmit the pointer value through standard
cache side-channels. If it is not an address, it may still bepossible for the adversary to monitor the (failed) page-walkor use TLB side-channels [23, 43] to learn the upper bits ofthe secret.
Indirection DMPs dynamically determine the base addressof some array(s) and prefetches portions of it based on aseries of index values in memory. These are more powerfultransmitters than pointer-chasing DMPs as they easily transmit
values that are not valid virtual addresses. Specifically, an
attacker that controls the train pattern can trick the DMP into
treating a secret as an offset in a base-plus-offset calculation.
Suppose the attacker additionally controls the base address(which is the case, if the attacker controls the training pattern). Then the indirection-based DMP avoids the previouslydiscussed issue in the pointer-chasing prefetcher: the attacker

6

can arrange for the base-plus-offset to fall within a mapped
memory region that is accessible to the attacker. This allows
both for simpler transmission and straight-forward cacheoccupancy side-channels for reception.
D. Receiving data transmitted by a DMP
Once a DMP has accessed and transmitted a secret, theadversary must now receive that secret. In the simplest caseof an indirection prefetcher this would involve checking theaccess time (cache occupancy status) of every entry in the basearray. For pointer-chasing prefetchers this would mean runninga cache contention side-channel to detect what address wasbrought into the cache.
A DMP may alternatively prefetch to a prefetch buffer
rather than directly to the cache. A prefetch buffer is a small,typically fully associative, cache which only holds prefetched
data. Only prefetched data can induce contention on thisbuffer, making it significantly harder for the adversary toobserve the effect of the prefetch. Then, there must be an
actual access to the address corresponding to the transmitted
value to observe a timing difference or affect cache state.
Since the value being transmitted is the address in question
for single-layer DMPs, it may not be possible for the adversary to directly access this address at all. This would occur
because it is unlikely that a secret address is mapped into theadversary’s virtual address space.

All experiments insert dependencies between operations
such as loads and PRNG calls. This action prevents out-oforder execution from issuing multiple operations simultaneously and makes overall execution time strongly correlated tothe average memory access time.
Finally, the cache is flushed between experiments to remove inter-experiment interference. We discuss this and othermethodological details, e.g., ensuring that both experiments
run the same instruction sequences, in Section V-C.
B. Setting up the sequence of memory accesses
We set up the experiment by allocating two large buffers
as shown in Figure 3. One of the buffers, the data buffer, isfilled with random data, and the other buffer, the AoP, is filledwith unique pointers to disjoint and non-consecutive 128-byte
chunks of the data buffer.
These constraints are not necessary to activate the DMP but
will amplify the signal to noise ratio of DMP-caused speed
ups and minimize any affects from noise or other microarchitectural optimizations. In particular, uniqueness and 128-bytealigned accesses ensure that data backed by pointers is notalready cached from being accessed earlier in the experiment.
Recall from Section II-E, the M1 has 128 byte (L2) cachelines. Using pointers to non-consecutive chunks improves thelikelihood that a classical prefetcher (Section II-A) will not
activate from data buffer accesses.
Prefetchedby DMP

Streamed over in Main Access Loop

V. E XISTENCE OF THE M1 DMP
In this section, we provide a detailed walkthrough of ourinitial experiments confirming the existence of a specific DMP
while ruling out the existence of several other DMPs. We also
describe the steps we took to determine that the root causeof our observations was, in fact, a DMP as opposed to othermicroarchitectural features (like speculative execution).
We tested for the existence of four DMPs: both single- andtwo-level versions of pointer-chasing and indirection-based
DMPs (Section IV). Our findings show the existence of asingle-level pointer-chasing DMP, so our focus below is on
how we setup the experiment for that variant. We discuss othervariants (negative results) at the end of the section (V-F).

aop
Pointer
Dereferences*aop[0] *aop[1] *aop[2][data_buf
Sparse31128-Byte
ChunksM*aop[N] *aop[M]N

Hits in cache
if prefetched

2]

Fig. 3: Memory layout of the DMP AoP and data buffer. Black arrows
illustrate memory accesses due to aop dereferences (Line 17) in Algorithm 1.
Baseline accesses (Line 16) directly load the same entries in the data bu f
without dereferencing from the aop. The AoP shown contains pointers which
are consecutive in memory (unit stride). Each pointer points to disjoint andnon-consecutive 128-byte chunks of the data buffer. If we access the AoP fromindex 1 through N and the DMP activates, the contents of the data buffer at
aop[M] for M > N may be brought into the cache.

C. Access patterns and other considerations
A. Experiment overview
To confirm the existence of the single-level pointer-chasing
DMP (referred to as the DMP for short), we compare theexecution time of two different methods for accessing the samerandomly generated sparse series of memory addresses. The
first method–the AoP DMP pattern–pre-computes all memory
addresses and stores them sequentially in an array-of-pointers(AoP). The addresses are then accessed by streaming over the
AoP and dereferencing each pointer. The second method–thebaseline–accesses the same series of addresses by computing
them on the fly. Computing the addresses ensures they cannot
be prefetched by either a DMP or a classical prefetcher. Bothexperiments generate addresses using the same PRNG seed.

After setting up the data buffer and the AoP, there arestill some precautions that must be taken when accessing thepointers to ensure a speedup can only be caused by a DMP.
If we were to just measure the execution time of two different loops–one baseline access pattern loop and one AoP accesspattern loop– then we would be comparing the execution timeof two different instruction sequences. The AoP access pattern
has an extra memory access per loop iteration since it must:
1) indirect by some offset into the AoP and 2) dereference
the pointer stored in the AoP. Whereas the baseline must 1)
make a single memory access and 2) use a PRNG to computethe next data buffer address on each iteration. Thus, seeing
different runtimes for the two loops would not be surprising,and not necessarily be due to the presence of a DMP.

7

1
2

data bu f = . . . /* some large buffer */aop = . . . /* some large buffer */aop mode = IS AOP RUN /* 0 - baseline, 1 - AoP */aop idx = 0
5 rand idx = PRNG(RAND SEED)
3

4/* Fill the AoP */for i in 0...NUM PTRS do
7∗aop[i] = data bu f + (rand idx ∗ aop mode ∗ CL SIZE)
8rand idx = PRNG(rand idx)
9 end
6

10

FLUSH CACHEMEM BARRIER
12 dep val = 0
13 start time = READ TIMER(dep val)
14 dep val = MSB(start time)11/* Training loop */for in 0...NUM PTRS do/* Baseline Access */16
dep val = MSB(data bu f [rand idx ∗ (1 − aop mode) ∗CL SIZE | dep val])/* AoP Access */17
dep val = MSB(∗aop[aop idx | dep val])15

aop idx = aop idx + aop mode
rand idx = PRNG(rand idx)

18
19
20

end

21

MEM BARRIER
stop time = READ TIMER(dep val)

22

Algorithm 1: Pseudocode for the baseline experiment (which computes
pointers on the fly) and the experiment testing for the presence of asingle-level pointer-chasing DMP and baseline. READ TIMER calls
mach absolute time which returns time in ticks. CL SIZE stands forthe (128 byte) cache line size. Dependencies are guaranteed to resolve
to zero by using only their Most Significant Bit; denoted by MSB.
MEM BARRIER is an instruction/data serialization instruction. PRNG
is a C macro that expands into a Lehmer random number generator, i.e.,
is not implemented as a syscall. The code is compiled with compiler
optimizations turned off, and the assembly code was manually inspected
to ensure intended behavior.

To address these discrepancies, we ensure that both the baseline and AoP experiments execute the same instructions, while
taking care to ensure that the baseline does not activate a DMP.
The code used for both experiments is shown in Algorithm 1.
For the baseline, we add an access and dereference the pointerat index 0 of the AoP during each iteration (Line 16). For the
AoP case, we compute the address on the fly as in the baseline(Line 19) but use the pointer read from the AoP to lookup thedata buffer (Line 17). With both experiments executing thesame instructions, we expect the baseline to run slightly fasterthan the AoP pattern due to occasional cache misses from AoP
traversal.
It is also necessary during baseline runs to set all pointersin the AoP to point to the first element in the data buffer:otherwise the DMP activates during the baseline run due tothe single AoP access combined with the computed pattern
being similar to the AoP case pattern. This is an instance ofthe pattern described in III-B where a single read of a cacheline
containing pointers is misinterpreted as the source of multiple
pointer dereferences.
Finally, we add dependencies between operations to ensure that speedups are not due to out-of-order execution.
Specifically, dep val in Algorithm 1 ensures that all loads

are executed serially and between the timer start and stop
operations. Note that the first load in each iteration, whichlooks up data bu f , depends on both the previous load into
the AoP and the PRNG computation—regardless of whether
the baseline or AoP-based experiment is being run. This,
coupled with the fact that both the AoP lookup and PRNG
operation are expected to be relatively fast, implies that the
loop’s performance will be strongly correlated to the data bu f
access latency.
D. Other Notes on Methodology
We find the DMP to be present solely on Firestorm cores. To
improve consistency, we core pin our experiments by setting
the thread quality of service, as described in [1]. We do not
perform any kind of frequency pinning (for the Firestorm coresor for DRAM) throughout our experiments.
Our experiments make use of two different timers: theM1’s performance monitoring counter (PMC) [27] and themach_absolute_time macOS syscall [3]. The PMC canmeasure time at cycle-granularity with Apple reporting a maximum clock speed of 3.2 GHz for the Firestorm cores whereas
mach_absolute_time can measure time at a granularityof (on average) 42 ns per ‘tick’. Despite the coarser-grainmeasurement, we use the mach_absolute_time timer
in many situations since we found it easier to work with(e.g., accessible from userspace, accessible across cores) andsufficient to distinguish between cache hit vs. DRAM access
events. We use the PMC in select experiments to distinguishbetween finer-grain events (e.g., an L1 cache vs. L2 cache hit).
For all experiments with either timer, we first measure
the timer’s overhead by running a start timer-stop timer
pair back to back in an empty loop. This overhead is subtracted from all points on graphs that use that timer. For
mach_absolute_time, we found the overhead to be ∼42 ns and convert measurements using that timer to ns usingthat conversion rate.
E. Results
Figure 4 reports the time elapsed (stop time - start time)
for the baseline and DMP variants tested in Algorithm 1,
for different length sequences of pointers (AoPs). The maintakeaway is that the “Array of Pointers” variant (testing thepresence of a single-level pointer-chasing DMP) sees significant speedup (3 − 8X) on medium to large AoPs compared tothe baseline (“Computed”) access times.
We note that, while the AoP variant always sees speedup
relative to the baseline, the speedup varies as a functionof NUM PTRS. To break this down, we divide Figure 4
into three regimes (1), (2) and (3) demarcated with verticaldashed lines. In regime (1)–small NUM PTRS–the speedup
is initially zero and increases quickly with NUM PTRS. Thisis due to timer granularity: for small NUM PTRS, timer
overhead dominates. In regime (2)–medium NUM PTRS–the
speedup converges given sufficiently large NUM PTRS. We
attribute this to the DMP improving the average memory access time in the AoP-based experiment. Finally, in regime (3)–large NUM PTRS–the speedup decreases with NUM PTRS.

8Mean Access Time (NS)1000

Memory Access Pattern(1) (2)ComputedIndirections
Array of Pointers

800
600

(3)

400
200
0

1

2

4

8

16

32

64

Figure 5 shows the time to perform one of these test accesses for N = 256 pointers and M = 259 as well as measured
access latencies to various memory levels (L1, L2, DRAM).
Lower latency test accesses indicate the DMP prefetched anddereferenced data. The figure shows that test accesses for the
DMP configuration track closely with the L2 cache hit latency.
From this, we conclude that the DMP prefetches into the L2
cache and is likely built alongside the L2.

128 256 512 1024 2048 4096 8192

Fig. 4: Execution times for the single-level pointer-chasing DMP (“Arrayof Pointers”), single-level indirection-based DMP (“Indirections”; c.f. Section V-F3), and Baseline/pointers computed on the fly (“Computed”) patterns,
using the setup in Algorithm 1. We measure access time using on-chip timers
according to Algorithm 1 (stop time - start time). Times are obtainedusing mach_absolute_time and converted to nanoseconds as described in
Section V-D. For the indirection-based access pattern, the AoP dereference isreplaced with an indirection. Each point represents average pointer dereferencetime (averaged across 2560 runs and the number of accesses in the train loop)with error bars representing standard deviation.

We attribute this to the DRAM frequency scaling discussed
in Section II-E. From the core’s perspective, an increase in
DRAM frequency will appear as a decrease in access times.
These results provide evidence that the speedups are not theresult of speculative execution. First, speculation would notcause such a large and consistent speedup for the AoP whileleaving the baseline–which executes the same (serialized)
instruction sequence in the same loop–unaffected.2 Second,
these speedups vanish when we run the same experimenton the M1’s Icestorm cores, which still feature speculative
execution but (presumably) lack other high-performance microarchitectural features such as the DMP.
The results are consistent with the behavior of a DMP(Section II-A). When iterating through smaller AoPs (regimes(1) and (2) in Figure 4), the DMP is less confident anddereferences fewer pointers. When iterating through larger
AoPs (regime (2)), the DMP is more confident and aggressively dereferences more pointers resulting in larger speed
ups [17, 50].
1) Testing for prefetches+dereferences of unaccessed
AoP entries: We also tested the existence of the DMP with asecond methodology. Shown in Figure 3, the idea is to have thetest program stop iterating through the AoP without accessing
all of the pointers and to then test whether the next unaccessed
AoP entries have been prefetched and dereferenced. If the AoP
stores M pointers, we have the test program access N pointers
for N < M. We then perform what we call a test access, andmeasure the time to load the cache line at the address given
by aop[M].3 Critically, we avoid interaction with the DMP
by not accessing the aop during the test access. That is, bycomputing and accessing the address pointed to by aop[M] inthe same manner as in the baseline case.
2 Subsequent results in Section VI are also inconsistent with speculative
execution but consistent with prefetchers.
3 This assumes M ≤ N + △ where △ is the prefetcher depth (Section II-A).
In this experiment, we assume that this holds and that △ is known. Analyzing
what is the depth △ in different situations is a subject in Section II-A.

Access time (PMC cycles)

Number of Accesses in Train Loop (NUM_PTRS)

103

L1 access timeL2 access time
Fastest main memory times
DMP prefetched ptr access time
Baseline pattern ptr access time

102

101

0

25

50

75

100

Trial number

125

150

175

Fig. 5: Test access latency, relative to the baseline (computing pointerson the fly) and measured access latencies to different level memories.
Time is measured using the fine-grain performance monitoring counter from
Section V-D. The label ‘Fastest main memory times’ refers to the fastest main
memory time we observed with DRAM frequency scaling (Section II-E).

F. Testing for the existence of other prefetchers
So far we have only discussed the existence of a singlelevel, pointer-chasing DMP. We also tested whether the M1
contained other classical prefetchers and other data memorydependent prefetchers. We found the M1 does feature at least
one other classical prefetcher but does not contain the otherdata memory-dependent prefetchers described in Section IV.
1) Testing for classical (stride) prefetchers: We confirmed through a separate analysis that the M1 contains aseparate classical (stride) prefetcher that prefetches data into
the L1 cache. Based on our analysis, this prefetcher seems
to be completely separate from the DMP—i.e., has different
depth, confidence, etc., parameters—and thus does not impact
what data the DMP can access (Section IV-B). Thus, we donot study it further in this paper.
2) Testing for multi-level pointer-chasing DMPs: Next,
we tested whether the pointer-chasing DMP we had been
focusing on was multi-level. Confirming whether such aprefetcher is present is very important since having more than
one level dramatically increases the scope of data that the
DMP can access (Section IV-B).
For this experiment, we added another level to the AoP
and reran the previous experiments. Specifically, we allocate
an additional array which holds pointers to random 128-byte
chunks of the original AoP. We call this additional array theouter AoP and the original AoP the inner AoP. The pointersin the outer AoP are again spaced out so that there is only one
pointer at the start of every 128-byte chunk with the rest of
the chunk zero-padded. We ensured that the pointers chosen

9for the outer AoP would not cause the DMP to activate for the
inner AoP and data buffer, which would create false positives.
The access pattern and training loop is then the same as the
AoP DMP (Algorithm 1), but this time we double dereference
the pointer at the current index of the AoP.
3) Testing for single-level indirection-based DMPs:
Next, we tested for the existence of a single-level indirectionbased prefetcher such as the indirect memory prefetcher (i.e.,
B[A[i]] [50]). Such prefetchers also have interesting (and different) security implications due to their ease of leaking nonpointer data (Section IV-C). For this experiment, we changed
the single-level AoP-style code in Algorithm 1 so that the AoP
would store offsets into a second array, as opposed to direct
pointers into memory.
4) Results: Both of the above experiments did not indicate
the presence of other styles of DMP. Figure 4 “Indirections”
shows the performance of the indirection-based experiment
relative to the pointer-chasing variants. We did not try toequalize the instruction sequences between this variant and thepointer-chasing variants. Yet, the Indirections variant results inperformance that is very similar to the pointer-chasing variant.
This is expected assuming no such indirection-based DMP
exists: both codes are memory bound (hence, performance islargely a function of the average memory access time) andexhibit the same memory system performance.
Since the single-level indirection-based prefetcher experiment returned a negative result, we did not directly test theexistence of a multi-level indirection-based prefetcher.
5) Other microarchitectures: We also ran existence tests
for indirection-based DMPs (Section V-F3) and the singlelevel, pointer-chasing DMP (Algorithm 1) on more than 5 Inteland 3 AMD processor families, more than 50 machines intotal. In none of these systems did we observe test pointers
being prefetched.
VI. R EVERSE E NGINEERING THE M1 DMP
After confirming that there is a DMP on the M1, we now
turn to reverse engineering the parameters of the M1 DMP sothat we can exploit it. Recall from Section IV that we need toanswer the following questions to understand how to exploit
or mitigate a DMP:
• What are the preconditions for DMP activation?
• What memory regions can a DMP access?
• What function of memory values is transmitted?
• How can the adversary receive the transmitted values?
These questions are discussed below and summarized inTable II.
A. What are the preconditions for activating the M1 DMP?
We identified four conditions necessary to activate the M1’s
DMP.
1) Fire vs. Icestorm cores: Any thread interacting with
the DMP must be running on a Firestorm core (Section II-E).
Developers and MacOS users can specify whether a program
should run on an Icestorm or Firestorm core by modifying aprocess’s quality of service (QoS) bits. For example, setting aprocess’s QoS to ‘user interactive’ will cause the process tobe scheduled only on Firestorm cores [12, 26].

2) DMP “noise” tolerance: There are restrictions on operations between sequential accesses of the AoP. We examined
four types of noise: serialization, system calls, other spurious
operations, and time. We found that system calls and serialization such as instruction and data synchronization barriers4
placed between accesses to pointers in the AoP prevents the
DMP from activating. On the other hand, we found thatthe DMP is generally tolerant of time-based delays between
memory accesses and the insertion of unrelated arithmetic(e.g., incrementing a counter variable from 1 to 1000) or
memory operations between accesses.
3) DMP minimum confidence threshold: For the DMP to
activate, the program needs to dereference at least 3 pointersin the AoP. That is, the DMP has a minimum confidence
threshold of 3 accesses to activate at all (Section II-A).
We determined this threshold by running the Section V-E1
experiment with various lengths of training loop (N). We
then find the smallest N at which we observe cache hits on
dereferencing the (un-touched) test pointers. On the M1, thisoccurs after 3 AoP pattern accesses. This is consistent with
Figure 4, which shows the AoP and baseline patterns diverging
for train lengths between 2 and 4.
4) AoP alignment requirements: The M1 DMP will notbuild confidence if the addresses of the pointers in the AoP are
not aligned to eight-byte boundaries. This is easily observedby offsetting the start of the AoP by any amount that is nota multiple of 8, and running any of the previous experiments.
This is slightly disappointing for attackers, as it precludes asliding-window style attack where the attacker learns a secretbyte-by-byte through repeated experiments with differentlyaligned AoPs.5
We also make several observations that weaken assumptions
needed to activate the DMP.
5) The DMP is not IP indexed: We observed that the M1
DMP is not IP indexed. That is, the instructions that cause
the memory accesses matching the AoP pattern need not be
related in any way. We tested this by unrolling the training
loop from Algorithm 1 into straight-line memory accesses
without branches and observing that both of the experimentsfrom Section V still show the DMP activating.
6) The DMP can be activated using only speculative
accesses: We found that the DMP can be activated using only
speculative memory accesses that are eventually squashed. We
demonstrate this by adapting a Spectre attack example [5] to
run on the M1, and using it to activate the DMP on branchmispredictions (Algorithm 6). Instead of tricking the branchpredictor into reading out of bounds, the experiment will readthe first three elements in the DMP AoP pattern when it
mispredicts and speculatively executes. Since DMP activationis slightly noisy for an AoP with 3 pointers (Figure 2),
the experiment performs this branch-predictor training andmisprediction loop many times (lines 7-16) to raise confidence
in whether target ptr was dereferenced or not. If the DMP
4 https://developer.arm.com/documentation/100941/0100/Barriers.
5 Recall from Section IV-C, the attacker may be able to learn high-order bitsof a secret (even if it is not a virtual address) by monitoring TLB and related
MMU state. A sliding-window attack can amplify this leakage by tricking the
DMP into interpreting different secret bytes as high-order address bits.

10

can be triggered via speculation only, then the target pointershould be dereferenced and it will be a cache hit which istested for on line 17.
aop[0 ∗ 128] = p1
aop[1 ∗ 128] = p2
3 aop[2 ∗ 128] = p3
4 aop[3 ∗ 128] = target ptr
5 aop[4 ∗ 128] = target ptr

1

2

6

FLUSH CACHE

for train iter in 1...30 do
idx1 = 0/* Branchless if-then-elses */9idx2 = if (train iter%6) then 0 else 1
10idx3 = if (train iter%6) then 0 else 2
11
if idx3 == access evicted memory containing(0) then12
∗aop[idx1 ∗ 128]13
∗aop[idx2 ∗ 128]14∗aop[idx3 ∗ 128]
15end
16 end17 result = was l2 timing(target ptr)
78Algorithm 2: Pseudocode of experiment for determining whether
the DMP will activate when all memory accesses are speculative andeventually squashed. This code will also be used in our ASLR break(Section VII-D). p1, p2, p3 are unique random pointers to a data buffer.
The cache line storing the value 0 used in the conditional check is evicted
on each iteration.

speculated_aop_patternbaseline

Cycle counts using PMC

800
600
400
200
0

0

200

400

600

800

1000

Trial number

1200

1400

1600

Fig. 6: Speculative accesses in an AoP pattern causes the DMP to activate.
Figure 6 shows the dereference times of the target ptr(line 17) across 1530 experiment runs. The baseline showsdereference times for the target pointer without the three
speculative accesses on each 6th train loop iteration–i.e., itnever mispredicts.
B. What memory regions can the M1 DMP access?
There are two main considerations for whether or not the
M1 DMP can leak a secret at a given address: 1) how far thesecret is located from an adversary-interactable AoP and 2)
whether the DMP is willing to prefetch memory located at
any reachable address.
Recall from Section IV-B that the location of the furthest pointer past the end of an AoP that a singlelevel DMP can dereference is (max stride × depth) +end o f training address where the maximum prefetch distance is max stride × depth in bytes. In the case of the M1,
we found that the DMP will also activate when traversing an
AoP backwards.
1) Determining maximum prefetch distance (as a function of confidence, stride and depth): We found there to be a
non-trivial relationship between DMP confidence (the numberof training accesses touching the AoP) and stride (distance
between pointers) in determining the M1 DMP’s maximum
prefetch depth. This is shown in Figure 7 and Table I. The
high-order bit is that a stride of 64 cache lines (8 KiB) enables
the DMP to reach (access and dereference) a pointer 64 KiB(i.e., 8 pointers deep) away from either end of the AoP.
To start, Figure 7 shows that the number of entries the
DMP is willing to prefetch and dereference (depth) is clearly
proportional to the number of accesses the program makesthat match the DMP’s target pattern (confidence). This isconsistent with expected DMP behavior (Section V-E). Note,consistent with Section VI-A3, the AoP DMP plot only shows
low latency test accesses for train sizes 4 and larger. We
note two other features in the data. First, when more than
2048 accesses are performed, either the first eight or sixteen
accesses are not prefetched. This behavior is caused by a 16
KiB page boundary, and is further studied in Section VI-B2.
Second, for both the AoP and baseline patterns, as the numberof accesses increases, the access time for misses decreases. We
propose an explanation for this in Section V-E.
Table I reports the maximum distance in bytes we canprefetch/dereference a pointer. We run this experiment witha training loop that is large enough to maximize confidence(and therefore depth, see previous paragraph). Our experiments
show that the maximum distance is not monotonically increasing with stride, but larger strides do tend to enable larger
maximum prefetch distances, as expected. To summarize, up
to a stride of 8 KiB, the maximum distance increases (up toa maximum distance of 64 KiB). We did not see the DMP
activate for strides larger than 8 KiB (1024 pointers).
Finally, we observed that the DMP does not activate when
the stride, at cache line granularity, is not a power of two.
This is shown in Figure 8. We confirmed that low measurements on the y-axis (faster times) occur iff test accesses are
dereferenced, i.e., indicate that the DMP activated.
Stride (B)
8
16
32
64
128
256

Maximum Distancefrom AoP (B)
384
384
256
1536
1024
2048

Stride (B)
512
1024
2048
4096
8192

Maximum Distancefrom AoP (B)
4096
8192
16384
32768
65536

TABLE I: The maximum distance ahead in memory prefetched is a functionof stride. All experiments are performed using 4144 training accesses. This
number of accesses achieves the maximum prefetch depth (Figure 7) while
avoiding the page boundary interaction described in Section VI-B. All memoryin the AoP in between touched pointers (for a given stride) is zeroed.

2) Unprefetchable virtual address regions: Unexpectedly, we found that the M1 DMP behavior is affected by thevirtual address of the AoP itself and the virtual addressesof pointers contained in the AoP. We found that the M1

11

AoP Access Pattern

80

Computed Access Pattern

72
64

Access Time (NS)Distance from Train

56
500

48

400

40

300

32

200

24

100

16

0

8
1
2
4
8
16
32
64
128
256
512
1024
2048
4096
8192

1
2
4
8
16
32
64
128
256
512
1024
2048
4096
8192

1

Number of Accesses in Train Loop Number of Accesses in Train Loop

Fig. 7: DMP prefetch depth is a function of train loop size (NUM PTRS
in Algorithm 1). The left/right graphs show results for the single-level
AoP/baseline experiments in Algorithm 1. Each column (along the x-axis)
represents a single training loop size. Each row in a given column (along
the y-axis) corresponds to a test access latency into data bu f (Section V-E1)
that far away from the last pointer touched in the training loop. Times aremeasured using mach_absolute_time and converted to nanoseconds as
described in Section V-D.

Mean Access Time (NS)

400

300

200

100

0

1

2

3

4

6

8

12

16

24

32

48

Training Stride (128B)

64

128

256

512

Fig. 8: DMP training loop performance as a function of stride. All
experiments use a large training loop size, similar to Table I. All memoryin the AoP in between touched pointers (for a given stride) is zeroed. Times
are measured using mach_absolute_time and converted to nanoseconds
as described in Section V-D.

4192
4184
4176
4168
4160
4152
4144
4136
4128
4120
4112
4104
4096
4088
4080
4072

Access Time (NS)

400
300
200
100

4072
4074
4076
4078
4080
4082
4084
4086
4088
4090
4092
4094
4096
4098
4100
4102
4104
4106
4108
4110
4112
4114
4116
4118

AoP Index (N + M)

DMP does not dereference pointers located in the cacheline
immediately after 16 KiB or 2 MiB virtual address boundariesof the AoP and has additional odd behavior depending on
which boundary (16 KiB or 2 MiB) we try to get it to cross.

Last Array of Pointers Index Accessed in Training (N)Fig. 9: For different training AoP lengths N (x-axis), what is the accesslatency for values in data bu f corresponding to pointers in the AoP at
offsets N + M (y-axis). The dashed lines indicate cacheline boundaries in
the AoP. A 16 KiB Boundary occurs at aop[4096]. Times are measured using
mach_absolute_time and converted to nanoseconds (Section V-D.)

We illustrate this behavior with a dense AoP in Figure 9.
We see that the DMP does not dereference pointers locatedin the 128 bytes immediately after the 16 KiB page boundary(y-axis value 4096), but it does dereference the pointers before
and after this ‘dead zone’. However, if the last training accessof the AoP occurs after the 16 KiB page boundary (x-axis
values 4096-4103, then the DMP only refuses to dereference
the pointers in the second 64 byte chunk after the 16 KiB
boundary until train accesses touch this 64 byte chunk (xaxis value 4104). Notably, this behavior is independent of
AoP sparsity. Though a sparse AoP will naturally have fewer
pointers within these 128 byte regions.
We observed a more aggressive behavior at 2 MiB address
boundaries of the AoP. This behavior is, once again, independent of AoP sparsity. The DMP will not dereference any
pointers past a 2 MiB boundary of the AoP. When a training
loop crosses this boundary, the DMP’s confidence resets andmust retrain based on pointers accessed after the boundary.
These interactions are difficult to explain because: 1) the L1
stride prefetcher (Section V-F1) prefetches AoP lines acrossthe 16 KiB boundary, and 2) the DMP induces page walks that
populate the TLB entries for both the AoP and the pointers in
the AoP (Section VI-C). We observed similar results running
this experiment on Asahi Linux.This means that the reluctanceof the DMP to cross these boundaries is not due to any
safeguards against address translation.
We additionally observed that on MacOS, the DMP will notdereference pointers contained in the AoP which have a virtual
address between 0x280000000 and 0x7fe840004000–theend of mappable user-space addresses. On Asahi Linux, whichallows us to map virtual addresses above 0x7fe840004000,
we found the DMP to activate and dereference pointers above
0xffff3f2b0000, but then addresses below 0x280000000
are not dereferenceable. At this time, we do not have an explanation for why there are restrictions on the virtual addresses
the M1 DMP will dereference.
C. What function of memory values is transmitted?
The M1 AoP DMP makes prefetches based on memory content as if it were pointer values. This, naively, places a major
restriction on the function of values transmitted. Only the top
57 bits of the address/value (i.e., L2 cacheline granularity) istransmitted, and only if they are a valid virtual address. As
pointers must be placed at 8-byte alignments (Section VI-A),
we cannot read partial values. (Section VI-A4).
We did, however, find that the M1 DMP fills entries in the
TLB for the pointers in the AoP. To test this we set up an
AoP in the usual way but made each ‘test pointer’ after theend of the AoP a pointer to a unique page. We can then use themprotect system call to change the protection bits of pages
associated with the test pointers to invalidate their TLB entries.
We now set up two experiments: 1) where we mprotect thetest pointers before streaming through the AoP and 2) where
we mprotect the test pointers after streaming through the
AoP.6 If the DMP fills TLB entries, then the test pointer access
6 We also pad the mprotect syscalls with 10,000 cycle delays on bothsides of the call and again add data dependencies.

12

DMP Activation Requirements

The DMP can

Access at least 3 pointers

Activate solely throughspeculative aop accesses

Retrain at each aop 2 MiB page
boundary

Recognize an unrolled aop (it is
not IP-indexed)

aop must be pointer aligned

Recognize strides through the
aop in powers of two

Run on firestorm

Prefetch in either direction
Leakage Target Must

Be a pointerBe within current prefetch distanceNot be 0x280000000-0xffff3f2b0000
Not be in first 128 bytes of any aop 16 KiB page boundary

TABLE II: Summary of the M1 DMP
times for experiment 1 should be faster than experiment 2, andif it does not fill TLB entries, then the access times shouldbe the same. Across 250 runs of each experiment, we foundthat the average test pointer access time and standard deviationfor experiment 1 was 27.95 cycles and 2.8 cycles respectively(using the PMC), and the times for experiment 2 were 110.83
cycles and 49.87 cycles respectively. From this, we conclude
that the DMP does fill TLB entries which transmits the page
bits of the value through another channel.
D. How can an adversary receive the transmitted values?
We found three attacker visible ways that the M1 DMP
affects microarchitectural state: it prefetches to the L2 cache,
it fills TLB entries, and it has internal state (e.g., confidence).
To receive changes to L2 cache state, the adversary may
use directly timed accesses to the cache, use a cache sidechannel like Prime+Probe [35, 38], or alternatively use aninterconnect side channel [36]. The TLB entries may also be
attacked directly using a TLB side channel [23, 43].
So far, the retrieval methods have had secrets or pointersof interest after the end of the AoP, but attackers can also
learn about pointers contained in the AoP by using the DMP’s
confidence metrics as an indicator. We showed earlier inFigure 7 that higher confidences result in deeper prefetching,
and frome Section VI-A3 that the DMP needs 3 AoP patterned
accesses to then prefetch the “4th” (next) pointer. We can use
these effects to determine the validity of pointers under theright circumstances. We later show in Section VII-D how one
can use the DMP’s confidence to break ASLR.
VII. E XAMPLES OF AUGURY T ECHNIQUESIn this section, we cover four scenarios where the M1
DMP can be used in attacks: performing out-of-bounds reads,
beating speculative load hardening, retrieving leaked addresses
via Prime+Probe, and breaking ASLR.
A. Out-of-Bounds Reads
Algorithm 3 shows a proof-of-concept (PoC) which uses the
DMP to read past the end of a buffer. We start by picking threerandom pointers (test p 1, test p 2, and test p 3) that point
to different cachelines of memory. Although in this example

these pointers are accessible to the attacker, we know thatthe DMP alters the L2 cache and TLB, so an attacker could
instead conduct an attack like Prime+Probe if they did nothave access to these pointers [35, 38]. The user then picks
one of the pointers on line 2, and we will use the DMP to
determine which pointer the user picked without reading it.
/* Stick the user chosen pointer after the filled AoP */aop[0 : AOP SIZE − 1] = ... /* Random, unique ptrs */2 test p = user choice(test p 1,test p 2,test p 3)
3 thrash cache()/* Evict test pointers */1/* Train the DMP by streaming through the AoP */∗aop[0]5 ...
6 ∗aop[AOP SIZE − 1]4/* Find the fastest test pointer access time */time(∗test p 1)
8 time(∗test p 2)
9 time(∗test p 3)
7

Algorithm 3: PoC using straight-line memory accesses to activate the
DMP and distinguish between three pointers.

To activate the DMP, we first create an AoP filled with
AOP SIZE random pointers to disjoint 128-byte chunks ofmemory. This AoP is placed immediately before the memory
location containing the user-chosen pointer. AOP SIZE mustbe at least 3 to activate the DMP, with larger sizes increasing
the DMP’s confidence and the clarity of the signal. Next,
we flush the entire cache state by reading in several MB of
unrelated data on line 3. We do this to ensure that the only
test pointer that has a cache hit will be the pointer off the endof the AoP, assuming it is prefetched. We now stream throughthe AoP, accessing and dereferencing each pointer in it, andnot the test pointer outside the AoP (see lines 4-6.) We haveunrolled the loop for two reasons: it makes it clear that thisis not a speculative execution effect, and it also demonstrates
that attackers only need to induce an access pattern that looks
like the cache misses caused by streaming through an AoP.
After training the DMP, we measure the access time to eachof the 3 test pointers. Since only the the user selected pointershould be prefetched into L2, it will be the fastest to access
We ran this PoC 500 times using an AoP of size 64, selecting a different test pointer number each time, and measuring its
accuracy in distinguishing pointers. For the first 250 runs, weused the M1’s PMC (see Section V-D) which can very accurately distinguish between L2 and main memory access times.
For the latter 250 runs, we used mach_absolute_time
which is noisier than the PMC. The with the PMC the PoC
had a 92.0% average accuracy–i.e., number of times the PoC
correctly picked the pointer. With mach_absolute_time,
the PoC had a 70.2% average accuracy.
B. Beating Speculative Load Hardening
Speculative load hardening (SLH) is a defense against
conditional branch-based speculative execution attacks, known
by the name of Spectre Variant #1 [15, 30]. Some pseudocode
with and without SLH applied is shown in Algorithm 4.
SLH prevents Spectre Variant #1 by adding a branchlessrecheck of each branch condition within each conditional’s

13

1
2

N = NUM TRAIN PTRS
stride = LINE SIZE/* AoP train loop without SLH */for i in 0...N do
4∗aop[i ∗ stride]
5 end
3/* AoP train loop with SLH */mask = 0
7 for i in 0...N do/* branchless set */8mask = (i >= N) ? 0 : ALL ONES BITMASK
9∗aop[(i & mask) ∗ stride]
10 end6

Algorithm 4: Example of gcc and clang’s SLH hardened AoP iteration loop [6, 7, 15]. We apply SLH by providing clang with the-mspeculative-load-hardening flag [6, 7]. This option for
AArch64 masks only the loaded value, and this is the only SLH option
for AArch64 when using LLVM 14 (the current latest version). Note that
there are additional speculative-execution-specific instructions inserted in
the final compiler output.

We set up this experiment identically to the basic out-ofbounds read in Section VII-A. However, we use only two test
pointers (test p 0 and test p 1) and build eviction sets of size
24 for each (ev0 and ev1 ) using the baseline algorithm from
Vila et al [46]. Each run of the experiment randomly chooses
either test p 0 or test p 1 as the test pointer.
After the training accesses are complete, we time an accessto each eviction set (ev0 and ev1 ) independently. The eviction
set with a longer access time corresponds to the pointer weguess as the test pointer. In general this manifested as one
eviction set taking around 100 PMC cycles longer to accessthan the other. Across 4300 runs, this resulted in a correct
guess in 60.0% of runs. However, if we remove runs where
the Probe step failed, and did not result in ev0 or ev1 being
significantly slower, the accuracy rises to 84.8%. The net effectis that Prime+Probe, while effective, adds another layer ofnoise to the recovery of pointer values.
D. Breaking ASLR by testing virtual addresses

body to apply an all-ones or all-zeroes bitmask to a dataload. This results in the load working as expected when the
branch predictor is correct and only loading from offset 0
when the branch predictor guesses incorrectly. In the case of
the SLH train loop in Algorithm 4, the hardening of loaded
values also applies to the index into the array of pointers; thisshould prevent the accesses from speculatively reading past
the bounds of the array of pointers.
Since the DMP only ever sees cache misses, the (nonspeculative) access pattern caused by both loops in Algorithm 4 will be the same. SLH provides no protection against
using the DMP to bypass the bounds check. We reran our
existence experiments from Section V with the SLH compiler
flag enabled and confirmed that they still work. We also reran
the PoC from Algorithm 3 getting an accuracy of 88.0% with
the AoP accesses turned back into a loop, SLH enabled, andusing the PMC. Indeed, the exploits should still work since
to the memory system, the memory accesses caused by bothloops in Algorithm 4 will be the same, and the additional
instructions inserted from SLH do not prevent DMP activation.
While it is unsurprising that SLH does not protect against
DMP leakage, it is important to note that some code vulnerable
to Spectre V1, but protected by SLH, will continue to bevulnerable to the same receive side-channel as before. As
such, a developer applying SLH to attacker submitted code orcode containing latent DMP gadgets (such Algorithm 4) gains
almost no defensive advantage. However, unlike the Spectre
attacks that SLH was designed to prevent, the M1 DMP has amaximum stride and depth which constrains the furthest value
past the end of a buffer that can be prefetched.

C. Retrieving leaked pointers via Prime+Probe
The previous example primitives rely on the adversary being
able to directly time accesses to the targeted pointers todetermine their cache state. This is often not possible, andwe can instead use cache side-channels like Prime+Probe todetermine if a given pointer was prefetched.

Address space layout randomization (ASLR) is a widely
deployed defense that prevents attackers from knowing a priori
where important parts of a program live in memory. It does
this by randomizing the memory locations of portions of aprogram such as the stack, heap, code, and libraries.
Breaking ASLR (that is, discovering the virtual addresses ofcode and data pages) is a core step in a larger exploit. We show
how the DMP can be used to check whether arbitrary pointers
are valid mapped virtual memory addresses and thus aid in
breaking ASLR. Using the DMP rather than a cache sidechannel removes the need for knowledge of the cache system,or creating eviction sets, and is significantly less noisy.
We set up an experiment similar to Algorithm 2, withthe third pointer (p3) replaced with the address we wish
to test validity of. Since the DMP requires 3 accesses (seeSection VI-A) that match the AoP pattern to activate, we
can use the DMP’s confidence threshold as a metric for thevalidity of p3. Since the test address may not be readable andreading it would cause a segfault, ensure that all three training
accesses are only speculative, and eventually squashed. Since
Section VI-A showed that the DMP can be activated in these
conditions, the fourth pointer (p4, the target pointer) will be
prefetched if and only if the p3 (the test address) was valid.
Using our experiment code from Algorithm 2 written in C
(and using mach_absolute_time), we can test a virtual
address for validity on average every 24.91 ms with standard
deviation 0.79 ms. This long duration is due to an unoptimized
implementation that uses cache thrashing rather than targeted
eviction sets. The attacker can repeat this per-pointer validity
test to sweep across the address space, trying each virtual
memory page and determining which are mapped. This will,at the least, reveal the location and size of memory regionsthat are mapped for use by the program.
VIII. M ITIGATING THE THREAT OF DMP S
Unfortunately, the AoP DMP is already widely deployed on
at least the A14 and M1 family of processors. This DMP, to ourknowledge, cannot be disabled via software updates. Given

14

that our experiments show the DMP is not present on Icestorm
cores (See Section V-E), the only dependable mitigation is to
execute sensitive software on the Icestorm cores at a significant
performance cost. For sensitive software running on Firestorm
cores, our remaining option is to modify the software to besteffort avoid DMP-caused data leakage.
A. Removing secrets
If we assume a sandboxed threat model, our most straightforward solution is similar to the one adopted by most Spectre
defenses: do not keep secret data in the same virtual address
space as the adversary sandbox or user-space program. This is
only applicable to cases where secret data and attacker code
are co-located, and is not relevant to other situations.
Since Spectre vulnerabilities have put all of a process’
virtual memory space at risk of being leaked, we have seen
widescale deployment of policies like Chrome’s Site Isolation [39]. These policies segment untrusted code (like sandboxed JavaScript) from sensitive data (such as the rendering
data from another web origin) by placing them into entirely
separate virtual address spaces. Similarly, KPTI/KAISER [24]removed virtual address mappings for the kernel from userspace processes. The net effect of these changes was theremoval of valuable targets from the virtual address spaceof highly attacker-influenceable code. Thankfully, these partitioning efforts have removed most of the obvious sandbox
or userspace to kernel attack surfaces for the M1 DMP.
B. Preventing M1 DMP interaction
For both the sandbox and latent gadget cases, we can use
any features or implementation quirks that cause the DMP toignore values or never activate. We consider this as preventing
the DMP from ever accessing and transmitting a secret bit.
In Section VI-B2 we found that the M1’s DMP is unwillingto prefetch pointers to specific virtual address regions. As the
DMP will skip pointers that are in this address range even after
it begins fetching nearby pointers, we can put all data in thisregion and prevent pointers to it from leaking. We caution that
there is no known explanation for why this region exists, andleveraging it should not be considered a complete mitigation.
We also found that the DMP requires pointers to be aligned
on 8-byte boundaries. If all pointers in the program are non8-byte aligned, the prefetcher cannot to prefetch them.
C. Protecting non-pointer values from the M1 DMP
Both of the above approaches assume that the DMP leaks
only pointer values. We believe that this is not a fundamental
limitation of the M1 DMP, and that by observing changes tothe cache caused by page walks and the TLB an adversary may
be able to receive information about a failed (invalid pointer)
prefetch. If this is the case, we must consider any page walkthat varies based on secret bits to be leaking information [23].
One possible defense would be to only store secret data in thebottom N-bits of every 64-bit aligned chunk, and ensure thatthe top N-bits are never a valid virtual address prefix. Any
attempted prefetch of a 64-bit chunk containing secrets would
then fail before the pagewalk encountered secret related bits.

D. General DMP mitigations
The only generalized, but incomplete, mitigation to all
DMPs is to remove secrets from the virtual address spaces
accessible to adversaries, similar to many Spectre mitigations.
Unfortunately there is no guarantee that all DMP implementations will happen to reach a subset of the memory reachable
by Spectre. As we outlined in Section IV there are many
possible design possibilities like aliasing or cross-PID trainingthat would reach beyond what a Spectre attack can.
Orthogonal to removal of secrets, we should also consider
cases where a privileged non-malicious program contains
latent DMP gadgets that must be detected and removed. In
our experiments we repeatedly unintentionally activated the
AoP DMP by storing pointers on the stack. With a DMP
this aggressive, it is possible for a program to be accidentallyleaking secret values without any intervention by an adversary.

IX. C ONCLUSIONS
Exotic microarchitectural optimizations that leak data neveraccessed by the core have arrived in mainstream processors
and are unlikely to disappear any time soon. The M1 has
been rightfully lauded for performance and efficiency, andthe recent M1 Pro and Max continue to drive excitement for
novel microarchitectural approaches. While exceptional now,
we expect that this AoP DMP is only the first of many DMPs
to be deployed across all architectures and manufacturers.
Here, we’ve demonstrated that, while difficult to wield, theM1’s DMP is capable of being abused by an adversary. It
can read and transmit some types of memory values outsideof sandboxes or test the validity of pointers controlled by anattacker. This is despite a single-level pointer-chasing DMP
being nearly the worst-case DMP for an attacker, leaking only
pointers and only under restricted situations. Thankfully, many
particularly worrying scenarios like JavaScript sandboxes already assume that an adversary can leak any value in thevirtual address space. These systems are unlikely to havesignificant security impacts from the M1 DMP. However, given
the ease with which the DMP can be activated, it is likely thatexisting programs and kernels contain latent DMP gadgets thatcan be leveraged to leak data in their own address spaces.
As with timing attacks, Spectre attacks, and others, weemphasize the need for compiler and program transformation
tools to adapt to mitigate data at rest leakage. The M1 DMP
is an opportunity to prepare our defensive software techniques
for the next generation of microarchitectural attacks.

X. ACKNOWLEDGMENTS
We thank our anonymous reviewers for their valuable feedback to this paper. We thank Andrei Frumusanu for their
exceptionally insightful remark “[...] we might believe they’reusing some sort of pointer-chase prefetching mechanism.”[22].
We thank Dean Tullsen for seeding this idea. This work was
funded partially by NSF grants 1954521 and 1942888, as well
as by an Intel RARE grant.

15

R EFERENCES[1] Energy Efficiency Guide for Mac Apps: Prioritize Work at
the Task Level. https://developer.apple.com/library/archive/
documentation/Performance/Conceptual/power efficiency gui
delines osx/PrioritizeWorkAtTheTaskLevel.html.
[2] Intel x86 64 and ia32 developers manual. https://software.intel.com/en-us/articles/intel-sdm.
[3] Mach absolute timer. https://developer.apple.com/documentation/kernel/1462446-mach absolute time.
[4] Software optimization guide for amd epyc 7003 processors. ht
tps://www.amd.com/system/files/TechDocs/56665.zip.
[5] Spectre attack example. https://github.com/Eugnis/spectre-attac
k.
[6] Spectre V1 defense in GCC. https://lwn.net/Articles/759423/.
[7] Speculative load hardening. https://llvm.org/docs/SpeculativeL
oadHardening.html.
[8] Onur Aciicmez, Jean-Pierre Seifert, and Cetin Kaya Koc. Predicting secret keys via branch prediction. IACR, 2006.
[9] Sam Ainsworth and Timothy M. Jones. Graph prefetching using
data structure knowledge. ICS, 2016.
[10] Sam Ainsworth and Timothy M. Jones. An event-triggered
programmable prefetcher for irregular workloads. ASPLOS,
2018.
[11] Apple. Apple event - november 10, 2020. https://www.apple.c
om/apple-events/, 2020.
[12] Apple. Optimize for apple silicon with performance and efficiency cores. https://developer.apple.com/news/?id=vk3m204o,
2020.
[13] Daniel J. Bernstein.
The Poly1305-AES MessageAuthentication Code. FSE, 2005.
[14] Daniel J. Bernstein. Curve25519: New diffie-hellman speedrecords. PKC, 2006.
[15] Chandler Carruth.
Speculative load hardening.
https://docs.google.com/document/d/1wwcfv3UV9ZnZVc
GiGuoITT 61e Ko3TmoCS3uXLcJR0/edit#.
[16] Sunjay Cauligi, Gary Soeller, Fraser Brown, Brian Johannesmeyer, Yunlu Huang, Ranjit Jhala, and Deian Stefan. Fact: A
flexible, constant-time programming language. SecDev, 2017.
[17] Yun Chen, Lingfeng Pei, and Trevor E. Carlson. Leaking control
flow information via the hardware prefetcher. arXiv, 2021.
[18] Robert Cooksey, Stephan Jourdan, and Dirk Grunwald. A
stateless, content-directed data prefetching mechanism. SIGOPS
Oper. Syst. Rev., 2002.
[19] Bart Coppens, Ingrid Verbauwhede, Koen De Bosschere, andBjorn De Sutter. Practical mitigations for timing-based sidechannel attacks on modern x86 processors. S&P, 2009.
[20] Patrick Cronin and Chengmo Yang. A fetching tale: Covert
communication with the hardware prefetcher. HOST, 2019.
[21] Babak Falsafi and Thomas F. Wenisch. A primer on hardware
prefetching. Synth. Lect. Comput. Archit., 2014.
[22] Andrei Frumusanu. Apple announces the Apple Silicon M1:
Ditching x86 - What to Expect, Based on A14, Nov 2020.
[23] Ben Gras, Kaveh Razavi, Herbert Bos, and Cristiano Giuffrida.
Translation Leak-aside Buffer: Defeating Cache Side-channel
Protections with TLB Attacks. Sec, 2018.
[24] Daniel Gruss, Moritz Lipp, Michael Schwarz, Richard Fellner,
Clémentine Maurice, and Stefan Mangard. Kaslr is dead: Long
live kaslr. ESSOS, 2017.
[25] Daniel Gruss, Clémentine Maurice, Anders Fogh, Moritz Lipp,and Stefan Mangard. Prefetch Side-Channel Attacks: Bypassing
SMAP and Kernel ASLR. CCS, 2016.
[26] hoakley. Cores shouldn’t all be the same: M1 Macs do better,
May 2021.
[27] Dougall Johnson. Apple CPU. https://github.com/dougallj/appl
ecpu, 2021.
[28] Dougall Johnson. Apple M1 Microarchitecture Research. https://dougallj.github.io/applecpu/firestorm.html, 2022.
[29] Vladimir Kiriansky, Ilia A. Lebedev, Saman P. Amarasinghe,
Srinivas Devadas, and Joel Emer. Dawg: A defense against

cache timing attacks in speculative execution processors. MICRO, 2018.
[30] Paul Kocher, Daniel Genkin, Daniel Gruss, Werner Haas, Mike
Hamburg, Moritz Lipp, Stefan Mangard, Thomas Prescher,Michael Schwarz, and Yuval Yarom. Spectre attacks: Exploiting
speculative execution. S&P, 2019.
[31] Sangho Lee, Ming-Wei Shih, Prasun Gera, Taesoo Kim, Hyesoon Kim, and Marcus Peinado. Inferring fine-grained control
flow inside SGX enclaves with branch shadowing. Sec, 2017.
[32] Kevin M. Lepak and Mikko H. Lipasti. On the value localityof store instructions. ISCA, 2000.
[33] Moritz Lipp, Michael Schwarz, Daniel Gruss, Thomas Prescher,
Werner Haas, Stefan Mangard, Paul Kocher, Daniel Genkin,Yuval Yarom, and Mike Hamburg. Meltdown: Reading kernel
memory from user space. Sec, 2018.
[34] Hector Martin. M1 dram scaling observed. https://twitter.com/
marcan42/status/1450364369519276032, 2021.
[35] Dag Arne Osvik, Adi Shamir, and Eran Tromer. Cache attacks
and countermeasures: The case of aes. In CT-RSA’06, 2006.
[36] Riccardo Paccagnella, Licheng Luo, and Christopher W.
Fletcher. Lord of the ring(s): Side channel attacks on the CPU
on-chip ring interconnect are practical. Sec, 2021.
[37] Gennady Pekhimenko, Vivek Seshadri, Onur Mutlu, Michael A.
Kozuch, Phillip B. Gibbons, and Todd C. Mowry. Base-deltaimmediate compression: Practical data compression for on-chipcaches. PACT, 2012.
[38] Colin Percival. Cache missing for fun and profit. Proc. of
BSDCan, 2005.
[39] Charles Reis, Alexander Moshchuk, and Nasko Oskov. Site
isolation: Process separation for web sites within the browser.
Sec, 2019.
[40] Amir Roth, Andreas Moshovos, and Gurindar S. Sohi. Dependence based prefetching for linked data structures. SIGOPS
Oper. Syst. Rev., 1998.
[41] Sreenivas Subramoneyand Stanislav Shwartsmanand Anant Noriand Shankar Balachandranand Elad Shtiegmannand Vineeth
Mekkatand Manjunath Shevgoor and Sourabh Alurkar. System,
method, and apparatus for enhanced pointer identification andprefetching, August 2021.
[42] Youngjoo Shin, Hyung Chan Kim, Dokeun Kwon, Ji Hoon
Jeong, and Junbeom Hur. Unveiling hardware-based data
prefetcher, a hidden source of information leakage. CCS, 2018.
[43] Andrei Tatar, Daniël Trujillo, Cristiano Giuffrida, and Herbert
Bos. TLB;DR: Enhancing TLB-based attacks with TLB desynchronized reverse engineering. Sec, 2022.
[44] Po-An Tsai, Andres Sanchez, Christopher W. Fletcher, andDaniel Sanchez. Safecracker: Leaking Secrets through Compressed Caches. ASPLOS, 2020.
[45] Jose Rodrigo Sanchez Vicarte, Pradyumna Shome, Nandeeka
Nayak, Caroline Trippel, Adam Morrison, David Kohlbrenner,and Christopher W. Fletcher. Opening Pandora’s Box: A
Systematic Study of New Ways Microarchitecture Can Leak
Private Data. ISCA, 2021.
[46] Pepe Vila, Boris Köpf, and José F. Morales. Theory and practiceof finding eviction sets. S&P, 2019.
[47] Yuanzhong Xu, Weidong Cui, and Marcus Peinado. Controlledchannel attacks: Deterministic side channels for untrusted operating systems. S&P, 2015.
[48] Yuval Yarom and Katrina Falkner. Flush+Reload: A highresolution, low noise, L3 cache side-channel attack. Sec, 2014.
[49] Jiyong Yu, Lucas Hsiung, Mohamad El Hajj, and Christopher W. Fletcher. Data oblivious isa extensions for side channelresistant and high performance computing. NDSS, 2019.
[50] Xiangyao Yu, Christopher J. Hughes, Nadathur Satish, andSrinivas Devadas. Imp: Indirect memory prefetcher. MICRO,
2015.
[51] Xiangyao Yu, Christopher J. Hughes, and Nadathur Rajagopalan
Satish. Hardware prefetcher for indirect access patterns, February 2017.