File Coverage

blib/lib/Games/Hack/Patch/i686.pm
Criterion Covered Total %
statement 16 16 100.0
branch 12 12 100.0
condition n/a
subroutine 1 1 100.0
pod 1 1 100.0
total 30 30 100.0


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2             # vim: set sw=2 expandtab : #
3             # Master version is at https://developer.berlios.de/projects/games-hack/
4              
5             package Games::Hack::Patch::i686;
6              
7             $VERSION=0.52;
8              
9             require Exporter;
10             @ISA = qw(Exporter);
11             @EXPORT = qw(GetNOP);
12              
13              
14              
15              
16             sub GetNOP
17             {
18 8     8 1 3096 my($adr_start, $adr_end, $disass)=@_;
19 8         13 my($binary, $diff);
20              
21 8         21 $binary="";
22              
23             ### Floating point store? Stores always %ST(0).
24 8 100       48 if ($disass =~ m#^f[bi]?st(p)?[sl]? #)
    100          
    100          
25             {
26 3 100       12 if ($1)
27             {
28             # If the "Pop" flag is given in the "fst" ("floating point store")
29             # operation, we need to clean the floating point stack.
30             # We use the "ffreep st(0)" instruction, .
31 2         3 $binary .= "\xdf\xc0";
32              
33 2         5 $adr_start += 2;
34             }
35             # Rest gets done by jump.
36             }
37             # Popping values from the stack
38             elsif ($disass =~ m#^pop#)
39             {
40             # increment esp; rest done by jump.
41             # is there a 64bit pop?
42 1         3 $binary .= "\x83\xc4\x04";
43 1         2 $adr_start += 3;
44             }
45             ### Integer move or direct modification
46             elsif ($disass =~ m#^(mov|or|and)#)
47             {
48             # done by jump.
49             }
50             else
51             {
52 2         21 warn "Unknown instruction '" . $disass . "', patching unsafe!";
53 2         11 return undef;
54             }
55              
56              
57             ### short jump
58 6 100       16 if (($diff=$adr_end-$adr_start) >= 2)
59             {
60             # The opcode needs two bytes; these are already consumed, and so the jump
61             # distance has to be reduced.
62 4         41 $binary .= "\xeb" . pack("C", $diff-2);
63 4         6 $adr_end=$adr_start;
64             }
65              
66             ### NOP.
67             # That should never be needed ... all instructions involving memory access
68             # (even via a register) have at least 2 bytes.
69             # (If some value would be persistently stored in a register, we wouldn't
70             # find it by looking at the memory contents.)
71 6 100       19 $binary .= "\x90" x $diff
72             if ($diff=$adr_end-$adr_start) >= 1;
73              
74 6         21 return $binary;
75             }
76              
77             __END__