#!/usr/bin/perl -w
#
# Override the Intel "processor dispatch" code
#

use strict;
use warning;

my %capabilityFlag = (
    "f16c"  => '00000400',
    "avx"   => '00000200',
    "sse42" => '00800000',
    "sse41" => '00200000',
    "ssse3" => '00100000',
    "sse3"  => '00080000'
);

sub usage {
    my $exe = shift;
    print "Usage: $exe cap exeFile\n\n";
    print ' Override the Intel "processor dispatch" code embedded in exeFile with specified "cap"' . "\n";
    print " where cap can be one of:\n\n";
    foreach ( keys %capabilityFlag ) {
        print "\t$_\n";
    }
    exit;
}

usage($0) if ( 1 != $#ARGV );
usage($0) unless ( exists $capabilityFlag{ $ARGV[0] } );

my $file        = $ARGV[1];
my $patchedFile = "$file." . $ARGV[0] . ".patched";
my $patchBytes  = $capabilityFlag{ $ARGV[0] };

open( FILE, $file ) or die("Couldn't open file '$file': $!");
binmode(FILE);
my ($contents) = join( '', <FILE> );    # Shlurp up file into one long binary string
close(FILE);

my ($unp) = unpack( 'H*', $contents );    # Unpack into a sequence of hex bytes

# Replace
#
#  400c90:       48 8b 05 51 35 20 00    mov    0x203551(%rip),%rax        # 6041e8 <_DYNAMIC+0x1b8>
#  400c97:       8b 00                   mov    (%rax),%eax
#  400c99:       a9 80 ff ff ff          test   $0xffffff80,%eax
#  400c9e:       0f 85 1c 00 00 00       jne    400cc0 <__intel_new_proc_init.H>
#
# with
#
#                48 8b 05 51 35 20 00    mov    0x203551(%rip),%rax        # 6041e8 <_DYNAMIC+0x1b8>
#                bb 00 08 00 00          mov    $0x800,%ebx
#                89 18                   mov    %ebx,(%rax)
#                90                      nop
#                e9                      jmp

my $orig;
while ( $unp =~ /488b05([0-9a-f]{8})8b00a9([0-9a-f]{8})0f85/ ) {
    $orig = '488b05' . $1 . '8b00a9' . $2 . '0f85';
    my $patch = '488b05' . $1 . "bb${patchBytes}891890e9";

    $unp =~ s/$orig/$patch/;
}

exit unless ( defined($orig) );
open( OUTPUT, ">${patchedFile}" ) or die("Can't create output file ${patchedFile}: $!");
print OUTPUT pack( 'H*', $unp );
close(OUTPUT);
`chmod --reference="$file" "${patchedFile}"`;    # chmod to original file's mode
print "Created ${patchedFile}\n";

#if ( $unp =~ /488b05([0-9a-f]{8})8b00a980ffffff0f85/ ) {
#	print "found $1\n";
#	my $newaddr = 3+ unpack("L",pack("H*", $1));
#	my $patch=  unpack("H*",pack("V",$newaddr));
#
#	$patch = 'c705' . $patch . '000800009090909090e9';
#
#    $unp =~ s/488b05([0-9a-f]{8})8b00a980ffffff0f85/$patch/;
#
#    open( OUTPUT, ">a.out.new" ) or die("Can't create output file 'a.out.new': $!");
#    print OUTPUT pack( 'H*', $unp );
#    close(OUTPUT);
#}
