Skip to content

Instantly share code, notes, and snippets.

@dougallj
Created January 3, 2018 08:55
Show Gist options
  • Star 35 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save dougallj/f9ffd7e37db35ee953729491cfb71392 to your computer and use it in GitHub Desktop.
Save dougallj/f9ffd7e37db35ee953729491cfb71392 to your computer and use it in GitHub Desktop.
x86-64 Speculative Execution Harness
global _time_load
global _cache_flush
global _run_attempt
extern _bools
extern _values
extern _pointers
section .text
_time_load:
rdtscp
mov r9, rax
inc byte [rdi]
rdtscp
dec byte [rdi]
sub rax, r9
ret
_cache_flush:
clflush [rdi]
ret
_run_attempt:
push rbp
mov rbp, rsp
push r15
push r14
push r13
push r12
push rbx
push rax
mov r14, 0FFFFFFFFFFFFE000h
lea rbx, [rel _bools]
lea r15, [rel _values]
mov ecx, edi
loop:
lea rax, [rel _pointers]
mov r13, [rax+r14+2000h]
mov rdi, rbx
clflush [rbx]
mov edi, [rbx]
cmp edi, 0
jnz skip
; access the pointer - this instruction will
; only execute speculatively, but load P into L1
movzx eax, byte [r13]
skip:
add rbx, 4
inc r15
add r14, 8
jnz loop
add rsp, 8
pop rbx
pop r12
pop r13
pop r14
pop r15
pop rbp
retn
set -e
nasm -f macho64 asm.s
clang asm.o spec.c -o spec
#include <stdio.h>
#include <stdint.h>
uint64_t time_load(void* o);
void cache_flush(void* o);
void run_attempt(void);
uint64_t buffer[4096];
uint64_t dummy_buffer[4096];
int bools[1024];
uint8_t *pointers[1024];
uint8_t values[1024];
int main() {
uint64_t *p = &buffer[4096/2];
uint64_t *dummy_p = &dummy_buffer[4096/2];
for (int i = 0; i < 1024; i++) {
// if you set this value to one, the branch will correctly predict
// to skip pointers[1000]. this disables speculative execution (and
// demonstrates a "false" result).
bools[i] = 0;
pointers[i] = dummy_p;
if (i == 1000) {
bools[i] = 1;
pointers[i] = p;
}
}
#define NUM_ATTEMPTS 20
uint64_t times[NUM_ATTEMPTS];
for (int attempt = 0; attempt < NUM_ATTEMPTS; attempt++) {
cache_flush(p);
run_attempt();
times[attempt] = time_load(p);
}
printf("bools: %p\n", &bools[0]);
uint64_t min = times[0];
for (int attempt = 0; attempt < NUM_ATTEMPTS; attempt++) {
printf("time: %llu!\n", times[attempt]);
if (times[attempt] < min) {
min = times[attempt];
}
}
printf("min: %llu!\n", min);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment