// File: /workspace/github_c_makefile_star2_O0/vusec[P]fpvi-scsb/fp_reverse_engineering/test_operands/test_operands.c
// Function: main
int main(int argc, char **argv)
{
    uint64_t x_hex, y_hex;
    
    //Ensure SSE default settings
    #ifdef x86
    _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_OFF);
    _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_OFF);
    #endif

    if (argc < 3)
    {
        fprintf(stderr, "Usage: %s <x> <y>\nEg: %s 0xc000e8b2c9755600 0x0004000000000000\n", argv[0], argv[0]);
        return -1;
    }
    sscanf(argv[1], "0x%lx", &x_hex);
    sscanf(argv[2], "0x%lx", &y_hex);

    /* Flush+Reload setup */
    __attribute__((aligned(4096))) size_t results[256] = {0};
    unsigned char *reloadbuffer = mmap(NULL, 256*STRIDE, PROT_READ | PROT_WRITE,
    #if defined(x86)
                                       MAP_ANONYMOUS | MAP_PRIVATE | MAP_POPULATE | MAP_HUGETLB, -1, 0);
    #elif defined(armv8)
                                       MAP_ANONYMOUS | MAP_PRIVATE | MAP_POPULATE, -1, 0);
    #else
    #error  "not supported arch"
    #endif
    
    /* Debug prints of input operands and arch result */
    double   x = *((double *)&x_hex);
    double   y = *((double *)&y_hex);
    //Get the FP architectural result of x/y
    uint64_t arch_res_hex = fp_leak_trans_res(reloadbuffer, &x_hex, &y_hex, 0);
    double   arch_res = *((double *) &arch_res_hex);

    print_double("x", x);
    print_double("y", y);
    print_double("arch_res", arch_res);

    /* Recover trans_res nibble by nibble
     * Leaking nibbles instead of bytes due to less noise
     */
    uint64_t trans_res_hex = 0;
    for(int i=0; i<16; i++)
    {
        memset(results, 0, sizeof(results));

        for(int j=0; j<ITER; j++)
        {
            flush(reloadbuffer);
            fp_leak_trans_res(reloadbuffer, &x_hex, &y_hex, i*4);
            reload(reloadbuffer, results);
        }

#if DEBUG == 1
        printf("Nibble %d:\n", i);
        print_results(results, ITER/10);
#endif
        //Reconstruct the speculative value
        uint8_t arch_nibble = (arch_res_hex>>i*4)&0xf;
        uint8_t spec_nibble = arch_nibble;

        //Arch result hit must be always be present, otherwise it means F+R is broken
        assert(results[arch_nibble] > ITER/10);
        for(int j=0; j<16; j++)
        {
            if(results[j] > ITER/10 && j != arch_nibble)
            {
                spec_nibble = j;    
            }
        }
        trans_res_hex |= ((uint64_t) spec_nibble) << (i*4);
    }
    
    double trans_res = *((double *)&trans_res_hex);
    print_double("trans_res", trans_res);

    return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
