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 |
#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