Created
January 3, 2018 08:55
-
-
Save dougallj/f9ffd7e37db35ee953729491cfb71392 to your computer and use it in GitHub Desktop.
x86-64 Speculative Execution Harness
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
set -e | |
nasm -f macho64 asm.s | |
clang asm.o spec.c -o spec |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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