andq $-0x1000, %rsp          # imm = 0xF000
subq $0x2000, %rsp           # imm = 0x2000
movl $0x0, 0x1f7c(%rsp)
movl %edi, 0x1f78(%rsp)
movq %rsi, 0x1f70(%rsp)
stmxcsr 0x1f5c(%rsp)
movl 0x1f5c(%rsp), %eax
andl $-0x41, %eax
orl $0x0, %eax
movl %eax, 0x1f58(%rsp)
ldmxcsr 0x1f58(%rsp)
stmxcsr 0x1f54(%rsp)
movl 0x1f54(%rsp), %eax
andl $0xffff7fff, %eax       # imm = 0xFFFF7FFF
orl $0x0, %eax
movl %eax, 0x1f50(%rsp)
ldmxcsr 0x1f50(%rsp)
cmpl $0x3, 0x1f78(%rsp)
jge 0x13fe
movq 0x2c31(%rip), %rax      # 0x3ff8
movq (%rax), %rdi
movq 0x1f70(%rsp), %rax
movq (%rax), %rdx
movq 0x1f70(%rsp), %rax
movq (%rax), %rcx
leaq 0xca1(%rip), %rsi       # 0x2088
movb $0x0, %al
callq 0x1070
movl $0xffffffff, 0x1f7c(%rsp) # imm = 0xFFFFFFFF
jmp 0x1884
movq 0x1f70(%rsp), %rax
movq 0x8(%rax), %rdi
leaq 0xcb7(%rip), %rsi       # 0x20c8
leaq 0x1f68(%rsp), %rdx
movb $0x0, %al
callq 0x1080
movq 0x1f70(%rsp), %rax
movq 0x10(%rax), %rdi
leaq 0xc95(%rip), %rsi       # 0x20c8
leaq 0x1f60(%rsp), %rdx
movb $0x0, %al
callq 0x1080
leaq 0x1000(%rsp), %rdi
xorl %esi, %esi
movl $0x800, %edx            # imm = 0x800
callq 0x1060
xorl %eax, %eax
movl %eax, %r9d
movl $0x80000, %esi          # imm = 0x80000
movl $0x3, %edx
movl $0x48022, %ecx          # imm = 0x48022
movl $0xffffffff, %r8d       # imm = 0xFFFFFFFF
movq %r9, %rdi
callq 0x1030
movq %rax, 0xff8(%rsp)
movsd 0x1f68(%rsp), %xmm0
movsd %xmm0, 0xff0(%rsp)
movsd 0x1f60(%rsp), %xmm0
movsd %xmm0, 0xfe8(%rsp)
movq 0xff8(%rsp), %rdi
leaq 0x1f68(%rsp), %rsi
leaq 0x1f60(%rsp), %rdx
xorl %eax, %eax
movl %eax, %ecx
callq 0x1890
movq %rax, 0xfe0(%rsp)
movsd 0xfe0(%rsp), %xmm0
movsd %xmm0, 0xfd8(%rsp)
movsd 0xff0(%rsp), %xmm0
leaq 0xbdd(%rip), %rdi       # 0x20cc
callq 0x1260
movsd 0xfe8(%rsp), %xmm0
leaq 0xbca(%rip), %rdi       # 0x20ce
callq 0x1260
movsd 0xfd8(%rsp), %xmm0
leaq 0xbb7(%rip), %rdi       # 0x20d0
callq 0x1260
movq $0x0, 0xfd0(%rsp)
movl $0x0, 0xfcc(%rsp)
cmpl $0x10, 0xfcc(%rsp)
jge 0x1852
leaq 0x1000(%rsp), %rdi
xorl %esi, %esi
movl $0x800, %edx            # imm = 0x800
callq 0x1060
movl $0x0, 0xfc8(%rsp)
cmpl $0x3e8, 0xfc8(%rsp) # imm = 0x3E8
jge 0x1753
movq 0xff8(%rsp), %rax
movq %rax, 0x1f88(%rsp)
movq $0x0, 0x1f80(%rsp)
cmpq $0x100, 0x1f80(%rsp) # imm = 0x100
jae 0x15cd
movq 0x1f88(%rsp), %rax
movq 0x1f80(%rsp), %rcx
shlq $0xb, %rcx
addq %rcx, %rax
clflush (%rax)
movq 0x1f80(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x1f80(%rsp)
jmp 0x158f
mfence
movq 0xff8(%rsp), %rdi
movl 0xfcc(%rsp), %eax
shll $0x2, %eax
movslq %eax, %rcx
leaq 0x1f68(%rsp), %rsi
leaq 0x1f60(%rsp), %rdx
callq 0x1890
movq 0xff8(%rsp), %rcx
leaq 0x1000(%rsp), %rax
movq %rcx, 0x1fc0(%rsp)
movq %rax, 0x1fb8(%rsp)
mfence
movq $0x0, 0x1fb0(%rsp)
cmpq $0x100, 0x1fb0(%rsp) # imm = 0x100
jae 0x173b
imulq $0xa7, 0x1fb0(%rsp), %rax
addq $0xd, %rax
andq $0xff, %rax
movq %rax, 0x1fa8(%rsp)
movq 0x1fc0(%rsp), %rax
movq 0x1fa8(%rsp), %rcx
shlq $0xb, %rcx
addq %rcx, %rax
movq %rax, 0x1fa0(%rsp)
rdtscp
movq %rax, 0x1fe0(%rsp)
movq %rdx, 0x1fd8(%rsp)
movq 0x1fd8(%rsp), %rax
shlq $0x20, %rax
orq 0x1fe0(%rsp), %rax
movq %rax, 0x1f98(%rsp)
movq 0x1fa0(%rsp), %rax
movq %rax, 0x1fe8(%rsp)
movq 0x1fe8(%rsp), %rax
movb (%rax), %al
rdtscp
movq %rax, 0x1fd0(%rsp)
movq %rdx, 0x1fc8(%rsp)
movq 0x1fc8(%rsp), %rax
shlq $0x20, %rax
orq 0x1fd0(%rsp), %rax
subq 0x1f98(%rsp), %rax
movq %rax, 0x1f90(%rsp)
cmpq $0xa0, 0x1f90(%rsp)
jae 0x1722
movq 0x1fb8(%rsp), %rax
movq 0x1fa8(%rsp), %rcx
movq (%rax,%rcx,8), %rdx
addq $0x1, %rdx
movq %rdx, (%rax,%rcx,8)
movq 0x1fb0(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x1fb0(%rsp)
jmp 0x1629
jmp 0x173d
movl 0xfc8(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xfc8(%rsp)
jmp 0x1562
movq 0xfe0(%rsp), %rax
movl 0xfcc(%rsp), %ecx
shll $0x2, %ecx
movl %ecx, %ecx
shrq %cl, %rax
andq $0xf, %rax
movb %al, 0xfc7(%rsp)
movb 0xfc7(%rsp), %al
movb %al, 0xfc6(%rsp)
movzbl 0xfc7(%rsp), %eax
cmpq $0x64, 0x1000(%rsp,%rax,8)
jbe 0x1798
jmp 0x17b7
leaq 0x93a(%rip), %rdi       # 0x20d9
leaq 0x952(%rip), %rsi       # 0x20f8
movl $0x66, %edx
leaq 0x956(%rip), %rcx       # 0x2108
callq 0x1050
movl $0x0, 0xfc0(%rsp)
cmpl $0x10, 0xfc0(%rsp)
jge 0x1815
movslq 0xfc0(%rsp), %rax
cmpq $0x64, 0x1000(%rsp,%rax,8)
jbe 0x1800
movl 0xfc0(%rsp), %eax
movzbl 0xfc7(%rsp), %ecx
cmpl %ecx, %eax
je 0x1800
movl 0xfc0(%rsp), %eax
movb %al, 0xfc6(%rsp)
jmp 0x1802
movl 0xfc0(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xfc0(%rsp)
jmp 0x17c2
movzbl 0xfc6(%rsp), %eax
movl 0xfcc(%rsp), %ecx
shll $0x2, %ecx
movl %ecx, %ecx
shlq %cl, %rax
orq 0xfd0(%rsp), %rax
movq %rax, 0xfd0(%rsp)
movl 0xfcc(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xfcc(%rsp)
jmp 0x1535
movsd 0xfd0(%rsp), %xmm0
movsd %xmm0, 0xfb8(%rsp)
movsd 0xfb8(%rsp), %xmm0
leaq 0x8ab(%rip), %rdi       # 0x211f
callq 0x1260
movl $0x0, 0x1f7c(%rsp)
movl 0x1f7c(%rsp), %eax
movq %rbp, %rsp
popq %rbp
retq