line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package CPU::x86_64::InstructionWriter; |
2
|
|
|
|
|
|
|
our $VERSION = '0.002'; # VERSION |
3
|
17
|
|
|
17
|
|
1645436
|
use v5.10; |
|
17
|
|
|
|
|
217
|
|
4
|
17
|
|
|
17
|
|
9770
|
use Moo 2; |
|
17
|
|
|
|
|
198510
|
|
|
17
|
|
|
|
|
99
|
|
5
|
17
|
|
|
17
|
|
25186
|
use Carp; |
|
17
|
|
|
|
|
42
|
|
|
17
|
|
|
|
|
945
|
|
6
|
17
|
|
|
17
|
|
106
|
use Scalar::Util 'looks_like_number'; |
|
17
|
|
|
|
|
41
|
|
|
17
|
|
|
|
|
710
|
|
7
|
17
|
|
|
17
|
|
94
|
use Exporter 'import'; |
|
17
|
|
|
|
|
33
|
|
|
17
|
|
|
|
|
407
|
|
8
|
17
|
|
|
17
|
|
7950
|
use CPU::x86_64::InstructionWriter::Unknown; |
|
17
|
|
|
|
|
57
|
|
|
17
|
|
|
|
|
492
|
|
9
|
17
|
|
|
17
|
|
7961
|
use CPU::x86_64::InstructionWriter::Label; |
|
17
|
|
|
|
|
47
|
|
|
17
|
|
|
|
|
1000
|
|
10
|
17
|
|
|
17
|
|
11099
|
use if !eval{ pack('Q<',1) }, 'CPU::x86_64::InstructionWriter::_int32', qw/pack/; |
|
17
|
|
|
|
|
231
|
|
|
17
|
|
|
|
|
34
|
|
|
17
|
|
|
|
|
93
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
# ABSTRACT: Assemble x86-64 instructions using a pure-perl API |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
my @byte_registers= qw( AH AL BH BL CH CL DH DL SPL BPL SIL DIL R8B R9B R10B R11B R12B R13B R14B R15B ); |
16
|
|
|
|
|
|
|
my %byte_register_alias= ( map {; "R${_}L" => "R${_}B" } 8..15 ); |
17
|
|
|
|
|
|
|
my @word_registers= qw( AX BX CX DX SI DI SP BP R8W R9W R10W R11W R12W R13W R14W R15W ); |
18
|
|
|
|
|
|
|
my @long_registers= qw( EAX EBX ECX EDX ESI EDI ESP EBP R8D R9D R10D R11D R12D R13D R14D R15D ); |
19
|
|
|
|
|
|
|
my @quad_registers= qw( RAX RBX RCX RDX RSI RDI RSP RBP R8 R9 R10 R11 R12 R13 R14 R15 RIP RFLAGS ); |
20
|
|
|
|
|
|
|
my @registers= ( @byte_registers, @word_registers, @long_registers, @quad_registers ); |
21
|
|
|
|
|
|
|
{ |
22
|
|
|
|
|
|
|
# Create a constant for each register name |
23
|
17
|
|
|
17
|
|
2723
|
no strict 'refs'; |
|
17
|
|
|
|
|
38
|
|
|
17
|
|
|
|
|
38492
|
|
24
|
|
|
|
|
|
|
eval 'sub '.$_.' { \''.$_.'\' } 1' || croak $@ |
25
|
0
|
|
|
0
|
0
|
0
|
for @registers; |
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
26
|
|
|
|
|
|
|
*{__PACKAGE__."::$_"}= *{__PACKAGE__."::$byte_register_alias{$_}"} |
27
|
|
|
|
|
|
|
for keys %byte_register_alias; |
28
|
|
|
|
|
|
|
} |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
# Map 64-bit register names to the numeric register number |
31
|
|
|
|
|
|
|
my %regnum64= ( |
32
|
|
|
|
|
|
|
RAX => 0, RCX => 1, RDX => 2, RBX => 3, |
33
|
|
|
|
|
|
|
rax => 0, rcx => 1, rdx => 2, rbx => 3, |
34
|
|
|
|
|
|
|
RSP => 4, RBP => 5, RSI => 6, RDI => 7, |
35
|
|
|
|
|
|
|
rsp => 4, rbp => 5, rsi => 6, rdi => 7, |
36
|
|
|
|
|
|
|
map { $_ => $_, "R$_" => $_, "r$_" => $_ } 0..15 |
37
|
|
|
|
|
|
|
); |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
my %regnum32= ( |
40
|
|
|
|
|
|
|
EAX => 0, ECX => 1, EDX => 2, EBX => 3, |
41
|
|
|
|
|
|
|
eax => 0, ecx => 1, edx => 2, ebx => 3, |
42
|
|
|
|
|
|
|
ESP => 4, EBP => 5, ESI => 6, EDI => 7, |
43
|
|
|
|
|
|
|
esp => 4, ebp => 5, esi => 6, edi => 7, |
44
|
|
|
|
|
|
|
map { $_ => $_, "R${_}D" => $_, "r${_}d" => $_ } 0..15 |
45
|
|
|
|
|
|
|
); |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
my %regnum16= ( |
48
|
|
|
|
|
|
|
AX => 0, CX => 1, DX => 2, BX => 3, |
49
|
|
|
|
|
|
|
ax => 0, cx => 1, dx => 2, bx => 3, |
50
|
|
|
|
|
|
|
SP => 4, BP => 5, SI => 6, DI => 7, |
51
|
|
|
|
|
|
|
sp => 4, bp => 5, si => 6, di => 7, |
52
|
|
|
|
|
|
|
map { $_ => $_, "R${_}W" => $_, "r${_}w" => $_ } 0..15 |
53
|
|
|
|
|
|
|
); |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
my %regnum8= ( |
56
|
|
|
|
|
|
|
AL => 0, CL => 1, DL => 2, BL => 3, |
57
|
|
|
|
|
|
|
al => 0, cl => 1, dl => 2, bl => 3, |
58
|
|
|
|
|
|
|
SPL => 4, BPL => 5, SIL => 6, DIL => 7, |
59
|
|
|
|
|
|
|
spl => 4, bpl => 5, sil => 6, dil => 7, |
60
|
|
|
|
|
|
|
map { $_ => $_, "R${_}B" => $_, "r${_}b" => $_, "R${_}L" => $_, "r${_}l" => $_ } 0..15 |
61
|
|
|
|
|
|
|
); |
62
|
|
|
|
|
|
|
my %regnum8_high= ( |
63
|
|
|
|
|
|
|
AH => 4, CH => 5, DH => 6, BH => 7, |
64
|
|
|
|
|
|
|
ah => 4, ch => 5, dh => 6, bh => 7, |
65
|
|
|
|
|
|
|
); |
66
|
|
|
|
|
|
|
my %register_bits= ( |
67
|
|
|
|
|
|
|
(map { $_ => 64 } keys %regnum64), |
68
|
|
|
|
|
|
|
(map { $_ => 32 } keys %regnum32), |
69
|
|
|
|
|
|
|
(map { $_ => 16 } keys %regnum16), |
70
|
|
|
|
|
|
|
(map { $_ => 8 } keys %regnum8), |
71
|
|
|
|
|
|
|
); |
72
|
|
|
|
|
|
|
|
73
|
8
|
|
|
8
|
0
|
25
|
sub unknown { CPU::x86_64::InstructionWriter::Unknown->new(name => $_[0]); } |
74
|
0
|
|
|
0
|
0
|
0
|
sub unknown8 { CPU::x86_64::InstructionWriter::Unknown->new(bits => 8, name => $_[0]); } |
75
|
0
|
|
|
0
|
0
|
0
|
sub unknown16 { CPU::x86_64::InstructionWriter::Unknown->new(bits => 16, name => $_[0]); } |
76
|
0
|
|
|
0
|
0
|
0
|
sub unknown32 { CPU::x86_64::InstructionWriter::Unknown->new(bits => 32, name => $_[0]); } |
77
|
54807
|
|
|
54807
|
0
|
175079
|
sub unknown64 { CPU::x86_64::InstructionWriter::Unknown->new(bits => 64, name => $_[0]); } |
78
|
0
|
|
|
0
|
0
|
0
|
sub unknown7 { CPU::x86_64::InstructionWriter::Unknown->new(bits => 7, name => $_[0]); } |
79
|
0
|
|
|
0
|
0
|
0
|
sub unknown15 { CPU::x86_64::InstructionWriter::Unknown->new(bits => 15, name => $_[0]); } |
80
|
0
|
|
|
0
|
0
|
0
|
sub unknown31 { CPU::x86_64::InstructionWriter::Unknown->new(bits => 31, name => $_[0]); } |
81
|
0
|
|
|
0
|
0
|
0
|
sub unknown63 { CPU::x86_64::InstructionWriter::Unknown->new(bits => 63, name => $_[0]); } |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
our %EXPORT_TAGS= ( |
84
|
|
|
|
|
|
|
registers => \@registers, |
85
|
|
|
|
|
|
|
unknown => [qw( unknown unknown8 unknown16 unknown32 unknown64 unknown7 unknown15 unknown31 unknown63 )], |
86
|
|
|
|
|
|
|
); |
87
|
|
|
|
|
|
|
our @EXPORT_OK= ( map { @{$_} } values %EXPORT_TAGS ); |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
has start_address => ( is => 'rw', default => sub { unknown64() } ); |
91
|
|
|
|
|
|
|
has debug => ( is => 'rw' ); |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
has _buf => ( is => 'rw', default => sub { '' } ); |
94
|
|
|
|
|
|
|
has _unresolved => ( is => 'rw', default => sub { [] } ); |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
has labels => ( is => 'rw', default => sub {; {} } ); |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
sub get_label { |
101
|
139
|
|
|
139
|
1
|
231
|
my ($self, $name)= @_; |
102
|
139
|
|
|
|
|
268
|
my $labels= $self->labels; |
103
|
139
|
100
|
66
|
|
|
486
|
unless (defined $name && defined $labels->{$name}) { |
104
|
61
|
|
|
|
|
176
|
my $label= bless { relative_to => $self->start_address }, __PACKAGE__.'::Label'; |
105
|
61
|
50
|
|
|
|
129
|
$name= "$label" unless defined $name; |
106
|
61
|
|
|
|
|
105
|
$label->{name}= $name; |
107
|
61
|
|
|
|
|
130
|
$labels->{$name}= $label; |
108
|
|
|
|
|
|
|
} |
109
|
139
|
|
|
|
|
258
|
$labels->{$name}; |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
sub label { |
114
|
61
|
50
|
|
61
|
1
|
143
|
@_ == 2 or croak "Invalid arguments to 'mark'"; |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
# If they gave an undefined label, we auto-populate it, which modifies |
117
|
|
|
|
|
|
|
# the variable they passed to this function. |
118
|
61
|
50
|
|
|
|
129
|
$_[1]= $_[0]->get_label |
119
|
|
|
|
|
|
|
unless defined $_[1]; |
120
|
|
|
|
|
|
|
|
121
|
61
|
|
|
|
|
115
|
my ($self, $label)= @_; |
122
|
|
|
|
|
|
|
# If they give a label by name, auto-inflate it |
123
|
61
|
50
|
|
|
|
159
|
$label= $self->get_label($label) |
124
|
|
|
|
|
|
|
unless ref $label; |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
# A label can only exist once |
127
|
61
|
50
|
|
|
|
134
|
defined $label->{offset} and croak "Can't mark label '$label->{name}' twice"; |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
# Set the label's current location |
130
|
61
|
|
|
|
|
106
|
$label->{offset}= length($self->{_buf}); |
131
|
61
|
|
|
|
|
106
|
$label->{len}= 0; |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
# Add it to the list of unresolved things, so its position can be updated |
134
|
61
|
|
|
|
|
86
|
push @{ $self->_unresolved }, $label; |
|
61
|
|
|
|
|
128
|
|
135
|
61
|
|
|
|
|
143
|
return $self; |
136
|
|
|
|
|
|
|
} |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
sub bytes { |
140
|
54830
|
|
|
54830
|
1
|
97906
|
my $self= shift; |
141
|
54830
|
|
|
|
|
134567
|
$self->_resolve; |
142
|
54830
|
|
|
|
|
255299
|
return $self->_buf; |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
|
146
|
1
|
|
|
1
|
1
|
8
|
sub data { $_[0]{_buf} .= $_[1] } |
147
|
2
|
|
|
2
|
1
|
11
|
sub data_i8 { $_[0]{_buf} .= chr($_[1]) } |
148
|
1
|
|
|
1
|
1
|
11
|
sub data_i16 { $_[0]{_buf} .= pack('v', $_[1]) } |
149
|
1
|
|
|
1
|
1
|
9
|
sub data_i32 { $_[0]{_buf} .= pack('V', $_[1]) } |
150
|
0
|
|
|
0
|
1
|
0
|
sub data_i64 { $_[0]{_buf} .= pack('Q<', $_[1]) } |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
|
153
|
0
|
|
|
0
|
1
|
0
|
sub data_f32 { $_[0]{_buf} .= pack('f', $_[1]) } |
154
|
0
|
|
|
0
|
1
|
0
|
sub data_f64 { $_[0]{_buf} .= pack('d', $_[1]) } |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
sub align { # ( self, bytes, fill_byte) |
158
|
1
|
|
|
1
|
1
|
4
|
my ($self, $bytes, $fill)= @_; |
159
|
1
|
50
|
|
|
|
4
|
($bytes & ($bytes-1)) |
160
|
|
|
|
|
|
|
and croak "Bytes must be a power of 2"; |
161
|
1
|
|
|
|
|
4
|
$self->_align(~($bytes-1), $fill); |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
sub _align { |
164
|
4
|
|
|
4
|
|
13
|
my ($self, $mask, $fill)= @_; |
165
|
4
|
|
100
|
|
|
20
|
$fill //= "\x90"; |
166
|
4
|
50
|
|
|
|
13
|
length($fill) == 1 or croak "Fill byte must be 1 byte long"; |
167
|
|
|
|
|
|
|
$self->_mark_unresolved( |
168
|
|
|
|
|
|
|
0, |
169
|
|
|
|
|
|
|
encode => sub { |
170
|
|
|
|
|
|
|
#warn "start=$_[1]{start}, mask=$mask, ~mask=${\~$mask} ".((($_[1]{start} + ~$mask) & $mask) - $_[1]{start})."\n"; |
171
|
|
|
|
|
|
|
$fill x ((($_[1]{offset} + ~$mask) & $mask) - $_[1]{offset}) |
172
|
20
|
|
|
20
|
|
59
|
} |
173
|
4
|
|
|
|
|
23
|
); |
174
|
|
|
|
|
|
|
} |
175
|
1
|
|
|
1
|
0
|
11
|
sub align2 { splice @_, 1, 0, ~1; &_align; } |
|
1
|
|
|
|
|
3
|
|
176
|
1
|
|
|
1
|
0
|
7
|
sub align4 { splice @_, 1, 0, ~3; &_align; } |
|
1
|
|
|
|
|
4
|
|
177
|
1
|
|
|
1
|
0
|
5
|
sub align8 { splice @_, 1, 0, ~7; &_align; } |
|
1
|
|
|
|
|
4
|
|
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
sub _autodetect_signature_dst_src { |
181
|
9
|
|
|
9
|
|
24
|
my ($self, $opname, $dst, $src, $bits)= @_; |
182
|
9
|
50
|
66
|
|
|
57
|
$bits ||= $register_bits{$dst} || $register_bits{$src} |
|
|
|
33
|
|
|
|
|
183
|
|
|
|
|
|
|
or croak "Can't determine bit-width of ".uc($opname)." instruction. " |
184
|
|
|
|
|
|
|
."Use ->$opname(\$dst, \$src, \$bits) to clarify, when there is no register"; |
185
|
|
|
|
|
|
|
my $dst_type= looks_like_number($dst)? 'imm' |
186
|
|
|
|
|
|
|
: ref $dst eq 'ARRAY'? 'mem' |
187
|
|
|
|
|
|
|
: ref $dst && ref($dst)->can('value')? 'imm' |
188
|
9
|
50
|
33
|
|
|
57
|
: $register_bits{$dst}? 'reg' |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
189
|
|
|
|
|
|
|
: croak "Can't identify type of destination operand $dst"; |
190
|
|
|
|
|
|
|
my $src_type= looks_like_number($src)? 'imm' |
191
|
|
|
|
|
|
|
: ref $src eq 'ARRAY'? 'mem' |
192
|
|
|
|
|
|
|
: ref $src && ref($src)->can('value')? 'imm' |
193
|
9
|
50
|
33
|
|
|
49
|
: $register_bits{$src}? 'reg' |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
194
|
|
|
|
|
|
|
: croak "Can't identify type of source operand $src"; |
195
|
9
|
|
|
|
|
25
|
my $method= "$opname${bits}_${dst_type}_${src_type}"; |
196
|
9
|
|
33
|
|
|
51
|
($self->can($method) || croak "No ".uc($opname)." variant $method available") |
197
|
|
|
|
|
|
|
->($self, $dst, $src); |
198
|
|
|
|
|
|
|
} |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
sub _autodetect_signature_1op { |
201
|
0
|
|
|
0
|
|
0
|
my ($self, $opname, $operand, $bits)= @_; |
202
|
0
|
|
|
|
|
0
|
my $opr_type= $register_bits{$operand}; |
203
|
0
|
0
|
0
|
|
|
0
|
$bits ||= $opr_type |
204
|
|
|
|
|
|
|
or croak "Can't determine bit-width of ".uc($opname)." instruction. " |
205
|
|
|
|
|
|
|
."Use ->$opname(\$arg, \$bits) to clarify, when \$arg is not a register"; |
206
|
0
|
0
|
|
|
|
0
|
$opr_type= $opr_type? 'reg' |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
207
|
|
|
|
|
|
|
: ref $operand eq 'ARRAY'? 'mem' |
208
|
|
|
|
|
|
|
: looks_like_number($operand)? 'imm' |
209
|
|
|
|
|
|
|
: croak "Can't identify type of operand $operand"; |
210
|
0
|
|
|
|
|
0
|
my $method= "$opname${bits}_${opr_type}"; |
211
|
0
|
|
0
|
|
|
0
|
($self->can($method) || croak "No ".uc($opname)." variant $method available") |
212
|
|
|
|
|
|
|
->($self, $operand); |
213
|
|
|
|
|
|
|
} |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
sub nop { |
217
|
117
|
100
|
|
117
|
1
|
476
|
$_[0]{_buf} .= (defined $_[1]? "\x90" x $_[1] : "\x90"); |
218
|
117
|
|
|
|
|
303
|
$_[0]; |
219
|
|
|
|
|
|
|
} |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
sub pause { |
222
|
0
|
0
|
|
0
|
1
|
0
|
$_[0]{_buf} .= (defined $_[1]? "\xF3\x90" x $_[1] : "\xF3\x90"); |
223
|
0
|
|
|
|
|
0
|
$_[0] |
224
|
|
|
|
|
|
|
} |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
sub call_label { |
228
|
2
|
50
|
|
2
|
1
|
8
|
@_ == 2 or croak "Wrong arguments"; |
229
|
2
|
50
|
|
|
|
8
|
$_[1]= $_[0]->get_label |
230
|
|
|
|
|
|
|
unless defined $_[1]; |
231
|
2
|
|
|
|
|
6
|
my ($self, $label)= @_; |
232
|
17
|
|
|
17
|
|
8612
|
use integer; |
|
17
|
|
|
|
|
257
|
|
|
17
|
|
|
|
|
109
|
|
233
|
2
|
50
|
|
|
|
9
|
$label= $self->get_label($label) |
234
|
|
|
|
|
|
|
unless ref $label; |
235
|
|
|
|
|
|
|
$self->_mark_unresolved( |
236
|
|
|
|
|
|
|
5, # estimated length |
237
|
|
|
|
|
|
|
encode => sub { |
238
|
2
|
|
|
2
|
|
5
|
my ($self, $params)= @_; |
239
|
2
|
50
|
|
|
|
7
|
defined $label->{offset} or croak "Label $label is not marked"; |
240
|
2
|
|
|
|
|
6
|
my $ofs= $label->{offset} - ($params->{offset}+$params->{len}); |
241
|
2
|
50
|
|
|
|
7
|
($ofs >> 31) == ($ofs >> 31 >> 1) or croak "Offset must be within 31 bits"; |
242
|
2
|
|
|
|
|
19
|
return pack('CV', 0xE8, $ofs); |
243
|
|
|
|
|
|
|
} |
244
|
2
|
|
|
|
|
20
|
); |
245
|
2
|
|
|
|
|
11
|
$self; |
246
|
|
|
|
|
|
|
} |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
sub call_rel { |
249
|
0
|
|
|
0
|
1
|
0
|
my ($self, $immed)= @_; |
250
|
0
|
0
|
|
|
|
0
|
$self->{_buf} .= pack('CV', 0xE8, ref $immed? 0 : $immed); |
251
|
0
|
0
|
|
|
|
0
|
$self->_mark_unresolved(-4, encode => '_repack', bits => 32, value => $immed) |
252
|
|
|
|
|
|
|
if ref $immed; |
253
|
0
|
|
|
|
|
0
|
$self; |
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
sub call_abs_reg { |
257
|
7
|
|
|
7
|
1
|
17
|
my ($self, $reg)= @_; |
258
|
|
|
|
|
|
|
$self->{_buf} .= $self->_encode_op_reg_reg(0, 0xFF, 2, |
259
|
7
|
|
33
|
|
|
60
|
$regnum64{$reg} // croak("$reg is not a 64-bit register"), |
260
|
|
|
|
|
|
|
); |
261
|
7
|
|
|
|
|
20
|
$self; |
262
|
|
|
|
|
|
|
} |
263
|
|
|
|
|
|
|
|
264
|
63
|
|
|
63
|
1
|
170
|
sub call_abs_mem { $_[0]->_append_op64_reg_mem(0, 0xFF, 2, $_[1]) } |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
sub ret { |
268
|
3
|
|
|
3
|
0
|
9
|
my ($self, $pop_bytes)= @_; |
269
|
3
|
100
|
|
|
|
9
|
if ($pop_bytes) { |
270
|
2
|
50
|
|
|
|
13
|
$self->{_buf} .= pack('Cv', 0xC2, ref $pop_bytes? 0 : $pop_bytes); |
271
|
2
|
50
|
|
|
|
8
|
$self->_mark_unresolved(-2, encode => '_repack', bits => 16, value => $pop_bytes) |
272
|
|
|
|
|
|
|
if ref $pop_bytes; |
273
|
|
|
|
|
|
|
} |
274
|
|
|
|
|
|
|
else { |
275
|
1
|
|
|
|
|
4
|
$self->{_buf} .= "\xC3"; |
276
|
|
|
|
|
|
|
} |
277
|
3
|
|
|
|
|
8
|
$self; |
278
|
|
|
|
|
|
|
} |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
sub jmp { |
282
|
4
|
50
|
|
4
|
1
|
69
|
@_ == 2 or croak "Wrong arguments"; |
283
|
4
|
50
|
|
|
|
12
|
$_[1]= $_[0]->get_label |
284
|
|
|
|
|
|
|
unless defined $_[1]; |
285
|
4
|
|
|
|
|
10
|
my ($self, $label)= @_; |
286
|
17
|
|
|
17
|
|
8868
|
use integer; |
|
17
|
|
|
|
|
42
|
|
|
17
|
|
|
|
|
90
|
|
287
|
4
|
50
|
|
|
|
17
|
$label= $self->get_label($label) |
288
|
|
|
|
|
|
|
unless ref $label; |
289
|
|
|
|
|
|
|
$self->_mark_unresolved( |
290
|
|
|
|
|
|
|
2, # estimated length |
291
|
|
|
|
|
|
|
encode => sub { |
292
|
10
|
|
|
10
|
|
19
|
my ($self, $params)= @_; |
293
|
10
|
50
|
|
|
|
21
|
defined $label->{offset} or croak "Label $label is not marked"; |
294
|
10
|
|
|
|
|
19
|
my $ofs= $label->{offset} - ($params->{offset}+$params->{len}); |
295
|
10
|
|
|
|
|
23
|
my $short= (($ofs>>7) == ($ofs>>8)); |
296
|
10
|
100
|
|
|
|
43
|
return $short? |
297
|
|
|
|
|
|
|
pack('Cc', 0xEB, $ofs) |
298
|
|
|
|
|
|
|
: pack('CV', 0xE9, $ofs); |
299
|
|
|
|
|
|
|
} |
300
|
4
|
|
|
|
|
30
|
); |
301
|
4
|
|
|
|
|
18
|
$self; |
302
|
|
|
|
|
|
|
} |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
sub jmp_abs_reg { |
306
|
7
|
|
|
7
|
1
|
18
|
my ($self, $reg)= @_; |
307
|
|
|
|
|
|
|
$self->{_buf} .= $self->_encode_op_reg_reg(0, 0xFF, 4, |
308
|
7
|
|
33
|
|
|
42
|
$regnum64{$reg} // croak("$reg is not a 64-bit register"), |
309
|
|
|
|
|
|
|
); |
310
|
7
|
|
|
|
|
18
|
$self; |
311
|
|
|
|
|
|
|
} |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
sub jmp_abs_mem { |
315
|
63
|
|
|
63
|
1
|
173
|
$_[0]->_append_op64_reg_mem(0, 0xFF, 4, $_[1]); |
316
|
|
|
|
|
|
|
} |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
|
319
|
4
|
|
|
4
|
1
|
36
|
sub jmp_if_eq { shift->_append_jmp_cond(4, shift) } |
320
|
|
|
|
|
|
|
*jz= *jmp_if_eq; |
321
|
|
|
|
|
|
|
*je= *jmp_if_eq; |
322
|
|
|
|
|
|
|
|
323
|
4
|
|
|
4
|
1
|
20
|
sub jmp_if_ne { shift->_append_jmp_cond(5, shift) } |
324
|
|
|
|
|
|
|
*jne= *jmp_if_ne; |
325
|
|
|
|
|
|
|
*jnz= *jmp_if_ne; |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
|
328
|
4
|
|
|
4
|
1
|
27
|
sub jmp_if_unsigned_lt { shift->_append_jmp_cond(2, shift) } |
329
|
|
|
|
|
|
|
*jb= *jmp_if_unsigned_lt; |
330
|
|
|
|
|
|
|
*jc= *jmp_if_unsigned_lt; |
331
|
|
|
|
|
|
|
|
332
|
4
|
|
|
4
|
1
|
18
|
sub jmp_if_unsigned_gt { shift->_append_jmp_cond(7, shift) } |
333
|
|
|
|
|
|
|
*ja= *jmp_if_unsigned_gt; |
334
|
|
|
|
|
|
|
|
335
|
4
|
|
|
4
|
1
|
19
|
sub jmp_if_unsigned_le { shift->_append_jmp_cond(6, shift) } |
336
|
|
|
|
|
|
|
*jbe= *jmp_if_unsigned_le; |
337
|
|
|
|
|
|
|
|
338
|
4
|
|
|
4
|
1
|
26
|
sub jmp_if_unsigned_ge { shift->_append_jmp_cond(3, shift) } |
339
|
|
|
|
|
|
|
*jae= *jmp_if_unsigned_ge; |
340
|
|
|
|
|
|
|
*jnc= *jmp_if_unsigned_ge; |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
|
343
|
4
|
|
|
4
|
1
|
21
|
sub jmp_if_signed_lt { shift->_append_jmp_cond(12, shift) } |
344
|
|
|
|
|
|
|
*jl= *jmp_if_signed_lt; |
345
|
|
|
|
|
|
|
|
346
|
4
|
|
|
4
|
1
|
22
|
sub jmp_if_signed_gt { shift->_append_jmp_cond(15, shift) } |
347
|
|
|
|
|
|
|
*jg= *jmp_if_signed_gt; |
348
|
|
|
|
|
|
|
|
349
|
4
|
|
|
4
|
1
|
39
|
sub jmp_if_signed_le { shift->_append_jmp_cond(14, shift) } |
350
|
|
|
|
|
|
|
*jle= *jmp_if_signed_le; |
351
|
|
|
|
|
|
|
|
352
|
4
|
|
|
4
|
1
|
19
|
sub jmp_if_signed_ge { shift->_append_jmp_cond(13, shift) } |
353
|
|
|
|
|
|
|
*jge= *jmp_if_signed_ge; |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
|
356
|
4
|
|
|
4
|
1
|
20
|
sub jmp_if_sign { shift->_append_jmp_cond(8, shift) } |
357
|
|
|
|
|
|
|
*js= *jmp_if_sign; |
358
|
|
|
|
|
|
|
|
359
|
4
|
|
|
4
|
1
|
19
|
sub jmp_unless_sign { shift->_append_jmp_cond(9, shift) } |
360
|
|
|
|
|
|
|
*jns= *jmp_unless_sign; |
361
|
|
|
|
|
|
|
|
362
|
4
|
|
|
4
|
1
|
20
|
sub jmp_if_overflow { shift->_append_jmp_cond(0, shift) } |
363
|
|
|
|
|
|
|
*jo= *jmp_if_overflow; |
364
|
|
|
|
|
|
|
|
365
|
4
|
|
|
4
|
1
|
20
|
sub jmp_unless_overflow { shift->_append_jmp_cond(1, shift) } |
366
|
|
|
|
|
|
|
*jno= *jmp_unless_overflow; |
367
|
|
|
|
|
|
|
|
368
|
4
|
|
|
4
|
1
|
18
|
sub jmp_if_parity_even { shift->_append_jmp_cond(10, shift) } |
369
|
|
|
|
|
|
|
*jpe= *jmp_if_parity_even; |
370
|
|
|
|
|
|
|
*jp= *jmp_if_parity_even; |
371
|
|
|
|
|
|
|
|
372
|
4
|
|
|
4
|
1
|
24
|
sub jmp_if_parity_odd { shift->_append_jmp_cond(11, shift) } |
373
|
|
|
|
|
|
|
*jpo= *jmp_if_parity_odd; |
374
|
|
|
|
|
|
|
*jnp= *jmp_if_parity_odd; |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
|
377
|
2
|
|
|
2
|
1
|
16
|
sub jmp_cx_zero { shift->_append_jmp_cx(0xE3, shift) } |
378
|
|
|
|
|
|
|
*jrcxz= *jmp_cx_zero; |
379
|
|
|
|
|
|
|
|
380
|
2
|
|
|
2
|
1
|
6
|
sub loop { shift->_append_jmp_cx(0xE2, shift) } |
381
|
|
|
|
|
|
|
|
382
|
2
|
|
|
2
|
1
|
12
|
sub loopz { shift->_append_jmp_cx(0xE1, shift) } |
383
|
|
|
|
|
|
|
*loope= *loopz; |
384
|
|
|
|
|
|
|
|
385
|
2
|
|
|
2
|
1
|
12
|
sub loopnz { shift->_append_jmp_cx(0xE0, shift) } |
386
|
|
|
|
|
|
|
*loopne= *loopnz; |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
|
389
|
6
|
|
|
6
|
1
|
17
|
sub mov { splice(@_,1,0,'mov'); &_autodetect_signature_dst_src } |
|
6
|
|
|
|
|
14
|
|
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
|
392
|
49
|
|
|
49
|
1
|
124
|
sub mov64_reg_reg { shift->_append_op64_reg_reg(0x89, $_[1], $_[0]) } |
393
|
1
|
|
|
1
|
0
|
6
|
sub mov32_reg_reg { shift->_append_op32_reg_reg(0x89, $_[1], $_[0]) } |
394
|
0
|
|
|
0
|
0
|
0
|
sub mov16_reg_reg { shift->_append_op16_reg_reg(0x89, $_[1], $_[0]) } |
395
|
0
|
|
|
0
|
0
|
0
|
sub mov8_reg_reg { shift->_append_op8_reg_reg (0x89, $_[1], $_[0]) } |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
|
398
|
443
|
|
|
443
|
0
|
1139
|
sub mov64_mem_reg { $_[0]->_append_mov_reg_mem($_[2], $_[1], 64, 0x89, 0xA3); } |
399
|
445
|
|
|
445
|
0
|
1140
|
sub mov64_reg_mem { $_[0]->_append_mov_reg_mem($_[1], $_[2], 64, 0x8B, 0xA1); } |
400
|
442
|
|
|
442
|
0
|
1130
|
sub mov32_mem_reg { $_[0]->_append_mov_reg_mem($_[2], $_[1], 32, 0x89, 0xA3); } |
401
|
446
|
|
|
446
|
0
|
1152
|
sub mov32_reg_mem { $_[0]->_append_mov_reg_mem($_[1], $_[2], 32, 0x8B, 0xA1); } |
402
|
442
|
|
|
442
|
0
|
1119
|
sub mov16_mem_reg { $_[0]->_append_mov_reg_mem($_[2], $_[1], 16, 0x89, 0xA3); } |
403
|
444
|
|
|
444
|
0
|
1075
|
sub mov16_reg_mem { $_[0]->_append_mov_reg_mem($_[1], $_[2], 16, 0x8B, 0xA1); } |
404
|
442
|
|
|
442
|
0
|
1156
|
sub mov8_mem_reg { $_[0]->_append_mov_reg_mem($_[2], $_[1], 8, 0x88, 0xA2); } |
405
|
444
|
|
|
444
|
0
|
1071
|
sub mov8_reg_mem { $_[0]->_append_mov_reg_mem($_[1], $_[2], 8, 0x8A, 0xA0); } |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
sub _append_mov_reg_mem { |
408
|
3548
|
|
|
3548
|
|
7278
|
my ($self, $reg, $mem, $bits, $opcode, $ax_opcode)= @_; |
409
|
|
|
|
|
|
|
# AX is allowed to load/store 64-bit addresses, if the address is a single constant |
410
|
3548
|
100
|
100
|
|
|
11505
|
if (!defined $mem->[0] && $mem->[1] && !defined $mem->[2] && ($mem->[1] > 0x7FFFFFFF || ref $mem->[1])) { |
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
411
|
16
|
|
|
|
|
32
|
my $disp= $mem->[1]; |
412
|
16
|
100
|
|
|
|
77
|
if (lc($reg) eq ($bits == 64? 'rax' : $bits == 32? 'eax' : $bits == 16? 'ax' : 'al')) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
413
|
16
|
|
|
|
|
41
|
my $opstr= chr($ax_opcode); |
414
|
16
|
100
|
|
|
|
39
|
$opstr= "\x48".$opstr if $bits == 64; |
415
|
16
|
100
|
|
|
|
38
|
$opstr= "\x66".$opstr if $bits == 16; |
416
|
|
|
|
|
|
|
# Do the dance for values which haven't been resolved yet |
417
|
16
|
100
|
|
|
|
72
|
my $val= looks_like_number($disp)? $disp : $disp->value; |
418
|
16
|
100
|
|
|
|
36
|
if (!defined $val) { |
419
|
|
|
|
|
|
|
$self->_mark_unresolved( |
420
|
|
|
|
|
|
|
10, # longest instruction possible, not the greatest guess. |
421
|
|
|
|
|
|
|
encode => sub { |
422
|
14
|
|
|
14
|
|
32
|
my $v= $disp->value; |
423
|
14
|
50
|
|
|
|
31
|
defined $v or croak "Placeholder $disp has not been assigned"; |
424
|
14
|
100
|
|
|
|
58
|
return $v > 0x7FFFFFFF? $opstr . pack('Q<', $v) |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
425
|
|
|
|
|
|
|
: ($bits == 16? "\x66":'') |
426
|
|
|
|
|
|
|
. $_[0]->_encode_op_reg_mem($bits == 64? 8 : 0, $opcode, 0, undef, $v); |
427
|
|
|
|
|
|
|
} |
428
|
8
|
|
|
|
|
52
|
); |
429
|
|
|
|
|
|
|
} else { |
430
|
8
|
|
|
|
|
31
|
$self->{_buf} .= $opstr . pack('Q<', $val); |
431
|
|
|
|
|
|
|
} |
432
|
16
|
|
|
|
|
113
|
return $self; |
433
|
|
|
|
|
|
|
} |
434
|
|
|
|
|
|
|
} |
435
|
|
|
|
|
|
|
# Else normal encoding for reg,mem |
436
|
3532
|
100
|
|
|
|
7972
|
return $self->_append_op64_reg_mem(8, $opcode, $reg, $mem) if $bits == 64; |
437
|
2648
|
100
|
|
|
|
5414
|
return $self->_append_op32_reg_mem(0, $opcode, $reg, $mem) if $bits == 32; |
438
|
1764
|
100
|
|
|
|
3995
|
return $self->_append_op16_reg_mem(0, $opcode, $reg, $mem) if $bits == 16; |
439
|
882
|
50
|
|
|
|
2323
|
return $self->_append_op8_reg_mem (0, $opcode, $reg, $mem) if $bits == 8; |
440
|
|
|
|
|
|
|
} |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
sub mov64_reg_imm { |
445
|
63
|
|
|
63
|
1
|
141
|
my ($self, $reg, $immed)= @_; |
446
|
63
|
|
33
|
|
|
152
|
$reg= $regnum64{$reg} // croak("$reg is not a 64-bit register"); |
447
|
63
|
|
|
|
|
181
|
$self->_append_possible_unknown('_encode_mov64_imm', [$reg, $immed], 1, 10); |
448
|
|
|
|
|
|
|
} |
449
|
|
|
|
|
|
|
sub _encode_mov64_imm { |
450
|
63
|
|
|
63
|
|
120
|
my ($self, $reg, $immed)= @_; |
451
|
17
|
|
|
17
|
|
29205
|
use integer; |
|
17
|
|
|
|
|
62
|
|
|
17
|
|
|
|
|
79
|
|
452
|
|
|
|
|
|
|
# If the number fits in 32-bits, encode as the classic instruction |
453
|
63
|
100
|
|
|
|
188
|
if (($immed >> 31 >> 1) == 0) { # ">> 32" is a no-op on 32-bit perl |
|
|
100
|
|
|
|
|
|
454
|
28
|
100
|
|
|
|
126
|
return $reg > 7? # need REX byte if extended register |
455
|
|
|
|
|
|
|
pack('C C L<', 0x41, 0xB8 + ($reg&7), $immed) |
456
|
|
|
|
|
|
|
: pack('C L<', 0xB8 + $reg, $immed); |
457
|
|
|
|
|
|
|
} |
458
|
|
|
|
|
|
|
# If the number can sign-extend from 32-bits, encode as 32-bit sign-extend |
459
|
|
|
|
|
|
|
elsif (($immed >> 31) == -1) { |
460
|
21
|
|
|
|
|
95
|
return pack('C C C l<', 0x48 | (($reg & 8) >> 3), 0xC7, 0xC0 + ($reg & 7), $immed); |
461
|
|
|
|
|
|
|
} |
462
|
|
|
|
|
|
|
# else encode as new 64-bit immediate |
463
|
|
|
|
|
|
|
else { |
464
|
14
|
|
|
|
|
66
|
return pack('C C Q<', 0x48 | (($reg & 8) >> 3), 0xB8 + ($reg & 7), $immed); |
465
|
|
|
|
|
|
|
} |
466
|
|
|
|
|
|
|
} |
467
|
|
|
|
|
|
|
sub mov32_reg_imm { |
468
|
57
|
|
|
57
|
0
|
125
|
my ($self, $reg, $immed)= @_; |
469
|
57
|
|
33
|
|
|
150
|
$reg= $regnum32{$reg} // croak("$reg is not a 32-bit register"); |
470
|
57
|
100
|
|
|
|
142
|
$self->{_buf} .= "\x41" if $reg > 7; |
471
|
57
|
|
|
|
|
159
|
$self->{_buf} .= pack('C' , 0xB8 | ($reg & 7)); |
472
|
57
|
|
|
57
|
|
248
|
$self->_append_possible_unknown(sub { pack('V', $_[1]) }, [$immed], 0, 4); |
|
57
|
|
|
|
|
167
|
|
473
|
|
|
|
|
|
|
} |
474
|
|
|
|
|
|
|
sub mov16_reg_imm { |
475
|
49
|
|
|
49
|
0
|
105
|
my ($self, $reg, $immed)= @_; |
476
|
49
|
|
33
|
|
|
136
|
$reg= $regnum16{$reg} // croak("$reg is not a 16-bit register"); |
477
|
49
|
|
|
|
|
98
|
$self->{_buf} .= "\x66"; |
478
|
49
|
100
|
|
|
|
103
|
$self->{_buf} .= "\x41" if $reg > 7; |
479
|
49
|
|
|
|
|
141
|
$self->{_buf} .= pack('C', 0xB8 | ($reg & 7)); |
480
|
49
|
|
|
49
|
|
207
|
$self->_append_possible_unknown(sub { pack('v', $_[1]) }, [$immed], 0, 2); |
|
49
|
|
|
|
|
132
|
|
481
|
|
|
|
|
|
|
} |
482
|
|
|
|
|
|
|
sub mov8_reg_imm { |
483
|
55
|
|
|
55
|
0
|
124
|
my ($self, $reg, $immed)= @_; |
484
|
55
|
|
|
|
|
108
|
$reg= $regnum8{$reg}; |
485
|
|
|
|
|
|
|
# Special case for the high-byte registers available without the REX prefix |
486
|
55
|
100
|
|
|
|
122
|
if (!defined $reg) { |
487
|
20
|
|
33
|
|
|
59
|
$reg= $regnum8_high{$_[1]} // croak("$_[1] is not a 8-bit register"); |
488
|
|
|
|
|
|
|
} else { |
489
|
35
|
100
|
|
|
|
123
|
$self->{_buf} .= pack('C', 0x40|(($reg&8)>>3)) if $reg > 3; |
490
|
|
|
|
|
|
|
} |
491
|
55
|
|
|
|
|
166
|
$self->{_buf} .= pack('C', 0xB0 | ($reg & 7)); |
492
|
55
|
|
|
55
|
|
233
|
$self->_append_possible_unknown(sub { pack('C', $_[1]&0xFF) }, [$immed], 0, 1); |
|
55
|
|
|
|
|
163
|
|
493
|
|
|
|
|
|
|
} |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
|
496
|
63
|
|
|
63
|
0
|
148
|
sub mov64_mem_imm { $_[0]->_append_op64_const_to_mem(0xC7, 0, $_[2], $_[1]) } |
497
|
63
|
|
|
63
|
0
|
156
|
sub mov32_mem_imm { $_[0]->_append_op32_const_to_mem(0xC7, 0, $_[2], $_[1]) } |
498
|
63
|
|
|
63
|
0
|
184
|
sub mov16_mem_imm { $_[0]->_append_op16_const_to_mem(0xC7, 0, $_[2], $_[1]) } |
499
|
63
|
|
|
63
|
0
|
347
|
sub mov8_mem_imm { $_[0]->_append_op8_const_to_mem (0xC6, 0, $_[2], $_[1]) } |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
|
502
|
3
|
|
|
3
|
1
|
11
|
sub lea { splice(@_,1,0,'lea'); &_autodetect_signature_dst_src } |
|
3
|
|
|
|
|
7
|
|
503
|
|
|
|
|
|
|
|
504
|
0
|
|
|
0
|
1
|
0
|
sub lea16_reg_reg { $_[0]->_append_op16_reg_reg( 0x8D, $_[1], $_[2]) } |
505
|
441
|
|
|
441
|
1
|
1181
|
sub lea16_reg_mem { $_[0]->_append_op16_reg_mem(0, 0x8D, $_[1], $_[2]) } |
506
|
1
|
|
|
1
|
1
|
8
|
sub lea32_reg_reg { $_[0]->_append_op32_reg_reg( 0x8D, $_[1], $_[2]) } |
507
|
443
|
|
|
443
|
1
|
1091
|
sub lea32_reg_mem { $_[0]->_append_op32_reg_mem(0, 0x8D, $_[1], $_[2]) } |
508
|
0
|
|
|
0
|
1
|
0
|
sub lea64_reg_reg { $_[0]->_append_op64_reg_reg( 0x8D, $_[1], $_[2]) } |
509
|
441
|
|
|
441
|
1
|
1125
|
sub lea64_reg_mem { $_[0]->_append_op64_reg_mem(8, 0x8D, $_[1], $_[2]) } |
510
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
|
512
|
0
|
|
|
0
|
1
|
0
|
sub add { splice(@_,1,0,'add'); &_autodetect_signature_dst_src } |
|
0
|
|
|
|
|
0
|
|
513
|
|
|
|
|
|
|
|
514
|
49
|
|
|
49
|
0
|
132
|
sub add64_reg_reg { $_[0]->_append_op64_reg_reg(0x01, $_[2], $_[1]) } |
515
|
49
|
|
|
49
|
0
|
113
|
sub add32_reg_reg { $_[0]->_append_op32_reg_reg(0x01, $_[2], $_[1]) } |
516
|
49
|
|
|
49
|
0
|
114
|
sub add16_reg_reg { $_[0]->_append_op16_reg_reg(0x01, $_[2], $_[1]) } |
517
|
49
|
|
|
49
|
0
|
126
|
sub add8_reg_reg { $_[0]->_append_op8_reg_reg (0x00, $_[2], $_[1]) } |
518
|
|
|
|
|
|
|
|
519
|
441
|
|
|
441
|
0
|
1489
|
sub add64_reg_mem { $_[0]->_append_op64_reg_mem(8, 0x03, $_[1], $_[2]); } |
520
|
441
|
|
|
441
|
0
|
1042
|
sub add32_reg_mem { $_[0]->_append_op32_reg_mem(0, 0x03, $_[1], $_[2]); } |
521
|
441
|
|
|
441
|
0
|
1109
|
sub add16_reg_mem { $_[0]->_append_op16_reg_mem(0, 0x03, $_[1], $_[2]); } |
522
|
441
|
|
|
441
|
0
|
1118
|
sub add8_reg_mem { $_[0]->_append_op8_reg_mem (0, 0x02, $_[1], $_[2]); } |
523
|
|
|
|
|
|
|
|
524
|
441
|
|
|
441
|
0
|
1117
|
sub add64_mem_reg { $_[0]->_append_op64_reg_mem(8, 0x01, $_[2], $_[1]); } |
525
|
441
|
|
|
441
|
0
|
1046
|
sub add32_mem_reg { $_[0]->_append_op32_reg_mem(0, 0x01, $_[2], $_[1]); } |
526
|
441
|
|
|
441
|
0
|
1105
|
sub add16_mem_reg { $_[0]->_append_op16_reg_mem(0, 0x01, $_[2], $_[1]); } |
527
|
441
|
|
|
441
|
0
|
1140
|
sub add8_mem_reg { $_[0]->_append_op8_reg_mem (0, 0x00, $_[2], $_[1]); } |
528
|
|
|
|
|
|
|
|
529
|
56
|
|
|
56
|
0
|
144
|
sub add64_reg_imm { shift->_append_mathop64_const(0x05, 0x83, 0x81, 0, @_) } |
530
|
56
|
|
|
56
|
0
|
127
|
sub add32_reg_imm { shift->_append_mathop32_const(0x05, 0x83, 0x81, 0, @_) } |
531
|
49
|
|
|
49
|
0
|
130
|
sub add16_reg_imm { shift->_append_mathop16_const(0x05, 0x83, 0x81, 0, @_) } |
532
|
35
|
|
|
35
|
0
|
119
|
sub add8_reg_imm { shift->_append_mathop8_const (0x04, 0x80, 0, @_) } |
533
|
|
|
|
|
|
|
|
534
|
504
|
|
|
504
|
0
|
1270
|
sub add64_mem_imm { $_[0]->_append_mathop64_const_to_mem(0x83, 0x81, 0, $_[2], $_[1]) } |
535
|
504
|
|
|
504
|
0
|
1260
|
sub add32_mem_imm { $_[0]->_append_mathop32_const_to_mem(0x83, 0x81, 0, $_[2], $_[1]) } |
536
|
441
|
|
|
441
|
0
|
1108
|
sub add16_mem_imm { $_[0]->_append_mathop16_const_to_mem(0x83, 0x81, 0, $_[2], $_[1]) } |
537
|
315
|
|
|
315
|
0
|
783
|
sub add8_mem_imm { $_[0]->_append_mathop8_const_to_mem (0x80, 0, $_[2], $_[1]) } |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
|
540
|
0
|
|
|
0
|
1
|
0
|
sub addcarry { splice(@_,1,0,'addcarry'); &_autodetect_signature_dst_src } |
|
0
|
|
|
|
|
0
|
|
541
|
|
|
|
|
|
|
*adc= *addcarry; |
542
|
|
|
|
|
|
|
|
543
|
49
|
|
|
49
|
0
|
130
|
sub addcarry64_reg_reg { $_[0]->_append_op64_reg_reg(0x11, $_[2], $_[1]) } |
544
|
49
|
|
|
49
|
0
|
124
|
sub addcarry32_reg_reg { $_[0]->_append_op32_reg_reg(0x11, $_[2], $_[1]) } |
545
|
49
|
|
|
49
|
0
|
112
|
sub addcarry16_reg_reg { $_[0]->_append_op16_reg_reg(0x11, $_[2], $_[1]) } |
546
|
49
|
|
|
49
|
0
|
122
|
sub addcarry8_reg_reg { $_[0]->_append_op8_reg_reg (0x10, $_[2], $_[1]) } |
547
|
|
|
|
|
|
|
|
548
|
441
|
|
|
441
|
0
|
1099
|
sub addcarry64_reg_mem { $_[0]->_append_op64_reg_mem(8, 0x13, $_[1], $_[2]); } |
549
|
441
|
|
|
441
|
0
|
1063
|
sub addcarry32_reg_mem { $_[0]->_append_op32_reg_mem(0, 0x13, $_[1], $_[2]); } |
550
|
441
|
|
|
441
|
0
|
1122
|
sub addcarry16_reg_mem { $_[0]->_append_op16_reg_mem(0, 0x13, $_[1], $_[2]); } |
551
|
441
|
|
|
441
|
0
|
1097
|
sub addcarry8_reg_mem { $_[0]->_append_op8_reg_mem (0, 0x12, $_[1], $_[2]); } |
552
|
|
|
|
|
|
|
|
553
|
441
|
|
|
441
|
0
|
1070
|
sub addcarry64_mem_reg { $_[0]->_append_op64_reg_mem(8, 0x11, $_[2], $_[1]); } |
554
|
441
|
|
|
441
|
0
|
1099
|
sub addcarry32_mem_reg { $_[0]->_append_op32_reg_mem(0, 0x11, $_[2], $_[1]); } |
555
|
441
|
|
|
441
|
0
|
1089
|
sub addcarry16_mem_reg { $_[0]->_append_op16_reg_mem(0, 0x11, $_[2], $_[1]); } |
556
|
441
|
|
|
441
|
0
|
1107
|
sub addcarry8_mem_reg { $_[0]->_append_op8_reg_mem (0, 0x10, $_[2], $_[1]); } |
557
|
|
|
|
|
|
|
|
558
|
56
|
|
|
56
|
0
|
177
|
sub addcarry64_reg_imm { shift->_append_mathop64_const(0x15, 0x83, 0x81, 2, @_) } |
559
|
56
|
|
|
56
|
0
|
129
|
sub addcarry32_reg_imm { shift->_append_mathop32_const(0x15, 0x83, 0x81, 2, @_) } |
560
|
49
|
|
|
49
|
0
|
123
|
sub addcarry16_reg_imm { shift->_append_mathop16_const(0x15, 0x83, 0x81, 2, @_) } |
561
|
35
|
|
|
35
|
0
|
84
|
sub addcarry8_reg_imm { shift->_append_mathop8_const (0x14, 0x80, 2, @_) } |
562
|
|
|
|
|
|
|
|
563
|
504
|
|
|
504
|
0
|
1348
|
sub addcarry64_mem_imm { $_[0]->_append_mathop64_const_to_mem(0x83, 0x81, 2, $_[2], $_[1]) } |
564
|
504
|
|
|
504
|
0
|
1291
|
sub addcarry32_mem_imm { $_[0]->_append_mathop32_const_to_mem(0x83, 0x81, 2, $_[2], $_[1]) } |
565
|
441
|
|
|
441
|
0
|
1243
|
sub addcarry16_mem_imm { $_[0]->_append_mathop16_const_to_mem(0x83, 0x81, 2, $_[2], $_[1]) } |
566
|
315
|
|
|
315
|
0
|
790
|
sub addcarry8_mem_imm { $_[0]->_append_mathop8_const_to_mem (0x80, 2, $_[2], $_[1]) } |
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
|
569
|
0
|
|
|
0
|
1
|
0
|
sub sub { splice(@_,1,0,'sub'); &_autodetect_signature_dst_src } |
|
0
|
|
|
|
|
0
|
|
570
|
|
|
|
|
|
|
|
571
|
49
|
|
|
49
|
0
|
120
|
sub sub64_reg_reg { $_[0]->_append_op64_reg_reg(0x29, $_[2], $_[1]) } |
572
|
49
|
|
|
49
|
0
|
107
|
sub sub32_reg_reg { $_[0]->_append_op32_reg_reg(0x29, $_[2], $_[1]) } |
573
|
49
|
|
|
49
|
0
|
118
|
sub sub16_reg_reg { $_[0]->_append_op16_reg_reg(0x29, $_[2], $_[1]) } |
574
|
49
|
|
|
49
|
0
|
123
|
sub sub8_reg_reg { $_[0]->_append_op8_reg_reg (0x28, $_[2], $_[1]) } |
575
|
|
|
|
|
|
|
|
576
|
441
|
|
|
441
|
0
|
1134
|
sub sub64_reg_mem { $_[0]->_append_op64_reg_mem(8, 0x2B, $_[1], $_[2]); } |
577
|
441
|
|
|
441
|
0
|
1061
|
sub sub32_reg_mem { $_[0]->_append_op32_reg_mem(0, 0x2B, $_[1], $_[2]); } |
578
|
441
|
|
|
441
|
0
|
1080
|
sub sub16_reg_mem { $_[0]->_append_op16_reg_mem(0, 0x2B, $_[1], $_[2]); } |
579
|
441
|
|
|
441
|
0
|
1084
|
sub sub8_reg_mem { $_[0]->_append_op8_reg_mem (0, 0x2A, $_[1], $_[2]); } |
580
|
|
|
|
|
|
|
|
581
|
441
|
|
|
441
|
0
|
1122
|
sub sub64_mem_reg { $_[0]->_append_op64_reg_mem(8, 0x29, $_[2], $_[1]); } |
582
|
441
|
|
|
441
|
0
|
1107
|
sub sub32_mem_reg { $_[0]->_append_op32_reg_mem(0, 0x29, $_[2], $_[1]); } |
583
|
441
|
|
|
441
|
0
|
1098
|
sub sub16_mem_reg { $_[0]->_append_op16_reg_mem(0, 0x29, $_[2], $_[1]); } |
584
|
441
|
|
|
441
|
0
|
1121
|
sub sub8_mem_reg { $_[0]->_append_op8_reg_mem (0, 0x28, $_[2], $_[1]); } |
585
|
|
|
|
|
|
|
|
586
|
56
|
|
|
56
|
0
|
142
|
sub sub64_reg_imm { shift->_append_mathop64_const(0x2D, 0x83, 0x81, 5, @_) } |
587
|
56
|
|
|
56
|
0
|
141
|
sub sub32_reg_imm { shift->_append_mathop32_const(0x2D, 0x83, 0x81, 5, @_) } |
588
|
49
|
|
|
49
|
0
|
123
|
sub sub16_reg_imm { shift->_append_mathop16_const(0x2D, 0x83, 0x81, 5, @_) } |
589
|
35
|
|
|
35
|
0
|
86
|
sub sub8_reg_imm { shift->_append_mathop8_const (0x2C, 0x80, 5, @_) } |
590
|
|
|
|
|
|
|
|
591
|
504
|
|
|
504
|
0
|
1431
|
sub sub64_mem_imm { $_[0]->_append_mathop64_const_to_mem(0x83, 0x81, 5, $_[2], $_[1]) } |
592
|
504
|
|
|
504
|
0
|
1353
|
sub sub32_mem_imm { $_[0]->_append_mathop32_const_to_mem(0x83, 0x81, 5, $_[2], $_[1]) } |
593
|
441
|
|
|
441
|
0
|
1173
|
sub sub16_mem_imm { $_[0]->_append_mathop16_const_to_mem(0x83, 0x81, 5, $_[2], $_[1]) } |
594
|
315
|
|
|
315
|
0
|
781
|
sub sub8_mem_imm { $_[0]->_append_mathop8_const_to_mem (0x80, 5, $_[2], $_[1]) } |
595
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
|
597
|
0
|
|
|
0
|
1
|
0
|
sub and { splice(@_,1,0,'and'); &_autodetect_signature_dst_src } |
|
0
|
|
|
|
|
0
|
|
598
|
|
|
|
|
|
|
|
599
|
49
|
|
|
49
|
0
|
121
|
sub and64_reg_reg { $_[0]->_append_op64_reg_reg(0x21, $_[2], $_[1]) } |
600
|
49
|
|
|
49
|
0
|
114
|
sub and32_reg_reg { $_[0]->_append_op32_reg_reg(0x21, $_[2], $_[1]) } |
601
|
49
|
|
|
49
|
0
|
107
|
sub and16_reg_reg { $_[0]->_append_op16_reg_reg(0x21, $_[2], $_[1]) } |
602
|
49
|
|
|
49
|
0
|
106
|
sub and8_reg_reg { $_[0]->_append_op8_reg_reg (0x20, $_[2], $_[1]) } |
603
|
|
|
|
|
|
|
|
604
|
441
|
|
|
441
|
0
|
1049
|
sub and64_reg_mem { $_[0]->_append_op64_reg_mem(8, 0x23, $_[1], $_[2]); } |
605
|
441
|
|
|
441
|
0
|
1130
|
sub and32_reg_mem { $_[0]->_append_op32_reg_mem(0, 0x23, $_[1], $_[2]); } |
606
|
441
|
|
|
441
|
0
|
1218
|
sub and16_reg_mem { $_[0]->_append_op16_reg_mem(0, 0x23, $_[1], $_[2]); } |
607
|
441
|
|
|
441
|
0
|
1168
|
sub and8_reg_mem { $_[0]->_append_op8_reg_mem (0, 0x22, $_[1], $_[2]); } |
608
|
|
|
|
|
|
|
|
609
|
441
|
|
|
441
|
0
|
1097
|
sub and64_mem_reg { $_[0]->_append_op64_reg_mem(8, 0x21, $_[2], $_[1]); } |
610
|
441
|
|
|
441
|
0
|
1125
|
sub and32_mem_reg { $_[0]->_append_op32_reg_mem(0, 0x21, $_[2], $_[1]); } |
611
|
441
|
|
|
441
|
0
|
1149
|
sub and16_mem_reg { $_[0]->_append_op16_reg_mem(0, 0x21, $_[2], $_[1]); } |
612
|
441
|
|
|
441
|
0
|
1525
|
sub and8_mem_reg { $_[0]->_append_op8_reg_mem (0, 0x20, $_[2], $_[1]); } |
613
|
|
|
|
|
|
|
|
614
|
56
|
|
|
56
|
0
|
173
|
sub and64_reg_imm { shift->_append_mathop64_const(0x25, 0x83, 0x81, 4, @_) } |
615
|
56
|
|
|
56
|
0
|
141
|
sub and32_reg_imm { shift->_append_mathop32_const(0x25, 0x83, 0x81, 4, @_) } |
616
|
49
|
|
|
49
|
0
|
136
|
sub and16_reg_imm { shift->_append_mathop16_const(0x25, 0x83, 0x81, 4, @_) } |
617
|
35
|
|
|
35
|
0
|
89
|
sub and8_reg_imm { shift->_append_mathop8_const (0x24, 0x80, 4, @_) } |
618
|
|
|
|
|
|
|
|
619
|
504
|
|
|
504
|
0
|
1353
|
sub and64_mem_imm { $_[0]->_append_mathop64_const_to_mem(0x83, 0x81, 4, $_[2], $_[1]) } |
620
|
504
|
|
|
504
|
0
|
1376
|
sub and32_mem_imm { $_[0]->_append_mathop32_const_to_mem(0x83, 0x81, 4, $_[2], $_[1]) } |
621
|
441
|
|
|
441
|
0
|
1218
|
sub and16_mem_imm { $_[0]->_append_mathop16_const_to_mem(0x83, 0x81, 4, $_[2], $_[1]) } |
622
|
315
|
|
|
315
|
0
|
819
|
sub and8_mem_imm { $_[0]->_append_mathop8_const_to_mem (0x80, 4, $_[2], $_[1]) } |
623
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
|
625
|
0
|
|
|
0
|
1
|
0
|
sub or { splice(@_,1,0,'or'); &_autodetect_signature_dst_src } |
|
0
|
|
|
|
|
0
|
|
626
|
|
|
|
|
|
|
|
627
|
49
|
|
|
49
|
0
|
112
|
sub or64_reg_reg { $_[0]->_append_op64_reg_reg(0x09, $_[2], $_[1]) } |
628
|
49
|
|
|
49
|
0
|
115
|
sub or32_reg_reg { $_[0]->_append_op32_reg_reg(0x09, $_[2], $_[1]) } |
629
|
49
|
|
|
49
|
0
|
126
|
sub or16_reg_reg { $_[0]->_append_op16_reg_reg(0x09, $_[2], $_[1]) } |
630
|
49
|
|
|
49
|
0
|
128
|
sub or8_reg_reg { $_[0]->_append_op8_reg_reg (0x08, $_[2], $_[1]) } |
631
|
|
|
|
|
|
|
|
632
|
441
|
|
|
441
|
0
|
1154
|
sub or64_reg_mem { $_[0]->_append_op64_reg_mem(8, 0x0B, $_[1], $_[2]); } |
633
|
441
|
|
|
441
|
0
|
1181
|
sub or32_reg_mem { $_[0]->_append_op32_reg_mem(0, 0x0B, $_[1], $_[2]); } |
634
|
441
|
|
|
441
|
0
|
1107
|
sub or16_reg_mem { $_[0]->_append_op16_reg_mem(0, 0x0B, $_[1], $_[2]); } |
635
|
441
|
|
|
441
|
0
|
1199
|
sub or8_reg_mem { $_[0]->_append_op8_reg_mem (0, 0x0A, $_[1], $_[2]); } |
636
|
|
|
|
|
|
|
|
637
|
441
|
|
|
441
|
0
|
1115
|
sub or64_mem_reg { $_[0]->_append_op64_reg_mem(8, 0x09, $_[2], $_[1]); } |
638
|
441
|
|
|
441
|
0
|
1254
|
sub or32_mem_reg { $_[0]->_append_op32_reg_mem(0, 0x09, $_[2], $_[1]); } |
639
|
441
|
|
|
441
|
0
|
1127
|
sub or16_mem_reg { $_[0]->_append_op16_reg_mem(0, 0x09, $_[2], $_[1]); } |
640
|
441
|
|
|
441
|
0
|
1218
|
sub or8_mem_reg { $_[0]->_append_op8_reg_mem (0, 0x08, $_[2], $_[1]); } |
641
|
|
|
|
|
|
|
|
642
|
56
|
|
|
56
|
0
|
149
|
sub or64_reg_imm { shift->_append_mathop64_const(0x0D, 0x83, 0x81, 1, @_) } |
643
|
56
|
|
|
56
|
0
|
147
|
sub or32_reg_imm { shift->_append_mathop32_const(0x0D, 0x83, 0x81, 1, @_) } |
644
|
49
|
|
|
49
|
0
|
130
|
sub or16_reg_imm { shift->_append_mathop16_const(0x0D, 0x83, 0x81, 1, @_) } |
645
|
35
|
|
|
35
|
0
|
96
|
sub or8_reg_imm { shift->_append_mathop8_const (0x0C, 0x80, 1, @_) } |
646
|
|
|
|
|
|
|
|
647
|
504
|
|
|
504
|
0
|
1314
|
sub or64_mem_imm { $_[0]->_append_mathop64_const_to_mem(0x83, 0x81, 1, $_[2], $_[1]) } |
648
|
504
|
|
|
504
|
0
|
1418
|
sub or32_mem_imm { $_[0]->_append_mathop32_const_to_mem(0x83, 0x81, 1, $_[2], $_[1]) } |
649
|
441
|
|
|
441
|
0
|
1191
|
sub or16_mem_imm { $_[0]->_append_mathop16_const_to_mem(0x83, 0x81, 1, $_[2], $_[1]) } |
650
|
315
|
|
|
315
|
0
|
807
|
sub or8_mem_imm { $_[0]->_append_mathop8_const_to_mem (0x80, 1, $_[2], $_[1]) } |
651
|
|
|
|
|
|
|
|
652
|
|
|
|
|
|
|
|
653
|
0
|
|
|
0
|
1
|
0
|
sub xor { splice(@_,1,0,'xor'); &_autodetect_signature_dst_src } |
|
0
|
|
|
|
|
0
|
|
654
|
|
|
|
|
|
|
|
655
|
49
|
|
|
49
|
0
|
130
|
sub xor64_reg_reg { $_[0]->_append_op64_reg_reg(0x31, $_[2], $_[1]) } |
656
|
49
|
|
|
49
|
0
|
117
|
sub xor32_reg_reg { $_[0]->_append_op32_reg_reg(0x31, $_[2], $_[1]) } |
657
|
49
|
|
|
49
|
0
|
124
|
sub xor16_reg_reg { $_[0]->_append_op16_reg_reg(0x31, $_[2], $_[1]) } |
658
|
49
|
|
|
49
|
0
|
122
|
sub xor8_reg_reg { $_[0]->_append_op8_reg_reg (0x30, $_[2], $_[1]) } |
659
|
|
|
|
|
|
|
|
660
|
441
|
|
|
441
|
0
|
1046
|
sub xor64_reg_mem { $_[0]->_append_op64_reg_mem(8, 0x33, $_[1], $_[2]); } |
661
|
441
|
|
|
441
|
0
|
1099
|
sub xor32_reg_mem { $_[0]->_append_op32_reg_mem(0, 0x33, $_[1], $_[2]); } |
662
|
441
|
|
|
441
|
0
|
1111
|
sub xor16_reg_mem { $_[0]->_append_op16_reg_mem(0, 0x33, $_[1], $_[2]); } |
663
|
441
|
|
|
441
|
0
|
1115
|
sub xor8_reg_mem { $_[0]->_append_op8_reg_mem (0, 0x32, $_[1], $_[2]); } |
664
|
|
|
|
|
|
|
|
665
|
441
|
|
|
441
|
0
|
1060
|
sub xor64_mem_reg { $_[0]->_append_op64_reg_mem(8, 0x31, $_[2], $_[1]); } |
666
|
441
|
|
|
441
|
0
|
1097
|
sub xor32_mem_reg { $_[0]->_append_op32_reg_mem(0, 0x31, $_[2], $_[1]); } |
667
|
441
|
|
|
441
|
0
|
1113
|
sub xor16_mem_reg { $_[0]->_append_op16_reg_mem(0, 0x31, $_[2], $_[1]); } |
668
|
441
|
|
|
441
|
0
|
1203
|
sub xor8_mem_reg { $_[0]->_append_op8_reg_mem (0, 0x30, $_[2], $_[1]); } |
669
|
|
|
|
|
|
|
|
670
|
56
|
|
|
56
|
0
|
132
|
sub xor64_reg_imm { shift->_append_mathop64_const(0x35, 0x83, 0x81, 6, @_) } |
671
|
56
|
|
|
56
|
0
|
186
|
sub xor32_reg_imm { shift->_append_mathop32_const(0x35, 0x83, 0x81, 6, @_) } |
672
|
49
|
|
|
49
|
0
|
143
|
sub xor16_reg_imm { shift->_append_mathop16_const(0x35, 0x83, 0x81, 6, @_) } |
673
|
35
|
|
|
35
|
0
|
90
|
sub xor8_reg_imm { shift->_append_mathop8_const (0x34, 0x80, 6, @_) } |
674
|
|
|
|
|
|
|
|
675
|
504
|
|
|
504
|
0
|
1429
|
sub xor64_mem_imm { $_[0]->_append_mathop64_const_to_mem(0x83, 0x81, 6, $_[2], $_[1]) } |
676
|
504
|
|
|
504
|
0
|
1320
|
sub xor32_mem_imm { $_[0]->_append_mathop32_const_to_mem(0x83, 0x81, 6, $_[2], $_[1]) } |
677
|
441
|
|
|
441
|
0
|
1147
|
sub xor16_mem_imm { $_[0]->_append_mathop16_const_to_mem(0x83, 0x81, 6, $_[2], $_[1]) } |
678
|
315
|
|
|
315
|
0
|
771
|
sub xor8_mem_imm { $_[0]->_append_mathop8_const_to_mem (0x80, 6, $_[2], $_[1]) } |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
|
681
|
0
|
|
|
0
|
1
|
0
|
sub shl { splice(@_,1,0,'shl'); &_autodetect_signature_dst_src } |
|
0
|
|
|
|
|
0
|
|
682
|
|
|
|
|
|
|
|
683
|
77
|
|
|
77
|
0
|
190
|
sub shl64_reg_imm { $_[0]->_append_shiftop_reg_imm(64, 0xD1, 0xC1, 4, $_[1], $_[2]) } |
684
|
63
|
|
|
63
|
0
|
220
|
sub shl32_reg_imm { $_[0]->_append_shiftop_reg_imm(32, 0xD1, 0xC1, 4, $_[1], $_[2]) } |
685
|
49
|
|
|
49
|
0
|
119
|
sub shl16_reg_imm { $_[0]->_append_shiftop_reg_imm(16, 0xD1, 0xC1, 4, $_[1], $_[2]) } |
686
|
55
|
|
|
55
|
0
|
130
|
sub shl8_reg_imm { $_[0]->_append_shiftop_reg_imm( 8, 0xD0, 0xC0, 4, $_[1], $_[2]) } |
687
|
|
|
|
|
|
|
|
688
|
7
|
|
|
7
|
0
|
24
|
sub shl64_reg_cl { $_[0]->_append_op64_reg_reg(0xD3, 4, $_[1]) } |
689
|
7
|
|
|
7
|
0
|
48
|
sub shl32_reg_cl { $_[0]->_append_op32_reg_reg(0xD3, 4, $_[1]) } |
690
|
7
|
|
|
7
|
0
|
23
|
sub shl16_reg_cl { $_[0]->_append_op16_reg_reg(0xD3, 4, $_[1]) } |
691
|
11
|
|
|
11
|
0
|
35
|
sub shl8_reg_cl { $_[0]->_append_op8_opreg_reg(0xD2, 4, $_[1]) } |
692
|
|
|
|
|
|
|
|
693
|
315
|
|
|
315
|
0
|
806
|
sub shl64_mem_imm { $_[0]->_append_shiftop_mem_imm(64, 0xD1, 0xC1, 4, $_[1], $_[2]) } |
694
|
315
|
|
|
315
|
0
|
828
|
sub shl32_mem_imm { $_[0]->_append_shiftop_mem_imm(32, 0xD1, 0xC1, 4, $_[1], $_[2]) } |
695
|
315
|
|
|
315
|
0
|
858
|
sub shl16_mem_imm { $_[0]->_append_shiftop_mem_imm(16, 0xD1, 0xC1, 4, $_[1], $_[2]) } |
696
|
315
|
|
|
315
|
0
|
877
|
sub shl8_mem_imm { $_[0]->_append_shiftop_mem_imm( 8, 0xD0, 0xC0, 4, $_[1], $_[2]) } |
697
|
|
|
|
|
|
|
|
698
|
63
|
|
|
63
|
0
|
159
|
sub shl64_mem_cl { $_[0]->_append_op64_reg_mem(8, 0xD3, 4, $_[1]) } |
699
|
63
|
|
|
63
|
0
|
527
|
sub shl32_mem_cl { $_[0]->_append_op32_reg_mem(0, 0xD3, 4, $_[1]) } |
700
|
63
|
|
|
63
|
0
|
165
|
sub shl16_mem_cl { $_[0]->_append_op16_reg_mem(0, 0xD3, 4, $_[1]) } |
701
|
63
|
|
|
63
|
0
|
165
|
sub shl8_mem_cl { $_[0]->_append_op8_opreg_mem(0, 0xD2, 4, $_[1]) } |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
|
704
|
0
|
|
|
0
|
1
|
0
|
sub shr { splice(@_,1,0,'shr'); &_autodetect_signature_dst_src } |
|
0
|
|
|
|
|
0
|
|
705
|
|
|
|
|
|
|
|
706
|
77
|
|
|
77
|
0
|
178
|
sub shr64_reg_imm { $_[0]->_append_shiftop_reg_imm(64, 0xD1, 0xC1, 5, $_[1], $_[2]) } |
707
|
63
|
|
|
63
|
0
|
156
|
sub shr32_reg_imm { $_[0]->_append_shiftop_reg_imm(32, 0xD1, 0xC1, 5, $_[1], $_[2]) } |
708
|
49
|
|
|
49
|
0
|
114
|
sub shr16_reg_imm { $_[0]->_append_shiftop_reg_imm(16, 0xD1, 0xC1, 5, $_[1], $_[2]) } |
709
|
55
|
|
|
55
|
0
|
134
|
sub shr8_reg_imm { $_[0]->_append_shiftop_reg_imm( 8, 0xD0, 0xC0, 5, $_[1], $_[2]) } |
710
|
|
|
|
|
|
|
|
711
|
7
|
|
|
7
|
0
|
23
|
sub shr64_reg_cl { $_[0]->_append_op64_reg_reg(0xD3, 5, $_[1]) } |
712
|
7
|
|
|
7
|
0
|
21
|
sub shr32_reg_cl { $_[0]->_append_op32_reg_reg(0xD3, 5, $_[1]) } |
713
|
7
|
|
|
7
|
0
|
27
|
sub shr16_reg_cl { $_[0]->_append_op16_reg_reg(0xD3, 5, $_[1]) } |
714
|
11
|
|
|
11
|
0
|
31
|
sub shr8_reg_cl { $_[0]->_append_op8_opreg_reg(0xD2, 5, $_[1]) } |
715
|
|
|
|
|
|
|
|
716
|
315
|
|
|
315
|
0
|
861
|
sub shr64_mem_imm { $_[0]->_append_shiftop_mem_imm(64, 0xD1, 0xC1, 5, $_[1], $_[2]) } |
717
|
315
|
|
|
315
|
0
|
915
|
sub shr32_mem_imm { $_[0]->_append_shiftop_mem_imm(32, 0xD1, 0xC1, 5, $_[1], $_[2]) } |
718
|
315
|
|
|
315
|
0
|
867
|
sub shr16_mem_imm { $_[0]->_append_shiftop_mem_imm(16, 0xD1, 0xC1, 5, $_[1], $_[2]) } |
719
|
315
|
|
|
315
|
0
|
890
|
sub shr8_mem_imm { $_[0]->_append_shiftop_mem_imm( 8, 0xD0, 0xC0, 5, $_[1], $_[2]) } |
720
|
|
|
|
|
|
|
|
721
|
63
|
|
|
63
|
0
|
179
|
sub shr64_mem_cl { $_[0]->_append_op64_reg_mem(8, 0xD3, 5, $_[1]) } |
722
|
63
|
|
|
63
|
0
|
163
|
sub shr32_mem_cl { $_[0]->_append_op32_reg_mem(0, 0xD3, 5, $_[1]) } |
723
|
63
|
|
|
63
|
0
|
156
|
sub shr16_mem_cl { $_[0]->_append_op16_reg_mem(0, 0xD3, 5, $_[1]) } |
724
|
63
|
|
|
63
|
0
|
178
|
sub shr8_mem_cl { $_[0]->_append_op8_opreg_mem(0, 0xD2, 5, $_[1]) } |
725
|
|
|
|
|
|
|
|
726
|
|
|
|
|
|
|
|
727
|
0
|
|
|
0
|
1
|
0
|
sub sar { splice(@_,1,0,'sar'); &_autodetect_signature_dst_src } |
|
0
|
|
|
|
|
0
|
|
728
|
|
|
|
|
|
|
|
729
|
77
|
|
|
77
|
0
|
190
|
sub sar64_reg_imm { $_[0]->_append_shiftop_reg_imm(64, 0xD1, 0xC1, 7, $_[1], $_[2]) } |
730
|
63
|
|
|
63
|
0
|
155
|
sub sar32_reg_imm { $_[0]->_append_shiftop_reg_imm(32, 0xD1, 0xC1, 7, $_[1], $_[2]) } |
731
|
49
|
|
|
49
|
0
|
121
|
sub sar16_reg_imm { $_[0]->_append_shiftop_reg_imm(16, 0xD1, 0xC1, 7, $_[1], $_[2]) } |
732
|
55
|
|
|
55
|
0
|
132
|
sub sar8_reg_imm { $_[0]->_append_shiftop_reg_imm( 8, 0xD0, 0xC0, 7, $_[1], $_[2]) } |
733
|
|
|
|
|
|
|
|
734
|
7
|
|
|
7
|
0
|
20
|
sub sar64_reg_cl { $_[0]->_append_op64_reg_reg(0xD3, 7, $_[1]) } |
735
|
7
|
|
|
7
|
0
|
20
|
sub sar32_reg_cl { $_[0]->_append_op32_reg_reg(0xD3, 7, $_[1]) } |
736
|
7
|
|
|
7
|
0
|
20
|
sub sar16_reg_cl { $_[0]->_append_op16_reg_reg(0xD3, 7, $_[1]) } |
737
|
11
|
|
|
11
|
0
|
30
|
sub sar8_reg_cl { $_[0]->_append_op8_opreg_reg(0xD2, 7, $_[1]) } |
738
|
|
|
|
|
|
|
|
739
|
315
|
|
|
315
|
0
|
904
|
sub sar64_mem_imm { $_[0]->_append_shiftop_mem_imm(64, 0xD1, 0xC1, 7, $_[1], $_[2]) } |
740
|
315
|
|
|
315
|
0
|
853
|
sub sar32_mem_imm { $_[0]->_append_shiftop_mem_imm(32, 0xD1, 0xC1, 7, $_[1], $_[2]) } |
741
|
315
|
|
|
315
|
0
|
885
|
sub sar16_mem_imm { $_[0]->_append_shiftop_mem_imm(16, 0xD1, 0xC1, 7, $_[1], $_[2]) } |
742
|
315
|
|
|
315
|
0
|
876
|
sub sar8_mem_imm { $_[0]->_append_shiftop_mem_imm( 8, 0xD0, 0xC0, 7, $_[1], $_[2]) } |
743
|
|
|
|
|
|
|
|
744
|
63
|
|
|
63
|
0
|
154
|
sub sar64_mem_cl { $_[0]->_append_op64_reg_mem(8, 0xD3, 7, $_[1]) } |
745
|
63
|
|
|
63
|
0
|
163
|
sub sar32_mem_cl { $_[0]->_append_op32_reg_mem(0, 0xD3, 7, $_[1]) } |
746
|
63
|
|
|
63
|
0
|
158
|
sub sar16_mem_cl { $_[0]->_append_op16_reg_mem(0, 0xD3, 7, $_[1]) } |
747
|
63
|
|
|
63
|
0
|
169
|
sub sar8_mem_cl { $_[0]->_append_op8_opreg_mem(0, 0xD2, 7, $_[1]) } |
748
|
|
|
|
|
|
|
|
749
|
|
|
|
|
|
|
|
750
|
0
|
|
|
0
|
1
|
0
|
sub cmp { splice(@_,1,0,'cmp'); &_autodetect_signature_dst_src } |
|
0
|
|
|
|
|
0
|
|
751
|
|
|
|
|
|
|
|
752
|
49
|
|
|
49
|
0
|
113
|
sub cmp64_reg_reg { $_[0]->_append_op64_reg_reg(0x39, $_[2], $_[1]) } |
753
|
49
|
|
|
49
|
0
|
119
|
sub cmp32_reg_reg { $_[0]->_append_op32_reg_reg(0x39, $_[2], $_[1]) } |
754
|
49
|
|
|
49
|
0
|
122
|
sub cmp16_reg_reg { $_[0]->_append_op16_reg_reg(0x39, $_[2], $_[1]) } |
755
|
49
|
|
|
49
|
0
|
115
|
sub cmp8_reg_reg { $_[0]->_append_op8_reg_reg (0x38, $_[2], $_[1]) } |
756
|
|
|
|
|
|
|
|
757
|
441
|
|
|
441
|
0
|
1099
|
sub cmp64_reg_mem { $_[0]->_append_op64_reg_mem(8, 0x3B, $_[1], $_[2]); } |
758
|
441
|
|
|
441
|
0
|
1096
|
sub cmp32_reg_mem { $_[0]->_append_op32_reg_mem(0, 0x3B, $_[1], $_[2]); } |
759
|
441
|
|
|
441
|
0
|
1124
|
sub cmp16_reg_mem { $_[0]->_append_op16_reg_mem(0, 0x3B, $_[1], $_[2]); } |
760
|
441
|
|
|
441
|
0
|
1119
|
sub cmp8_reg_mem { $_[0]->_append_op8_reg_mem (0, 0x3A, $_[1], $_[2]); } |
761
|
|
|
|
|
|
|
|
762
|
0
|
|
|
0
|
0
|
0
|
sub cmp64_mem_reg { $_[0]->_append_op64_reg_mem(8, 0x39, $_[2], $_[1]); } |
763
|
0
|
|
|
0
|
0
|
0
|
sub cmp32_mem_reg { $_[0]->_append_op32_reg_mem(0, 0x39, $_[2], $_[1]); } |
764
|
0
|
|
|
0
|
0
|
0
|
sub cmp16_mem_reg { $_[0]->_append_op16_reg_mem(0, 0x39, $_[2], $_[1]); } |
765
|
0
|
|
|
0
|
0
|
0
|
sub cmp8_mem_reg { $_[0]->_append_op8_reg_mem (0, 0x38, $_[2], $_[1]); } |
766
|
|
|
|
|
|
|
|
767
|
56
|
|
|
56
|
0
|
144
|
sub cmp64_reg_imm { shift->_append_mathop64_const(0x3D, 0x83, 0x81, 7, @_) } |
768
|
56
|
|
|
56
|
0
|
142
|
sub cmp32_reg_imm { shift->_append_mathop32_const(0x3D, 0x83, 0x81, 7, @_) } |
769
|
49
|
|
|
49
|
0
|
133
|
sub cmp16_reg_imm { shift->_append_mathop16_const(0x3D, 0x83, 0x81, 7, @_) } |
770
|
35
|
|
|
35
|
0
|
89
|
sub cmp8_reg_imm { shift->_append_mathop8_const (0x3C, 0x80, 7, @_) } |
771
|
|
|
|
|
|
|
|
772
|
504
|
|
|
504
|
0
|
1389
|
sub cmp64_mem_imm { $_[0]->_append_mathop64_const_to_mem(0x83, 0x81, 7, $_[2], $_[1]) } |
773
|
504
|
|
|
504
|
0
|
1371
|
sub cmp32_mem_imm { $_[0]->_append_mathop32_const_to_mem(0x83, 0x81, 7, $_[2], $_[1]) } |
774
|
441
|
|
|
441
|
0
|
1175
|
sub cmp16_mem_imm { $_[0]->_append_mathop16_const_to_mem(0x83, 0x81, 7, $_[2], $_[1]) } |
775
|
315
|
|
|
315
|
0
|
793
|
sub cmp8_mem_imm { $_[0]->_append_mathop8_const_to_mem (0x80, 7, $_[2], $_[1]) } |
776
|
|
|
|
|
|
|
|
777
|
|
|
|
|
|
|
|
778
|
0
|
|
|
0
|
1
|
0
|
sub test { splice(@_,1,0,'test'); &_autodetect_signature_dst_src } |
|
0
|
|
|
|
|
0
|
|
779
|
|
|
|
|
|
|
|
780
|
49
|
|
|
49
|
0
|
112
|
sub test64_reg_reg { $_[0]->_append_op64_reg_reg(0x85, $_[2], $_[1]) } |
781
|
49
|
|
|
49
|
0
|
120
|
sub test32_reg_reg { $_[0]->_append_op32_reg_reg(0x85, $_[2], $_[1]) } |
782
|
49
|
|
|
49
|
0
|
115
|
sub test16_reg_reg { $_[0]->_append_op16_reg_reg(0x85, $_[2], $_[1]) } |
783
|
49
|
|
|
49
|
0
|
127
|
sub test8_reg_reg { $_[0]->_append_op8_reg_reg (0x84, $_[2], $_[1]) } |
784
|
|
|
|
|
|
|
|
785
|
441
|
|
|
441
|
0
|
1208
|
sub test64_reg_mem { $_[0]->_append_op64_reg_mem(8, 0x85, $_[1], $_[2]); } |
786
|
441
|
|
|
441
|
0
|
1135
|
sub test32_reg_mem { $_[0]->_append_op32_reg_mem(0, 0x85, $_[1], $_[2]); } |
787
|
441
|
|
|
441
|
0
|
1151
|
sub test16_reg_mem { $_[0]->_append_op16_reg_mem(0, 0x85, $_[1], $_[2]); } |
788
|
441
|
|
|
441
|
0
|
1216
|
sub test8_reg_mem { $_[0]->_append_op8_reg_mem (0, 0x84, $_[1], $_[2]); } |
789
|
|
|
|
|
|
|
|
790
|
56
|
|
|
56
|
0
|
169
|
sub test64_reg_imm { $_[0]->_append_mathop64_const(0xA9, undef, 0xF7, 0, $_[1], $_[2]) } |
791
|
56
|
|
|
56
|
0
|
136
|
sub test32_reg_imm { $_[0]->_append_mathop32_const(0xA9, undef, 0xF7, 0, $_[1], $_[2]) } |
792
|
49
|
|
|
49
|
0
|
168
|
sub test16_reg_imm { $_[0]->_append_mathop16_const(0xA9, undef, 0xF7, 0, $_[1], $_[2]) } |
793
|
35
|
|
|
35
|
0
|
93
|
sub test8_reg_imm { $_[0]->_append_mathop8_const (0xA8, 0xF6, 0, $_[1], $_[2]) } |
794
|
|
|
|
|
|
|
|
795
|
504
|
|
|
504
|
0
|
1408
|
sub test64_mem_imm { $_[0]->_append_mathop64_const_to_mem(undef, 0xF7, 0, $_[2], $_[1]) } |
796
|
504
|
|
|
504
|
0
|
1315
|
sub test32_mem_imm { $_[0]->_append_mathop32_const_to_mem(undef, 0xF7, 0, $_[2], $_[1]) } |
797
|
441
|
|
|
441
|
0
|
1125
|
sub test16_mem_imm { $_[0]->_append_mathop16_const_to_mem(undef, 0xF7, 0, $_[2], $_[1]) } |
798
|
315
|
|
|
315
|
0
|
759
|
sub test8_mem_imm { $_[0]->_append_mathop8_const_to_mem (0xF6, 0, $_[2], $_[1]) } |
799
|
|
|
|
|
|
|
|
800
|
|
|
|
|
|
|
|
801
|
0
|
|
|
0
|
1
|
0
|
sub dec { splice(@_,1,0,'dec'); &_autodetect_signature_1op; } |
|
0
|
|
|
|
|
0
|
|
802
|
|
|
|
|
|
|
|
803
|
7
|
|
|
7
|
0
|
19
|
sub dec64_reg { $_[0]->_append_op64_reg_reg(0xFF, 1, $_[1]) } |
804
|
7
|
|
|
7
|
0
|
19
|
sub dec32_reg { $_[0]->_append_op32_reg_reg(0xFF, 1, $_[1]) } |
805
|
7
|
|
|
7
|
0
|
18
|
sub dec16_reg { $_[0]->_append_op16_reg_reg(0xFF, 1, $_[1]) } |
806
|
7
|
|
|
7
|
0
|
25
|
sub dec8_reg { $_[0]->_append_op8_reg_reg (0xFE, 1, $_[1]) } |
807
|
|
|
|
|
|
|
|
808
|
63
|
|
|
63
|
0
|
152
|
sub dec64_mem { $_[0]->_append_op64_reg_mem(8, 0xFF, 1, $_[1]) } |
809
|
63
|
|
|
63
|
0
|
151
|
sub dec32_mem { $_[0]->_append_op32_reg_mem(0, 0xFF, 1, $_[1]) } |
810
|
63
|
|
|
63
|
0
|
142
|
sub dec16_mem { $_[0]->_append_op16_reg_mem(0, 0xFF, 1, $_[1]) } |
811
|
63
|
|
|
63
|
0
|
153
|
sub dec8_mem { $_[0]->_append_op8_reg_mem (0, 0xFE, 1, $_[1]) } |
812
|
|
|
|
|
|
|
|
813
|
|
|
|
|
|
|
|
814
|
0
|
|
|
0
|
1
|
0
|
sub inc { splice(@_,1,0,'inc'); &_autodetect_signature_1op; } |
|
0
|
|
|
|
|
0
|
|
815
|
|
|
|
|
|
|
|
816
|
7
|
|
|
7
|
0
|
18
|
sub inc64_reg { $_[0]->_append_op64_reg_reg(0xFF, 0, $_[1]) } |
817
|
7
|
|
|
7
|
0
|
17
|
sub inc32_reg { $_[0]->_append_op32_reg_reg(0xFF, 0, $_[1]) } |
818
|
7
|
|
|
7
|
0
|
19
|
sub inc16_reg { $_[0]->_append_op16_reg_reg(0xFF, 0, $_[1]) } |
819
|
7
|
|
|
7
|
0
|
21
|
sub inc8_reg { $_[0]->_append_op8_reg_reg (0xFE, 0, $_[1]) } |
820
|
|
|
|
|
|
|
|
821
|
63
|
|
|
63
|
0
|
152
|
sub inc64_mem { $_[0]->_append_op64_reg_mem(8, 0xFF, 0, $_[1]) } |
822
|
63
|
|
|
63
|
0
|
155
|
sub inc32_mem { $_[0]->_append_op32_reg_mem(0, 0xFF, 0, $_[1]) } |
823
|
63
|
|
|
63
|
0
|
144
|
sub inc16_mem { $_[0]->_append_op16_reg_mem(0, 0xFF, 0, $_[1]) } |
824
|
63
|
|
|
63
|
0
|
157
|
sub inc8_mem { $_[0]->_append_op8_reg_mem (0, 0xFE, 0, $_[1]) } |
825
|
|
|
|
|
|
|
|
826
|
|
|
|
|
|
|
|
827
|
0
|
|
|
0
|
0
|
0
|
sub not { splice(@_,1,0,'not'); &_autodetect_signature_1op; } |
|
0
|
|
|
|
|
0
|
|
828
|
|
|
|
|
|
|
|
829
|
7
|
|
|
7
|
0
|
21
|
sub not64_reg { $_[0]->_append_op64_reg_reg(0xF7, 2, $_[1]) } |
830
|
7
|
|
|
7
|
0
|
18
|
sub not32_reg { $_[0]->_append_op32_reg_reg(0xF7, 2, $_[1]) } |
831
|
7
|
|
|
7
|
0
|
21
|
sub not16_reg { $_[0]->_append_op16_reg_reg(0xF7, 2, $_[1]) } |
832
|
7
|
|
|
7
|
0
|
20
|
sub not8_reg { $_[0]->_append_op8_reg_reg (0xF6, 2, $_[1]) } |
833
|
|
|
|
|
|
|
|
834
|
63
|
|
|
63
|
0
|
164
|
sub not64_mem { $_[0]->_append_op64_reg_mem(8, 0xF7, 2, $_[1]) } |
835
|
63
|
|
|
63
|
0
|
188
|
sub not32_mem { $_[0]->_append_op32_reg_mem(0, 0xF7, 2, $_[1]) } |
836
|
63
|
|
|
63
|
0
|
157
|
sub not16_mem { $_[0]->_append_op16_reg_mem(0, 0xF7, 2, $_[1]) } |
837
|
63
|
|
|
63
|
0
|
161
|
sub not8_mem { $_[0]->_append_op8_reg_mem (0, 0xF6, 2, $_[1]) } |
838
|
|
|
|
|
|
|
|
839
|
|
|
|
|
|
|
|
840
|
0
|
|
|
0
|
0
|
0
|
sub neg { splice(@_,1,0,'neg'); &_autodetect_signature_1op; } |
|
0
|
|
|
|
|
0
|
|
841
|
|
|
|
|
|
|
|
842
|
7
|
|
|
7
|
0
|
24
|
sub neg64_reg { $_[0]->_append_op64_reg_reg(0xF7, 3, $_[1]) } |
843
|
7
|
|
|
7
|
0
|
21
|
sub neg32_reg { $_[0]->_append_op32_reg_reg(0xF7, 3, $_[1]) } |
844
|
7
|
|
|
7
|
0
|
21
|
sub neg16_reg { $_[0]->_append_op16_reg_reg(0xF7, 3, $_[1]) } |
845
|
7
|
|
|
7
|
0
|
20
|
sub neg8_reg { $_[0]->_append_op8_reg_reg (0xF6, 3, $_[1]) } |
846
|
|
|
|
|
|
|
|
847
|
63
|
|
|
63
|
0
|
169
|
sub neg64_mem { $_[0]->_append_op64_reg_mem(8, 0xF7, 3, $_[1]) } |
848
|
63
|
|
|
63
|
0
|
154
|
sub neg32_mem { $_[0]->_append_op32_reg_mem(0, 0xF7, 3, $_[1]) } |
849
|
63
|
|
|
63
|
0
|
153
|
sub neg16_mem { $_[0]->_append_op16_reg_mem(0, 0xF7, 3, $_[1]) } |
850
|
63
|
|
|
63
|
0
|
156
|
sub neg8_mem { $_[0]->_append_op8_reg_mem (0, 0xF6, 3, $_[1]) } |
851
|
|
|
|
|
|
|
|
852
|
|
|
|
|
|
|
|
853
|
0
|
|
|
0
|
0
|
0
|
sub div { splice(@_,1,0,'div' ); &_autodetect_signature_1op; } |
|
0
|
|
|
|
|
0
|
|
854
|
0
|
|
|
0
|
0
|
0
|
sub idiv { splice(@_,1,0,'idiv'); &_autodetect_signature_1op; } |
|
0
|
|
|
|
|
0
|
|
855
|
|
|
|
|
|
|
|
856
|
7
|
|
|
7
|
0
|
22
|
sub div64_reg { $_[0]->_append_op64_reg_reg (0xF7, 6, $_[1]) } |
857
|
7
|
|
|
7
|
0
|
19
|
sub div32_reg { $_[0]->_append_op32_reg_reg (0xF7, 6, $_[1]) } |
858
|
7
|
|
|
7
|
0
|
23
|
sub div16_reg { $_[0]->_append_op16_reg_reg (0xF7, 6, $_[1]) } |
859
|
7
|
|
|
7
|
0
|
21
|
sub div8_reg { $_[0]->_append_op8_opreg_reg(0xF6, 6, $_[1]) } |
860
|
|
|
|
|
|
|
|
861
|
63
|
|
|
63
|
0
|
157
|
sub div64_mem { $_[0]->_append_op64_reg_mem (8, 0xF7, 6, $_[1]) } |
862
|
63
|
|
|
63
|
0
|
159
|
sub div32_mem { $_[0]->_append_op32_reg_mem (0, 0xF7, 6, $_[1]) } |
863
|
63
|
|
|
63
|
0
|
155
|
sub div16_mem { $_[0]->_append_op16_reg_mem (0, 0xF7, 6, $_[1]) } |
864
|
63
|
|
|
63
|
0
|
159
|
sub div8_mem { $_[0]->_append_op8_opreg_mem(0, 0xF6, 6, $_[1]) } |
865
|
|
|
|
|
|
|
|
866
|
7
|
|
|
7
|
0
|
20
|
sub idiv64_reg { $_[0]->_append_op64_reg_reg (0xF7, 7, $_[1]) } |
867
|
7
|
|
|
7
|
0
|
19
|
sub idiv32_reg { $_[0]->_append_op32_reg_reg (0xF7, 7, $_[1]) } |
868
|
7
|
|
|
7
|
0
|
21
|
sub idiv16_reg { $_[0]->_append_op16_reg_reg (0xF7, 7, $_[1]) } |
869
|
7
|
|
|
7
|
0
|
21
|
sub idiv8_reg { $_[0]->_append_op8_opreg_reg(0xF6, 7, $_[1]) } |
870
|
|
|
|
|
|
|
|
871
|
63
|
|
|
63
|
0
|
154
|
sub idiv64_mem { $_[0]->_append_op64_reg_mem (8, 0xF7, 7, $_[1]) } |
872
|
63
|
|
|
63
|
0
|
158
|
sub idiv32_mem { $_[0]->_append_op32_reg_mem (0, 0xF7, 7, $_[1]) } |
873
|
63
|
|
|
63
|
0
|
172
|
sub idiv16_mem { $_[0]->_append_op16_reg_mem (0, 0xF7, 7, $_[1]) } |
874
|
63
|
|
|
63
|
0
|
160
|
sub idiv8_mem { $_[0]->_append_op8_opreg_mem(0, 0xF6, 7, $_[1]) } |
875
|
|
|
|
|
|
|
|
876
|
|
|
|
|
|
|
|
877
|
|
|
|
|
|
|
#=item mul64_reg |
878
|
|
|
|
|
|
|
# |
879
|
|
|
|
|
|
|
#=item mul32_reg |
880
|
|
|
|
|
|
|
# |
881
|
|
|
|
|
|
|
#=item mul16_reg |
882
|
|
|
|
|
|
|
# |
883
|
|
|
|
|
|
|
#=item mul64_mem |
884
|
|
|
|
|
|
|
# |
885
|
|
|
|
|
|
|
#=item mul32_mem |
886
|
|
|
|
|
|
|
# |
887
|
|
|
|
|
|
|
#=item mul16_mem |
888
|
|
|
|
|
|
|
# |
889
|
|
|
|
|
|
|
#=item mul64_reg_imm |
890
|
|
|
|
|
|
|
# |
891
|
|
|
|
|
|
|
#=item mul32_reg_imm |
892
|
|
|
|
|
|
|
# |
893
|
|
|
|
|
|
|
#=item mul16_reg_imm |
894
|
|
|
|
|
|
|
# |
895
|
|
|
|
|
|
|
#=item mul64_mem_imm |
896
|
|
|
|
|
|
|
# |
897
|
|
|
|
|
|
|
#=item mul32_mem_imm |
898
|
|
|
|
|
|
|
# |
899
|
|
|
|
|
|
|
#=item mul16_mem_imm |
900
|
|
|
|
|
|
|
|
901
|
0
|
|
|
0
|
1
|
0
|
sub mul64_dxax_reg { shift->_append_op64_reg_reg(8, 0xF7, 5, @_) } |
902
|
0
|
|
|
0
|
1
|
0
|
sub mul32_dxax_reg { shift->_append_op32_reg_reg(0, 0xF7, 5, @_) } |
903
|
0
|
|
|
0
|
1
|
0
|
sub mul16_dxax_reg { shift->_append_op16_reg_reg(0, 0xF7, 5, @_) } |
904
|
0
|
|
|
0
|
1
|
0
|
sub mul8_ax_reg { shift->_append_op8_reg_reg (0, 0xF6, 5, @_) } |
905
|
|
|
|
|
|
|
|
906
|
|
|
|
|
|
|
#sub mul64s_reg { shift->_append_op64_reg_reg(8, |
907
|
|
|
|
|
|
|
|
908
|
|
|
|
|
|
|
|
909
|
1
|
|
|
1
|
1
|
8
|
sub sign_extend_al_ax { $_[0]{_buf} .= "\x66\x98"; $_[0] } |
|
1
|
|
|
|
|
4
|
|
910
|
|
|
|
|
|
|
*cbw= *sign_extend_al_ax; |
911
|
|
|
|
|
|
|
|
912
|
1
|
|
|
1
|
1
|
7
|
sub sign_extend_ax_eax { $_[0]{_buf} .= "\x98"; $_[0] } |
|
1
|
|
|
|
|
3
|
|
913
|
|
|
|
|
|
|
*cwde= *sign_extend_ax_eax; |
914
|
|
|
|
|
|
|
|
915
|
1
|
|
|
1
|
1
|
4
|
sub sign_extend_eax_rax { $_[0]{_buf} .= "\x48\x98"; $_[0] } |
|
1
|
|
|
|
|
3
|
|
916
|
|
|
|
|
|
|
*cdqe= *sign_extend_eax_rax; |
917
|
|
|
|
|
|
|
|
918
|
1
|
|
|
1
|
1
|
4
|
sub sign_extend_ax_dx { $_[0]{_buf} .= "\x66\x99"; $_[0] } |
|
1
|
|
|
|
|
4
|
|
919
|
|
|
|
|
|
|
*cwd= *sign_extend_ax_dx; |
920
|
|
|
|
|
|
|
|
921
|
1
|
|
|
1
|
1
|
3
|
sub sign_extend_eax_edx { $_[0]{_buf} .= "\x99"; $_[0] } |
|
1
|
|
|
|
|
2
|
|
922
|
|
|
|
|
|
|
*cdq= *sign_extend_eax_edx; |
923
|
|
|
|
|
|
|
|
924
|
1
|
|
|
1
|
1
|
3
|
sub sign_extend_rax_rdx { $_[0]{_buf} .= "\x48\x99"; $_[0] } |
|
1
|
|
|
|
|
3
|
|
925
|
|
|
|
|
|
|
*cqo= *sign_extend_rax_rdx; |
926
|
|
|
|
|
|
|
|
927
|
|
|
|
|
|
|
|
928
|
|
|
|
|
|
|
my @_carry_flag_op= ( "\xF5", "\xF8", "\xF9" ); |
929
|
3
|
|
|
3
|
1
|
8
|
sub flag_carry { $_[0]{_buf} .= $_carry_flag_op[$_[1] + 1]; $_[0] } |
|
3
|
|
|
|
|
10
|
|
930
|
1
|
|
|
1
|
1
|
14
|
sub clc { $_[0]{_buf} .= "\xF8"; $_[0] } |
|
1
|
|
|
|
|
4
|
|
931
|
1
|
|
|
1
|
1
|
8
|
sub cmc { $_[0]{_buf} .= "\xF5"; $_[0] } |
|
1
|
|
|
|
|
3
|
|
932
|
1
|
|
|
1
|
1
|
6
|
sub stc { $_[0]{_buf} .= "\xF9"; $_[0] } |
|
1
|
|
|
|
|
3
|
|
933
|
|
|
|
|
|
|
|
934
|
|
|
|
|
|
|
|
935
|
|
|
|
|
|
|
# wait til late in compilation to avoid name clash hassle |
936
|
17
|
|
|
17
|
1
|
960
|
END { eval q|sub push { splice(@_,1,0,'push' ); &_autodetect_signature_1op; }| }; |
|
0
|
|
|
0
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
937
|
|
|
|
|
|
|
|
938
|
|
|
|
|
|
|
sub push_reg { |
939
|
7
|
|
|
7
|
0
|
17
|
my ($self, $reg)= @_; |
940
|
7
|
|
33
|
|
|
22
|
$reg= ($regnum64{$reg} // croak("$reg is not a 64-bit register")); |
941
|
7
|
100
|
|
|
|
33
|
$self->{_buf} .= $reg > 7? pack('CC', 0x41, 0x50+($reg&7)) : pack('C', 0x50+($reg&7)); |
942
|
7
|
|
|
|
|
16
|
$self; |
943
|
|
|
|
|
|
|
} |
944
|
|
|
|
|
|
|
|
945
|
|
|
|
|
|
|
sub push_imm { |
946
|
8
|
|
|
8
|
0
|
17
|
my ($self, $imm)= @_; |
947
|
17
|
|
|
17
|
|
158021
|
use integer; |
|
17
|
|
|
|
|
57
|
|
|
17
|
|
|
|
|
110
|
|
948
|
8
|
50
|
|
|
|
18
|
my $val= ref $imm? 0x7FFFFFFF : $imm; |
949
|
8
|
100
|
|
|
|
34
|
$self->{_buf} .= (($val >> 7) == ($val >> 8))? pack('Cc', 0x6A, $val) : pack('CV', 0x68, $val); |
950
|
8
|
50
|
|
|
|
20
|
$self->_mark_unresolved(-4, encode => '_repack', bits => 32, value => $imm) |
951
|
|
|
|
|
|
|
if ref $imm; |
952
|
8
|
|
|
|
|
19
|
$self; |
953
|
|
|
|
|
|
|
} |
954
|
|
|
|
|
|
|
|
955
|
63
|
|
|
63
|
0
|
175
|
sub push_mem { shift->_append_op64_reg_mem(0, 0xFF, 6, shift) } |
956
|
|
|
|
|
|
|
|
957
|
|
|
|
|
|
|
|
958
|
|
|
|
|
|
|
# wait til late in compilation to avoid name clash hassle |
959
|
17
|
|
|
17
|
1
|
55944
|
END { eval q|sub pop { splice(@_,1,0,'pop' ); &_autodetect_signature_1op; }| }; |
|
0
|
|
|
0
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
960
|
|
|
|
|
|
|
|
961
|
|
|
|
|
|
|
sub pop_reg { |
962
|
7
|
|
|
7
|
1
|
70
|
my ($self, $reg)= @_; |
963
|
7
|
|
33
|
|
|
71
|
$reg= ($regnum64{$reg} // croak("$reg is not a 64-bit register")); |
964
|
7
|
100
|
|
|
|
37
|
$self->{_buf} .= $reg > 7? pack('CC', 0x41, 0x58+($reg&7)) : pack('C', 0x58+($reg&7)); |
965
|
7
|
|
|
|
|
20
|
$self; |
966
|
|
|
|
|
|
|
} |
967
|
|
|
|
|
|
|
|
968
|
63
|
|
|
63
|
1
|
167
|
sub pop_mem { shift->_append_op64_reg_mem(0, 0x8F, 0, shift) } |
969
|
|
|
|
|
|
|
|
970
|
|
|
|
|
|
|
|
971
|
|
|
|
|
|
|
sub enter { |
972
|
28
|
|
|
28
|
0
|
64
|
my ($self, $varspace, $nesting)= @_; |
973
|
28
|
|
50
|
|
|
65
|
$nesting //= 0; |
974
|
28
|
50
|
33
|
|
|
94
|
if (!ref $varspace && !ref $nesting) { |
975
|
28
|
|
|
|
|
95
|
$self->{_buf} .= pack('CvC', 0xC8, $varspace, $nesting); |
976
|
|
|
|
|
|
|
} |
977
|
|
|
|
|
|
|
else { |
978
|
0
|
0
|
|
|
|
0
|
$self->{_buf} .= pack('Cv', 0xC8, ref $varspace? 0 : $varspace); |
979
|
0
|
0
|
|
|
|
0
|
$self->_mark_unresolved(-2, encode => '_repack', bits => 16, value => $varspace) |
980
|
|
|
|
|
|
|
if ref $varspace; |
981
|
0
|
0
|
|
|
|
0
|
$self->{_buf} .= pack('C', ref $nesting? 0 : $nesting); |
982
|
0
|
0
|
|
|
|
0
|
$self->_mark_unresolved(-1, encode => '_repack', bits => 8, value => $nesting) |
983
|
|
|
|
|
|
|
if ref $nesting; |
984
|
|
|
|
|
|
|
} |
985
|
28
|
|
|
|
|
60
|
$self |
986
|
|
|
|
|
|
|
} |
987
|
|
|
|
|
|
|
|
988
|
|
|
|
|
|
|
|
989
|
1
|
|
|
1
|
0
|
5
|
sub leave { $_[0]{_buf} .= "\xC9"; $_[0] } |
|
1
|
|
|
|
|
5
|
|
990
|
|
|
|
|
|
|
|
991
|
|
|
|
|
|
|
|
992
|
|
|
|
|
|
|
sub syscall { |
993
|
0
|
|
|
0
|
1
|
0
|
$_[0]{_buf} .= "\x0F\x05"; |
994
|
0
|
|
|
|
|
0
|
$_[0]; |
995
|
|
|
|
|
|
|
} |
996
|
|
|
|
|
|
|
|
997
|
|
|
|
|
|
|
|
998
|
24
|
|
|
24
|
1
|
61
|
sub rep { $_[0]{_buf} .= "\xF3"; $_[0] } |
|
24
|
|
|
|
|
53
|
|
999
|
|
|
|
|
|
|
*repe= *repz= *rep; |
1000
|
|
|
|
|
|
|
|
1001
|
24
|
|
|
24
|
1
|
60
|
sub repnz { $_[0]{_buf} .= "\xF2"; $_[0] } |
|
24
|
|
|
|
|
93
|
|
1002
|
|
|
|
|
|
|
*repne= *repnz; |
1003
|
|
|
|
|
|
|
|
1004
|
|
|
|
|
|
|
|
1005
|
|
|
|
|
|
|
my @_direction_flag_op= ( "\xFC", "\xFD" ); |
1006
|
2
|
|
|
2
|
1
|
10
|
sub flag_direction { $_[0]{_buf} .= $_direction_flag_op[0+!!$_[1]]; $_[0] } |
|
2
|
|
|
|
|
5
|
|
1007
|
1
|
|
|
1
|
1
|
8
|
sub cld { $_[0]{_buf} .= "\xFC"; $_[0] } |
|
1
|
|
|
|
|
7
|
|
1008
|
1
|
|
|
1
|
1
|
3
|
sub std { $_[0]{_buf} .= "\xFD"; $_[0] } |
|
1
|
|
|
|
|
3
|
|
1009
|
|
|
|
|
|
|
|
1010
|
|
|
|
|
|
|
|
1011
|
4
|
|
|
4
|
1
|
9
|
sub movs64 { $_[0]{_buf} .= "\x48\xA5"; $_[0] } |
|
4
|
|
|
|
|
7
|
|
1012
|
|
|
|
|
|
|
*movsq= *movs64; |
1013
|
|
|
|
|
|
|
|
1014
|
4
|
|
|
4
|
1
|
7
|
sub movs32 { $_[0]{_buf} .= "\xA5"; $_[0] } |
|
4
|
|
|
|
|
9
|
|
1015
|
|
|
|
|
|
|
*movsd= *movs32; |
1016
|
|
|
|
|
|
|
|
1017
|
4
|
|
|
4
|
1
|
9
|
sub movs16 { $_[0]{_buf} .= "\x66\xA5"; $_[0] } |
|
4
|
|
|
|
|
8
|
|
1018
|
|
|
|
|
|
|
*movsw= *movs16; |
1019
|
|
|
|
|
|
|
|
1020
|
4
|
|
|
4
|
1
|
372
|
sub movs8 { $_[0]{_buf} .= "\xA4"; $_[0] } |
|
4
|
|
|
|
|
11
|
|
1021
|
|
|
|
|
|
|
*movsb= *movs8; |
1022
|
|
|
|
|
|
|
|
1023
|
|
|
|
|
|
|
|
1024
|
4
|
|
|
4
|
1
|
7
|
sub cmps64 { $_[0]{_buf}.= "\x48\xA7"; $_[0] } |
|
4
|
|
|
|
|
9
|
|
1025
|
|
|
|
|
|
|
*cmpsq= *cmps64; |
1026
|
|
|
|
|
|
|
|
1027
|
4
|
|
|
4
|
1
|
10
|
sub cmps32 { $_[0]{_buf}.= "\xA7"; $_[0] } |
|
4
|
|
|
|
|
8
|
|
1028
|
|
|
|
|
|
|
*cmpsd= *cmps32; |
1029
|
|
|
|
|
|
|
|
1030
|
4
|
|
|
4
|
1
|
11
|
sub cmps16 { $_[0]{_buf}.= "\x66\xA7"; $_[0] } |
|
4
|
|
|
|
|
8
|
|
1031
|
|
|
|
|
|
|
*cmpsw= *cmps16; |
1032
|
|
|
|
|
|
|
|
1033
|
4
|
|
|
4
|
1
|
18
|
sub cmps8 { $_[0]{_buf}.= "\xA6"; $_[0] } |
|
4
|
|
|
|
|
9
|
|
1034
|
|
|
|
|
|
|
*cmpsb= *cmps8; |
1035
|
|
|
|
|
|
|
|
1036
|
|
|
|
|
|
|
|
1037
|
4
|
|
|
4
|
1
|
11
|
sub scas64 { $_[0]{_buf} .= "\x48\xAF"; $_[0] } |
|
4
|
|
|
|
|
9
|
|
1038
|
|
|
|
|
|
|
*scasq= *scas64; |
1039
|
|
|
|
|
|
|
|
1040
|
4
|
|
|
4
|
1
|
15
|
sub scas32 { $_[0]{_buf} .= "\xAF"; $_[0] } |
|
4
|
|
|
|
|
9
|
|
1041
|
|
|
|
|
|
|
*scasd= *scas32; |
1042
|
|
|
|
|
|
|
|
1043
|
4
|
|
|
4
|
1
|
13
|
sub scas16 { $_[0]{_buf} .= "\x66\xAF"; $_[0] } |
|
4
|
|
|
|
|
9
|
|
1044
|
|
|
|
|
|
|
*scasw= *scas16; |
1045
|
|
|
|
|
|
|
|
1046
|
4
|
|
|
4
|
1
|
9
|
sub scas8 { $_[0]{_buf} .= "\xAE"; $_[0] } |
|
4
|
|
|
|
|
9
|
|
1047
|
|
|
|
|
|
|
*scasb= *scas8; |
1048
|
|
|
|
|
|
|
|
1049
|
|
|
|
|
|
|
|
1050
|
|
|
|
|
|
|
sub mfence { |
1051
|
0
|
|
|
0
|
1
|
0
|
$_[0]{_buf} .= "\x0F\xAE\xF0"; |
1052
|
0
|
|
|
|
|
0
|
$_[0]; |
1053
|
|
|
|
|
|
|
} |
1054
|
|
|
|
|
|
|
sub lfence { |
1055
|
0
|
|
|
0
|
1
|
0
|
$_[0]{_buf} .= "\x0F\xAE\xE8"; |
1056
|
0
|
|
|
|
|
0
|
$_[0]; |
1057
|
|
|
|
|
|
|
} |
1058
|
|
|
|
|
|
|
sub sfence { |
1059
|
0
|
|
|
0
|
1
|
0
|
$_[0]{_buf} .= "\x0F\xAE\xF8"; |
1060
|
0
|
|
|
|
|
0
|
$_[0]; |
1061
|
|
|
|
|
|
|
} |
1062
|
|
|
|
|
|
|
|
1063
|
|
|
|
|
|
|
#sub cache_flush { |
1064
|
|
|
|
|
|
|
# ...; |
1065
|
|
|
|
|
|
|
#} |
1066
|
|
|
|
|
|
|
#*clflush= *cache_flush; |
1067
|
|
|
|
|
|
|
|
1068
|
|
|
|
|
|
|
|
1069
|
|
|
|
|
|
|
#=head2 _encode_op_reg_reg |
1070
|
|
|
|
|
|
|
# |
1071
|
|
|
|
|
|
|
#Encode standard instruction with REX prefix which refers only to registers. |
1072
|
|
|
|
|
|
|
#This skips all the memory addressing logic since it is only operating on registers, |
1073
|
|
|
|
|
|
|
#and always produces known-length encodings. |
1074
|
|
|
|
|
|
|
# |
1075
|
|
|
|
|
|
|
#=cut |
1076
|
|
|
|
|
|
|
|
1077
|
|
|
|
|
|
|
sub _encode_op_reg_reg { |
1078
|
14
|
|
|
14
|
|
38
|
my ($self, $rex, $opcode, $reg1, $reg2, $immed_pack, $immed)= @_; |
1079
|
17
|
|
|
17
|
|
21774
|
use integer; |
|
17
|
|
|
|
|
46
|
|
|
17
|
|
|
|
|
365
|
|
1080
|
14
|
|
|
|
|
33
|
$rex |= (($reg1 & 8) >> 1) | (($reg2 & 8) >> 3); |
1081
|
14
|
50
|
|
|
|
92
|
return $rex? |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1082
|
|
|
|
|
|
|
(defined $immed? |
1083
|
|
|
|
|
|
|
pack('CCC'.$immed_pack, 0x40|$rex, $opcode, 0xC0 | (($reg1 & 7) << 3) | ($reg2 & 7), $immed) |
1084
|
|
|
|
|
|
|
: pack('CCC', 0x40|$rex, $opcode, 0xC0 | (($reg1 & 7) << 3) | ($reg2 & 7)) |
1085
|
|
|
|
|
|
|
) |
1086
|
|
|
|
|
|
|
: (defined $immed? |
1087
|
|
|
|
|
|
|
pack('CC'.$immed_pack, $opcode, 0xC0 | (($reg1 & 7) << 3) | ($reg2 & 7), $immed) |
1088
|
|
|
|
|
|
|
: pack('CC', $opcode, 0xC0 | (($reg1 & 7) << 3) | ($reg2 & 7)) |
1089
|
|
|
|
|
|
|
); |
1090
|
|
|
|
|
|
|
} |
1091
|
|
|
|
|
|
|
|
1092
|
|
|
|
|
|
|
sub _append_op64_reg_reg { |
1093
|
735
|
|
|
735
|
|
1864
|
my ($self, $opcode, $reg1, $reg2)= @_; |
1094
|
735
|
|
33
|
|
|
1957
|
$reg1= ($regnum64{$reg1} // croak("$reg1 is not a 64-bit register")); |
1095
|
735
|
|
33
|
|
|
1629
|
$reg2= ($regnum64{$reg2} // croak("$reg2 is not a 64-bit register")); |
1096
|
17
|
|
|
17
|
|
3764
|
use integer; |
|
17
|
|
|
|
|
59
|
|
|
17
|
|
|
|
|
93
|
|
1097
|
735
|
|
|
|
|
2718
|
$self->{_buf} .= pack('CCC', |
1098
|
|
|
|
|
|
|
0x48 | (($reg1 & 8) >> 1) | (($reg2 & 8) >> 3), |
1099
|
|
|
|
|
|
|
$opcode, 0xC0 | (($reg1 & 7) << 3) | ($reg2 & 7)); |
1100
|
735
|
|
|
|
|
1620
|
$self; |
1101
|
|
|
|
|
|
|
} |
1102
|
|
|
|
|
|
|
sub _append_op32_reg_reg { |
1103
|
646
|
|
|
646
|
|
1324
|
my ($self, $opcode, $reg1, $reg2)= @_; |
1104
|
646
|
|
33
|
|
|
1696
|
$reg1= ($regnum32{$reg1} // croak("$reg1 is not a 32-bit register")); |
1105
|
646
|
|
33
|
|
|
1485
|
$reg2= ($regnum32{$reg2} // croak("$reg2 is not a 32-bit register")); |
1106
|
17
|
|
|
17
|
|
2616
|
use integer; |
|
17
|
|
|
|
|
39
|
|
|
17
|
|
|
|
|
79
|
|
1107
|
646
|
|
|
|
|
1312
|
my $rex= (($reg1 & 8) >> 1) | (($reg2 & 8) >> 3); |
1108
|
646
|
100
|
|
|
|
2358
|
$self->{_buf} .= $rex? |
1109
|
|
|
|
|
|
|
pack('CCC', 0x40|$rex, $opcode, 0xC0 | (($reg1 & 7) << 3) | ($reg2 & 7)) |
1110
|
|
|
|
|
|
|
: pack('CC', $opcode, 0xC0 | (($reg1 & 7) << 3) | ($reg2 & 7)); |
1111
|
646
|
|
|
|
|
1382
|
$self; |
1112
|
|
|
|
|
|
|
} |
1113
|
|
|
|
|
|
|
sub _append_op16_reg_reg { |
1114
|
602
|
|
|
602
|
|
1286
|
my ($self, $opcode, $reg1, $reg2)= @_; |
1115
|
602
|
|
33
|
|
|
1593
|
$reg1= ($regnum16{$reg1} // croak("$reg1 is not a 16-bit register")); |
1116
|
602
|
|
33
|
|
|
1375
|
$reg2= ($regnum16{$reg2} // croak("$reg2 is not a 16-bit register")); |
1117
|
17
|
|
|
17
|
|
2761
|
use integer; |
|
17
|
|
|
|
|
34
|
|
|
17
|
|
|
|
|
63
|
|
1118
|
602
|
|
|
|
|
1245
|
my $rex= (($reg1 & 8) >> 1) | (($reg2 & 8) >> 3); |
1119
|
602
|
100
|
|
|
|
2289
|
$self->{_buf} .= $rex? |
1120
|
|
|
|
|
|
|
pack('CCCC', 0x66, 0x40|$rex, $opcode, 0xC0 | (($reg1 & 7) << 3) | ($reg2 & 7)) |
1121
|
|
|
|
|
|
|
: pack('CCC', 0x66, $opcode, 0xC0 | (($reg1 & 7) << 3) | ($reg2 & 7)); |
1122
|
602
|
|
|
|
|
1342
|
$self; |
1123
|
|
|
|
|
|
|
} |
1124
|
|
|
|
|
|
|
sub _append_op8_reg_reg { |
1125
|
420
|
|
|
420
|
|
893
|
my ($self, $opcode, $reg1, $reg2)= @_; |
1126
|
17
|
|
|
17
|
|
2261
|
use integer; |
|
17
|
|
|
|
|
36
|
|
|
17
|
|
|
|
|
75
|
|
1127
|
420
|
|
|
|
|
857
|
$reg1= $regnum8{$reg1}; |
1128
|
420
|
|
|
|
|
722
|
$reg2= $regnum8{$reg2}; |
1129
|
|
|
|
|
|
|
# special case for the "high byte" registers. They can't be used in an |
1130
|
|
|
|
|
|
|
# instruction that uses the REX prefix. |
1131
|
420
|
50
|
33
|
|
|
1527
|
if (!defined $reg1 || !defined $reg2) { |
1132
|
0
|
|
|
|
|
0
|
my $old_reg1= $reg1; |
1133
|
0
|
|
|
|
|
0
|
my $old_reg2= $reg2; |
1134
|
0
|
|
0
|
|
|
0
|
$reg1= $regnum8_high{$_[2]} // croak "$_[2] is not a valid 8-bit register"; |
1135
|
0
|
|
0
|
|
|
0
|
$reg2= $regnum8_high{$_[3]} // croak "$_[3] is not a valid 8-bit register"; |
1136
|
0
|
0
|
0
|
|
|
0
|
if (($old_reg1 && $old_reg1 > 3) || ($old_reg2 && $old_reg2 > 3)) { |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
1137
|
0
|
|
|
|
|
0
|
croak "Can't combine $_[2] with $_[3] in same instruction"; |
1138
|
|
|
|
|
|
|
} |
1139
|
0
|
|
|
|
|
0
|
$self->{_buf} .= pack('CC', $opcode, 0xC0 | ($reg1 << 3) | $reg2); |
1140
|
|
|
|
|
|
|
} |
1141
|
|
|
|
|
|
|
else { |
1142
|
420
|
100
|
100
|
|
|
2145
|
$self->{_buf} .= ($reg1 > 3 || $reg2 > 3)? |
1143
|
|
|
|
|
|
|
pack('CCC', 0x40|(($reg1 & 8) >> 1) | (($reg2 & 8) >> 3), $opcode, 0xC0 | (($reg1 & 7) << 3) | ($reg2 & 7)) |
1144
|
|
|
|
|
|
|
: pack('CC', $opcode, 0xC0 | ($reg1 << 3) | $reg2); |
1145
|
|
|
|
|
|
|
} |
1146
|
420
|
|
|
|
|
1018
|
$self; |
1147
|
|
|
|
|
|
|
} |
1148
|
|
|
|
|
|
|
|
1149
|
|
|
|
|
|
|
# Like above, but the first register argument isn't really a register argument |
1150
|
|
|
|
|
|
|
# and therefore doesn't require a 0x40 prefix for values > 3 |
1151
|
|
|
|
|
|
|
sub _append_op8_opreg_reg { |
1152
|
212
|
|
|
212
|
|
422
|
my ($self, $opcode, $opreg, $reg2)= @_; |
1153
|
17
|
|
|
17
|
|
4261
|
use integer; |
|
17
|
|
|
|
|
40
|
|
|
17
|
|
|
|
|
69
|
|
1154
|
212
|
|
|
|
|
460
|
$reg2= $regnum8{$reg2}; |
1155
|
|
|
|
|
|
|
# special case for the "high byte" registers. They can't be used in an |
1156
|
|
|
|
|
|
|
# instruction that uses the REX prefix. |
1157
|
212
|
100
|
|
|
|
393
|
if (!defined $reg2) { |
1158
|
72
|
|
|
|
|
118
|
my $old_reg2= $reg2; |
1159
|
72
|
|
33
|
|
|
197
|
$reg2= $regnum8_high{$_[3]} // croak "$_[3] is not a valid 8-bit register"; |
1160
|
72
|
|
|
|
|
234
|
$self->{_buf} .= pack('CC', $opcode, 0xC0 | ($opreg << 3) | $reg2); |
1161
|
|
|
|
|
|
|
} |
1162
|
|
|
|
|
|
|
else { |
1163
|
140
|
100
|
|
|
|
581
|
$self->{_buf} .= ($reg2 > 3)? |
1164
|
|
|
|
|
|
|
pack('CCC', 0x40| (($reg2 & 8) >> 3), $opcode, 0xC0 | ($opreg << 3) | ($reg2 & 7)) |
1165
|
|
|
|
|
|
|
: pack('CC', $opcode, 0xC0 | ($opreg << 3) | $reg2); |
1166
|
|
|
|
|
|
|
} |
1167
|
212
|
|
|
|
|
401
|
$self; |
1168
|
|
|
|
|
|
|
} |
1169
|
|
|
|
|
|
|
|
1170
|
|
|
|
|
|
|
#=head2 _append_op##_reg_mem |
1171
|
|
|
|
|
|
|
# |
1172
|
|
|
|
|
|
|
#Encode standard ##-bit instruction with REX prefix which addresses memory for one of its operands. |
1173
|
|
|
|
|
|
|
#The encoded length might not be resolved until later if an unknown displacement value was given. |
1174
|
|
|
|
|
|
|
# |
1175
|
|
|
|
|
|
|
#=cut |
1176
|
|
|
|
|
|
|
|
1177
|
|
|
|
|
|
|
sub _append_op64_reg_mem { |
1178
|
9263
|
|
|
9263
|
|
18827
|
my ($self, $rex, $opcode, $reg, $mem)= @_; |
1179
|
9263
|
|
|
|
|
18797
|
my ($base_reg, $disp, $index_reg, $scale)= @$mem; |
1180
|
9263
|
50
|
33
|
|
|
28791
|
$reg= $regnum64{$reg} // croak "$reg is not a valid 64-bit register" |
1181
|
|
|
|
|
|
|
if defined $reg; |
1182
|
9263
|
100
|
33
|
|
|
23466
|
$base_reg= $regnum64{$base_reg} // croak "$base_reg is not a valid 64-bit register" |
1183
|
|
|
|
|
|
|
if defined $base_reg; |
1184
|
9263
|
100
|
33
|
|
|
22951
|
$index_reg= $regnum64{$index_reg} // croak "$index_reg is not a valid 64-bit register" |
1185
|
|
|
|
|
|
|
if defined $index_reg; |
1186
|
9263
|
|
|
|
|
34061
|
$self->_append_possible_unknown('_encode_op_reg_mem', [$rex, $opcode, $reg, $base_reg, $disp, $index_reg, $scale], 4, 7); |
1187
|
9263
|
|
|
|
|
24550
|
$self; |
1188
|
|
|
|
|
|
|
} |
1189
|
|
|
|
|
|
|
|
1190
|
|
|
|
|
|
|
sub _append_op32_reg_mem { |
1191
|
9013
|
|
|
9013
|
|
18302
|
my ($self, $rex, $opcode, $reg, $mem)= @_; |
1192
|
9013
|
|
|
|
|
18157
|
my ($base_reg, $disp, $index_reg, $scale)= @$mem; |
1193
|
9013
|
50
|
33
|
|
|
27885
|
$reg= $regnum32{$reg} // croak "$reg is not a valid 32-bit register" |
1194
|
|
|
|
|
|
|
if defined $reg; |
1195
|
9013
|
100
|
33
|
|
|
22785
|
$base_reg= $regnum64{$base_reg} // croak "$base_reg is not a valid 64-bit register" |
1196
|
|
|
|
|
|
|
if defined $base_reg; |
1197
|
9013
|
100
|
33
|
|
|
21801
|
$index_reg= $regnum64{$index_reg} // croak "$index_reg is not a valid 64-bit register" |
1198
|
|
|
|
|
|
|
if defined $index_reg; |
1199
|
9013
|
|
|
|
|
27939
|
$self->_append_possible_unknown('_encode_op_reg_mem', [$rex, $opcode, $reg, $base_reg, $disp, $index_reg, $scale], 4, 7); |
1200
|
|
|
|
|
|
|
} |
1201
|
|
|
|
|
|
|
|
1202
|
|
|
|
|
|
|
sub _append_op16_reg_mem { |
1203
|
9009
|
|
|
9009
|
|
17988
|
my ($self, $rex, $opcode, $reg, $mem)= @_; |
1204
|
9009
|
|
|
|
|
18149
|
my ($base_reg, $disp, $index_reg, $scale)= @$mem; |
1205
|
9009
|
50
|
33
|
|
|
27725
|
$reg= $regnum16{$reg} // croak "$reg is not a valid 16-bit register" |
1206
|
|
|
|
|
|
|
if defined $reg; |
1207
|
9009
|
100
|
33
|
|
|
22979
|
$base_reg= $regnum64{$base_reg} // croak "$base_reg is not a valid 64-bit register" |
1208
|
|
|
|
|
|
|
if defined $base_reg; |
1209
|
9009
|
100
|
33
|
|
|
21840
|
$index_reg= $regnum64{$index_reg} // croak "$index_reg is not a valid 64-bit register" |
1210
|
|
|
|
|
|
|
if defined $index_reg; |
1211
|
9009
|
|
|
|
|
18711
|
$self->{_buf} .= "\x66"; |
1212
|
9009
|
|
|
|
|
28590
|
$self->_append_possible_unknown('_encode_op_reg_mem', [$rex, $opcode, $reg, $base_reg, $disp, $index_reg, $scale], 4, 7); |
1213
|
|
|
|
|
|
|
} |
1214
|
|
|
|
|
|
|
|
1215
|
|
|
|
|
|
|
sub _append_op8_reg_mem { |
1216
|
7308
|
|
|
7308
|
|
14942
|
my ($self, $rex, $opcode, $reg, $mem)= @_; |
1217
|
7308
|
|
|
|
|
14580
|
my ($base_reg, $disp, $index_reg, $scale)= @$mem; |
1218
|
7308
|
100
|
33
|
|
|
21269
|
$base_reg= $regnum64{$base_reg} // croak "$base_reg is not a valid 64-bit register" |
1219
|
|
|
|
|
|
|
if defined $base_reg; |
1220
|
7308
|
100
|
33
|
|
|
18407
|
$index_reg= $regnum64{$index_reg} // croak "$index_reg is not a valid 64-bit register" |
1221
|
|
|
|
|
|
|
if defined $index_reg; |
1222
|
7308
|
|
|
|
|
13017
|
$reg= $regnum8{$reg}; |
1223
|
|
|
|
|
|
|
# special case for the "high byte" registers |
1224
|
7308
|
50
|
|
|
|
18910
|
if (!defined $reg) { |
|
|
100
|
|
|
|
|
|
1225
|
0
|
|
0
|
|
|
0
|
$reg= $regnum8_high{$_[3]} // croak "$_[3] is not a valid 8-bit register"; |
1226
|
0
|
0
|
0
|
|
|
0
|
!$rex && ($base_reg//0) < 8 && ($index_reg//0) < 8 |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
1227
|
|
|
|
|
|
|
or croak "Cannot use $_[3] in instruction with REX prefix"; |
1228
|
|
|
|
|
|
|
} |
1229
|
|
|
|
|
|
|
# special case for needing REX byte for SPL, BPL, DIL, and SIL |
1230
|
|
|
|
|
|
|
elsif ($reg > 3) { |
1231
|
5040
|
|
|
|
|
8690
|
$rex |= 0x40; |
1232
|
|
|
|
|
|
|
} |
1233
|
7308
|
|
|
|
|
23945
|
$self->_append_possible_unknown('_encode_op_reg_mem', [$rex, $opcode, $reg, $base_reg, $disp, $index_reg, $scale], 4, 7); |
1234
|
|
|
|
|
|
|
} |
1235
|
|
|
|
|
|
|
# Like above, but the first register is a constant and don't need to test it for |
1236
|
|
|
|
|
|
|
# requiring a REX prefix if >3. |
1237
|
|
|
|
|
|
|
sub _append_op8_opreg_mem { |
1238
|
1260
|
|
|
1260
|
|
2330
|
my ($self, $rex, $opcode, $opreg, $mem)= @_; |
1239
|
1260
|
|
|
|
|
2687
|
my ($base_reg, $disp, $index_reg, $scale)= @$mem; |
1240
|
1260
|
100
|
33
|
|
|
3677
|
$base_reg= $regnum64{$base_reg} // croak "$base_reg is not a valid 64-bit register" |
1241
|
|
|
|
|
|
|
if defined $base_reg; |
1242
|
1260
|
100
|
33
|
|
|
3351
|
$index_reg= $regnum64{$index_reg} // croak "$index_reg is not a valid 64-bit register" |
1243
|
|
|
|
|
|
|
if defined $index_reg; |
1244
|
1260
|
|
|
|
|
3998
|
$self->_append_possible_unknown('_encode_op_reg_mem', [$rex, $opcode, $opreg, $base_reg, $disp, $index_reg, $scale], 4, 7); |
1245
|
|
|
|
|
|
|
} |
1246
|
|
|
|
|
|
|
|
1247
|
|
|
|
|
|
|
#=head2 _append_op##_const_to_mem |
1248
|
|
|
|
|
|
|
# |
1249
|
|
|
|
|
|
|
#Encode standard ##-bit instruction with REX prefix which operates on a constant and then |
1250
|
|
|
|
|
|
|
#writes to a memory location. |
1251
|
|
|
|
|
|
|
# |
1252
|
|
|
|
|
|
|
#=cut |
1253
|
|
|
|
|
|
|
|
1254
|
|
|
|
|
|
|
sub _append_op8_const_to_mem { |
1255
|
63
|
|
|
63
|
|
145
|
my ($self, $opcode, $opreg, $value, $mem)= @_; |
1256
|
63
|
|
|
|
|
130
|
my ($base_reg, $disp, $index_reg, $scale)= @$mem; |
1257
|
63
|
100
|
33
|
|
|
184
|
$base_reg= ($regnum64{$base_reg} // croak "$base_reg is not a 64-bit register") |
1258
|
|
|
|
|
|
|
if defined $base_reg; |
1259
|
63
|
100
|
33
|
|
|
168
|
$index_reg= ($regnum64{$index_reg} // croak "$index_reg is not a 64-bit register") |
1260
|
|
|
|
|
|
|
if defined $index_reg; |
1261
|
63
|
50
|
|
|
|
279
|
$self->_append_possible_unknown('_encode_op_reg_mem', [ 0, $opcode, $opreg, $base_reg, $disp, $index_reg, $scale, 'C', $value ], ref $disp? 4 : 8, defined $disp? 16:12); |
|
|
50
|
|
|
|
|
|
1262
|
|
|
|
|
|
|
} |
1263
|
|
|
|
|
|
|
sub _append_op16_const_to_mem { |
1264
|
63
|
|
|
63
|
|
131
|
my ($self, $opcode, $opreg, $value, $mem)= @_; |
1265
|
63
|
|
|
|
|
131
|
my ($base_reg, $disp, $index_reg, $scale)= @$mem; |
1266
|
63
|
100
|
33
|
|
|
199
|
$base_reg= ($regnum64{$base_reg} // croak "$base_reg is not a 64-bit register") |
1267
|
|
|
|
|
|
|
if defined $base_reg; |
1268
|
63
|
100
|
33
|
|
|
155
|
$index_reg= ($regnum64{$index_reg} // croak "$index_reg is not a 64-bit register") |
1269
|
|
|
|
|
|
|
if defined $index_reg; |
1270
|
63
|
|
|
|
|
129
|
$self->{_buf} .= "\x66"; |
1271
|
63
|
50
|
|
|
|
247
|
$self->_append_possible_unknown('_encode_op_reg_mem', [ 0, $opcode, $opreg, $base_reg, $disp, $index_reg, $scale, 'v', $value ], ref $disp? 4 : 8, defined $disp? 16:12); |
|
|
50
|
|
|
|
|
|
1272
|
|
|
|
|
|
|
} |
1273
|
|
|
|
|
|
|
sub _append_op32_const_to_mem { |
1274
|
63
|
|
|
63
|
|
149
|
my ($self, $opcode, $opreg, $value, $mem)= @_; |
1275
|
63
|
|
|
|
|
125
|
my ($base_reg, $disp, $index_reg, $scale)= @$mem; |
1276
|
63
|
100
|
33
|
|
|
184
|
$base_reg= ($regnum64{$base_reg} // croak "$base_reg is not a 64-bit register") |
1277
|
|
|
|
|
|
|
if defined $base_reg; |
1278
|
63
|
100
|
33
|
|
|
157
|
$index_reg= ($regnum64{$index_reg} // croak "$index_reg is not a 64-bit register") |
1279
|
|
|
|
|
|
|
if defined $index_reg; |
1280
|
63
|
50
|
|
|
|
248
|
$self->_append_possible_unknown('_encode_op_reg_mem', [ 0, $opcode, $opreg, $base_reg, $disp, $index_reg, $scale, 'V', $value ], ref $disp? 4 : 8, defined $disp? 16:12); |
|
|
50
|
|
|
|
|
|
1281
|
|
|
|
|
|
|
} |
1282
|
|
|
|
|
|
|
sub _append_op64_const_to_mem { |
1283
|
63
|
|
|
63
|
|
122
|
my ($self, $opcode, $opreg, $value, $mem)= @_; |
1284
|
63
|
|
|
|
|
127
|
my ($base_reg, $disp, $index_reg, $scale)= @$mem; |
1285
|
63
|
100
|
33
|
|
|
195
|
$base_reg= ($regnum64{$base_reg} // croak "$base_reg is not a 64-bit register") |
1286
|
|
|
|
|
|
|
if defined $base_reg; |
1287
|
63
|
100
|
33
|
|
|
159
|
$index_reg= ($regnum64{$index_reg} // croak "$index_reg is not a 64-bit register") |
1288
|
|
|
|
|
|
|
if defined $index_reg; |
1289
|
63
|
50
|
|
|
|
240
|
$self->_append_possible_unknown('_encode_op_reg_mem', [ 8, $opcode, $opreg, $base_reg, $disp, $index_reg, $scale, 'V', $value ], ref $disp? 4 : 8, defined $disp? 16:12); |
|
|
50
|
|
|
|
|
|
1290
|
|
|
|
|
|
|
} |
1291
|
|
|
|
|
|
|
|
1292
|
|
|
|
|
|
|
|
1293
|
|
|
|
|
|
|
# scale values for the SIB byte |
1294
|
|
|
|
|
|
|
my %SIB_scale= ( |
1295
|
|
|
|
|
|
|
1 => 0x00, |
1296
|
|
|
|
|
|
|
2 => 0x40, |
1297
|
|
|
|
|
|
|
4 => 0x80, |
1298
|
|
|
|
|
|
|
8 => 0xC0 |
1299
|
|
|
|
|
|
|
); |
1300
|
|
|
|
|
|
|
|
1301
|
|
|
|
|
|
|
sub _encode_op_reg_mem { |
1302
|
50225
|
|
|
50225
|
|
116750
|
my ($self, $rex, $opcode, $reg, $base_reg, $disp, $index_reg, $scale, $immed_pack, $immed)= @_; |
1303
|
17
|
|
|
17
|
|
24306
|
use integer; |
|
17
|
|
|
|
|
48
|
|
|
17
|
|
|
|
|
79
|
|
1304
|
50225
|
|
|
|
|
93598
|
$rex |= ($reg & 8) >> 1; |
1305
|
|
|
|
|
|
|
|
1306
|
50225
|
|
|
|
|
73523
|
my $tail; |
1307
|
50225
|
100
|
|
|
|
91888
|
if (defined $base_reg) { |
1308
|
38261
|
|
|
|
|
58744
|
$rex |= ($base_reg & 8) >> 3; |
1309
|
|
|
|
|
|
|
|
1310
|
|
|
|
|
|
|
# RBP,R13 always gets mod_rm displacement to differentiate from Null base register |
1311
|
38261
|
100
|
|
|
|
130651
|
my ($mod_rm, $suffix)= !$disp? ( ($base_reg&7) == 5? (0x40, "\0") : (0x00, '') ) |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1312
|
|
|
|
|
|
|
: (($disp >> 7) == ($disp >> 8))? (0x40, pack('c', $disp)) |
1313
|
|
|
|
|
|
|
: (($disp >> 31) == ($disp >> 31 >> 1))? (0x80, pack('V', $disp)) |
1314
|
|
|
|
|
|
|
: croak "address displacement out of range: $disp"; |
1315
|
|
|
|
|
|
|
|
1316
|
38261
|
100
|
|
|
|
75253
|
if (defined $index_reg) { |
|
|
100
|
|
|
|
|
|
1317
|
28694
|
|
50
|
|
|
79450
|
my $scale= $SIB_scale{$scale // 1} // croak "invalid index multiplier $scale"; |
|
|
|
33
|
|
|
|
|
1318
|
28694
|
50
|
|
|
|
57608
|
$index_reg != 4 or croak "RSP cannot be used as index register"; |
1319
|
28694
|
|
|
|
|
46053
|
$rex |= ($index_reg & 8) >> 2; |
1320
|
28694
|
|
|
|
|
84452
|
$tail= pack('CC', $mod_rm | (($reg & 7) << 3) | 4, $scale | (($index_reg & 7) << 3) | ($base_reg & 7)) . $suffix; |
1321
|
|
|
|
|
|
|
} |
1322
|
|
|
|
|
|
|
# RSP,R12 always gets a SIB byte |
1323
|
|
|
|
|
|
|
elsif (($base_reg&7) == 4) { |
1324
|
3188
|
|
|
|
|
9023
|
$tail= pack('CC', $mod_rm | (($reg & 7) << 3) | 4, 0x24) . $suffix; |
1325
|
|
|
|
|
|
|
} |
1326
|
|
|
|
|
|
|
else { |
1327
|
|
|
|
|
|
|
# Null index register is encoded as RSP |
1328
|
6379
|
|
|
|
|
17649
|
$tail= pack('C', $mod_rm | (($reg & 7) << 3) | ($base_reg & 7)) . $suffix; |
1329
|
|
|
|
|
|
|
} |
1330
|
|
|
|
|
|
|
} else { |
1331
|
|
|
|
|
|
|
# Null base register is encoded as RBP + 32bit displacement |
1332
|
|
|
|
|
|
|
|
1333
|
11964
|
50
|
|
|
|
27799
|
(($disp >> 31) == ($disp >> 31 >> 1)) |
1334
|
|
|
|
|
|
|
or croak "address displacement out of range: $disp"; |
1335
|
|
|
|
|
|
|
|
1336
|
11964
|
100
|
|
|
|
22006
|
if (defined $index_reg) { |
1337
|
9564
|
|
50
|
|
|
27558
|
my $scale= $SIB_scale{$scale // 1} // croak "invalid index multiplier $scale"; |
|
|
|
33
|
|
|
|
|
1338
|
9564
|
50
|
|
|
|
19316
|
$index_reg != 4 or croak "RSP cannot be used as index register"; |
1339
|
9564
|
|
|
|
|
15697
|
$rex |= ($index_reg & 8) >> 2; |
1340
|
9564
|
|
|
|
|
30644
|
$tail= pack('CCV', (($reg & 7) << 3) | 4, $scale | (($index_reg & 7) << 3) | 5, $disp); |
1341
|
|
|
|
|
|
|
} |
1342
|
|
|
|
|
|
|
else { |
1343
|
|
|
|
|
|
|
# Null index register is encoded as RSP |
1344
|
2400
|
|
|
|
|
7359
|
$tail= pack('CCV', (($reg & 7) << 3) | 4, 0x25, $disp); |
1345
|
|
|
|
|
|
|
} |
1346
|
|
|
|
|
|
|
} |
1347
|
50225
|
100
|
|
|
|
107444
|
$tail .= pack($immed_pack, $immed) |
1348
|
|
|
|
|
|
|
if defined $immed; |
1349
|
|
|
|
|
|
|
|
1350
|
50225
|
100
|
|
|
|
177154
|
return $rex? |
1351
|
|
|
|
|
|
|
pack('CC', ($rex|0x40), $opcode) . $tail |
1352
|
|
|
|
|
|
|
: pack('C', $opcode) . $tail; |
1353
|
|
|
|
|
|
|
} |
1354
|
|
|
|
|
|
|
|
1355
|
|
|
|
|
|
|
#=head2 _append_mathopNN_const |
1356
|
|
|
|
|
|
|
# |
1357
|
|
|
|
|
|
|
#This is so bizarre I don't even know where to start. Most "math-like" instructions have an opcode |
1358
|
|
|
|
|
|
|
#for an immediate the size of the register (except 64-bit which only gets a 32-bit immediate), an |
1359
|
|
|
|
|
|
|
#opcode for an 8-bit immediate, and another opcode specifically for the AX register which is a byte |
1360
|
|
|
|
|
|
|
#shorter than the normal, which is the only redeeming reason to bother using it. |
1361
|
|
|
|
|
|
|
#Also, there is a constant stored in the 3 bits of the unused register in the ModRM byte which acts |
1362
|
|
|
|
|
|
|
#as an extension of the opcode. |
1363
|
|
|
|
|
|
|
# |
1364
|
|
|
|
|
|
|
#These 4 methods are the generic implementation for encoding this mess. |
1365
|
|
|
|
|
|
|
#Each implementation also handles the possibility that the immediate value is an unknown variable |
1366
|
|
|
|
|
|
|
#resolved while the instructions are assembled. |
1367
|
|
|
|
|
|
|
# |
1368
|
|
|
|
|
|
|
#=over |
1369
|
|
|
|
|
|
|
# |
1370
|
|
|
|
|
|
|
#=item C<_append_mathop64_const($opcodeAX32, $opcode8, $opcode32, $opcode_reg, $reg, $immed)> |
1371
|
|
|
|
|
|
|
# |
1372
|
|
|
|
|
|
|
#This one is annoying because it only gets a sign-extended 32-bit value, so you actually only get |
1373
|
|
|
|
|
|
|
#31 bits of an immediate value for a 64-bit instruction. |
1374
|
|
|
|
|
|
|
# |
1375
|
|
|
|
|
|
|
#=cut |
1376
|
|
|
|
|
|
|
|
1377
|
|
|
|
|
|
|
sub _append_mathop64_const { |
1378
|
448
|
|
|
448
|
|
1184
|
my ($self, @args)= @_; # $opcodeAX32, $opcode8, $opcode32, $opcode_reg, $reg, $immed |
1379
|
448
|
|
33
|
|
|
1356
|
$args[4]= $regnum64{$args[4]} // croak("$args[4] is not a 64-bit register"); |
1380
|
448
|
|
|
|
|
1102
|
$self->_append_possible_unknown('_encode_mathop64_imm', \@args, 5, 7); |
1381
|
|
|
|
|
|
|
} |
1382
|
|
|
|
|
|
|
sub _encode_mathop64_imm { |
1383
|
448
|
|
|
448
|
|
983
|
my ($self, $opcodeAX32, $opcode8, $opcode32, $opcode_reg, $reg, $value)= @_; |
1384
|
17
|
|
|
17
|
|
8656
|
use integer; |
|
17
|
|
|
|
|
56
|
|
|
17
|
|
|
|
|
96
|
|
1385
|
448
|
|
|
|
|
894
|
my $rex= 0x48 | (($reg & 8)>>3); |
1386
|
448
|
100
|
100
|
|
|
2930
|
defined $opcode8 && (($value >> 7) == ($value >> 8))? |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1387
|
|
|
|
|
|
|
pack('CCCc', $rex, $opcode8, 0xC0 | ($opcode_reg << 3) | ($reg & 7), $value) |
1388
|
|
|
|
|
|
|
: (($value >> 31) == ($value >> 31 >> 1))? ( |
1389
|
|
|
|
|
|
|
# Ops on AX get encoded as a special instruction |
1390
|
|
|
|
|
|
|
$reg? pack('CCCV', $rex, $opcode32, 0xC0 | ($opcode_reg << 3) | ($reg & 7), $value) |
1391
|
|
|
|
|
|
|
: pack('CCV', $rex, $opcodeAX32, $value) |
1392
|
|
|
|
|
|
|
) |
1393
|
|
|
|
|
|
|
# 64-bit only supports 32-bit sign-extend immediate |
1394
|
|
|
|
|
|
|
: croak "$value is wider than 32-bit"; |
1395
|
|
|
|
|
|
|
} |
1396
|
|
|
|
|
|
|
|
1397
|
|
|
|
|
|
|
#=item C<_append_mathop32_const($opcodeAX32, $opcode8, $opcode32, $opcode_reg, $reg, $immed)> |
1398
|
|
|
|
|
|
|
# |
1399
|
|
|
|
|
|
|
#=cut |
1400
|
|
|
|
|
|
|
|
1401
|
|
|
|
|
|
|
sub _append_mathop32_const { |
1402
|
448
|
|
|
448
|
|
1144
|
my ($self, @args)= @_; # $opcodeAX32, $opcode8, $opcode32, $opcode_reg, $reg, $immed |
1403
|
448
|
|
33
|
|
|
1203
|
$args[4]= $regnum32{$args[4]} // croak("$args[4] is not a 32-bit register"); |
1404
|
448
|
|
|
|
|
1059
|
$self->_append_possible_unknown('_encode_mathop32_imm', \@args, 5, 7); |
1405
|
|
|
|
|
|
|
} |
1406
|
|
|
|
|
|
|
sub _encode_mathop32_imm { |
1407
|
448
|
|
|
448
|
|
959
|
my ($self, $opcodeAX32, $opcode8, $opcode32, $opcode_reg, $reg, $value)= @_; |
1408
|
17
|
|
|
17
|
|
4277
|
use integer; |
|
17
|
|
|
|
|
47
|
|
|
17
|
|
|
|
|
92
|
|
1409
|
448
|
|
|
|
|
807
|
my $rex= (($reg & 8)>>3); |
1410
|
448
|
100
|
100
|
|
|
3410
|
defined $opcode8 && (($value >> 7) == ($value >> 8) or ($value >> 8 == 0xFFFFFF))? |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1411
|
|
|
|
|
|
|
( $rex? pack('CCCC', 0x40|$rex, $opcode8, 0xC0 | ($opcode_reg << 3) | ($reg & 7), $value&0xFF) |
1412
|
|
|
|
|
|
|
: pack('CCC', $opcode8, 0xC0 | ($opcode_reg << 3) | ($reg & 7), $value&0xFF) |
1413
|
|
|
|
|
|
|
) |
1414
|
|
|
|
|
|
|
: (($value >> 31 >> 1) == ($value >> 31 >> 2))? ( |
1415
|
|
|
|
|
|
|
# Ops on AX get encoded as a special instruction |
1416
|
|
|
|
|
|
|
$rex? pack('CCCV', 0x40|$rex, $opcode32, 0xC0 | ($opcode_reg << 3) | ($reg & 7), $value) |
1417
|
|
|
|
|
|
|
: $reg? pack('CCV', $opcode32, 0xC0 | ($opcode_reg << 3) | ($reg & 7), $value) |
1418
|
|
|
|
|
|
|
: pack('CV', $opcodeAX32, $value) |
1419
|
|
|
|
|
|
|
) |
1420
|
|
|
|
|
|
|
: croak "$value is wider than 32-bit"; |
1421
|
|
|
|
|
|
|
} |
1422
|
|
|
|
|
|
|
|
1423
|
|
|
|
|
|
|
#=item C<_append_mathop16_const($opcodeAX16, $opcode8, $opcode16, $opcode_reg, $reg, $immed)> |
1424
|
|
|
|
|
|
|
# |
1425
|
|
|
|
|
|
|
#=cut |
1426
|
|
|
|
|
|
|
|
1427
|
|
|
|
|
|
|
sub _append_mathop16_const { |
1428
|
392
|
|
|
392
|
|
1017
|
my ($self, @args)= @_; # $opcodeAX16, $opcode8, $opcode16, $opcode_reg, $reg, $immed |
1429
|
392
|
|
33
|
|
|
1116
|
$args[4]= $regnum16{$args[4]} // croak("$args[4] is not a 16-bit register"); |
1430
|
392
|
|
|
|
|
901
|
$self->_append_possible_unknown('_encode_mathop16_imm', \@args, 5, 8); |
1431
|
|
|
|
|
|
|
} |
1432
|
|
|
|
|
|
|
sub _encode_mathop16_imm { |
1433
|
392
|
|
|
392
|
|
853
|
my ($self, $opcodeAX16, $opcode8, $opcode16, $opcode_reg, $reg, $value)= @_; |
1434
|
17
|
|
|
17
|
|
4824
|
use integer; |
|
17
|
|
|
|
|
69
|
|
|
17
|
|
|
|
|
111
|
|
1435
|
392
|
|
|
|
|
696
|
my $rex= (($reg & 8)>>3); |
1436
|
392
|
100
|
100
|
|
|
3031
|
defined $opcode8 && (($value >> 7) == ($value >> 8) or ($value >> 8 == 0xFF))? |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1437
|
|
|
|
|
|
|
( $rex? pack('CCCCC', 0x66, 0x40|$rex, $opcode8, 0xC0 | ($opcode_reg << 3) | ($reg & 7), $value&0xFF) |
1438
|
|
|
|
|
|
|
: pack('CCCC', 0x66, $opcode8, 0xC0 | ($opcode_reg << 3) | ($reg & 7), $value&0xFF) |
1439
|
|
|
|
|
|
|
) |
1440
|
|
|
|
|
|
|
: (($value >> 16) == ($value >> 17))? ( |
1441
|
|
|
|
|
|
|
# Ops on AX get encoded as a special instruction |
1442
|
|
|
|
|
|
|
$rex? pack('CCCCv', 0x66, 0x40|$rex, $opcode16, 0xC0 | ($opcode_reg << 3) | ($reg & 7), $value&0xFFFF) |
1443
|
|
|
|
|
|
|
: $reg? pack('CCCv', 0x66, $opcode16, 0xC0 | ($opcode_reg << 3) | ($reg & 7), $value&0xFFFF) |
1444
|
|
|
|
|
|
|
: pack('CCv', 0x66, $opcodeAX16, $value) |
1445
|
|
|
|
|
|
|
) |
1446
|
|
|
|
|
|
|
: croak "$value is wider than 16-bit"; |
1447
|
|
|
|
|
|
|
} |
1448
|
|
|
|
|
|
|
|
1449
|
|
|
|
|
|
|
#=item C<_append_mathop8_const($opcodeAX8, $opcode8, $opcode_reg, $reg, $immed)> |
1450
|
|
|
|
|
|
|
# |
1451
|
|
|
|
|
|
|
#On the upside, this one only has one bit width, so the length of the instruction is known even if |
1452
|
|
|
|
|
|
|
#the immediate value isn't. |
1453
|
|
|
|
|
|
|
# |
1454
|
|
|
|
|
|
|
#However, we also have to handle the case where "dil", "sil", etc need a REX prefix but AH, BH, etc |
1455
|
|
|
|
|
|
|
#can't have one. |
1456
|
|
|
|
|
|
|
# |
1457
|
|
|
|
|
|
|
#=back |
1458
|
|
|
|
|
|
|
# |
1459
|
|
|
|
|
|
|
#=cut |
1460
|
|
|
|
|
|
|
|
1461
|
|
|
|
|
|
|
sub _append_mathop8_const { |
1462
|
280
|
|
|
280
|
|
706
|
my ($self, $opcodeAX8, $opcode8, $opcode_reg, $reg, $immed)= @_; |
1463
|
17
|
|
|
17
|
|
3408
|
use integer; |
|
17
|
|
|
|
|
68
|
|
|
17
|
|
|
|
|
105
|
|
1464
|
280
|
|
|
|
|
571
|
$reg= $regnum8{$reg}; |
1465
|
280
|
50
|
|
|
|
600
|
my $value= ref $immed? 0x00 : $immed; |
1466
|
280
|
50
|
|
|
|
751
|
(($value >> 8) == ($value >> 9)) or croak "$value is wider than 8 bits"; |
1467
|
280
|
50
|
|
|
|
790
|
if (!defined $reg) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1468
|
0
|
|
0
|
|
|
0
|
$reg= $regnum8_high{$_[1]} // croak("$reg is not a 8-bit register"); |
1469
|
0
|
|
|
|
|
0
|
$self->{_buf} .= pack('CCC', $opcode8, 0xC0 | ($opcode_reg<<3) | ($reg & 7), $value&0xFF); |
1470
|
|
|
|
|
|
|
} elsif (!$reg) { |
1471
|
40
|
|
|
|
|
192
|
$self->{_buf} .= pack('CC', $opcodeAX8, $value&0xFF); |
1472
|
|
|
|
|
|
|
} elsif ($reg > 3) { |
1473
|
200
|
|
|
|
|
791
|
$self->{_buf} .= pack('CCCC', 0x40|(($reg & 8)>>3), $opcode8, 0xC0 | ($opcode_reg << 3) | ($reg & 7), $value&0xFF); |
1474
|
|
|
|
|
|
|
} else { |
1475
|
40
|
|
|
|
|
169
|
$self->{_buf} .= pack('CCC', $opcode8, 0xC0 | ($opcode_reg << 3) | ($reg & 7), $value&0xFF); |
1476
|
|
|
|
|
|
|
} |
1477
|
280
|
50
|
|
|
|
659
|
$self->_mark_unresolved(-1, encode => '_repack', bits => 8, value => $immed) |
1478
|
|
|
|
|
|
|
if ref $immed; |
1479
|
280
|
|
|
|
|
675
|
$self; |
1480
|
|
|
|
|
|
|
} |
1481
|
|
|
|
|
|
|
|
1482
|
|
|
|
|
|
|
sub _append_mathop64_const_to_mem { |
1483
|
4032
|
|
|
4032
|
|
8679
|
my ($self, $opcode8, $opcode32, $opcode_reg, $value, $mem)= @_; |
1484
|
4032
|
|
|
|
|
8236
|
my ($base_reg, $disp, $index_reg, $scale)= @$mem; |
1485
|
4032
|
100
|
33
|
|
|
11992
|
$base_reg= ($regnum64{$base_reg} // croak "$base_reg is not a 64-bit register") |
1486
|
|
|
|
|
|
|
if defined $base_reg; |
1487
|
4032
|
100
|
33
|
|
|
10544
|
$index_reg= ($regnum64{$index_reg} // croak "$index_reg is not a 64-bit register") |
1488
|
|
|
|
|
|
|
if defined $index_reg; |
1489
|
4032
|
50
|
|
|
|
14828
|
$self->_append_possible_unknown('_encode_mathop64_mem_immed', [ $opcode8, $opcode32, $opcode_reg, $value, $base_reg, $disp, $index_reg, $scale ], 3, defined $disp? 9:12); |
1490
|
|
|
|
|
|
|
} |
1491
|
|
|
|
|
|
|
sub _encode_mathop64_mem_immed { |
1492
|
4032
|
|
|
4032
|
|
8746
|
my ($self, $opcode8, $opcode32, $opcode_reg, $value, $base_reg, $disp, $index_reg, $scale)= @_; |
1493
|
17
|
|
|
17
|
|
6956
|
use integer; |
|
17
|
|
|
|
|
40
|
|
|
17
|
|
|
|
|
69
|
|
1494
|
4032
|
50
|
100
|
|
|
19153
|
defined $opcode8 && (($value >> 7) == ($value >> 8))? |
|
|
100
|
|
|
|
|
|
1495
|
|
|
|
|
|
|
$self->_encode_op_reg_mem(8, $opcode8, $opcode_reg, $base_reg, $disp, $index_reg, $scale, 'C', $value&0xFF) |
1496
|
|
|
|
|
|
|
: (($value >> 31) == ($value >> 31 >> 1))? |
1497
|
|
|
|
|
|
|
$self->_encode_op_reg_mem(8, $opcode32, $opcode_reg, $base_reg, $disp, $index_reg, $scale, 'V', $value&0xFFFFFFFF) |
1498
|
|
|
|
|
|
|
: croak "$value is wider than 31-bit"; |
1499
|
|
|
|
|
|
|
} |
1500
|
|
|
|
|
|
|
|
1501
|
|
|
|
|
|
|
sub _append_mathop32_const_to_mem { |
1502
|
4032
|
|
|
4032
|
|
8658
|
my ($self, $opcode8, $opcode32, $opcode_reg, $value, $mem)= @_; |
1503
|
4032
|
|
|
|
|
8117
|
my ($base_reg, $disp, $index_reg, $scale)= @$mem; |
1504
|
4032
|
100
|
33
|
|
|
11925
|
$base_reg= ($regnum64{$base_reg} // croak "$base_reg is not a 64-bit register") |
1505
|
|
|
|
|
|
|
if defined $base_reg; |
1506
|
4032
|
100
|
33
|
|
|
10285
|
$index_reg= ($regnum64{$index_reg} // croak "$index_reg is not a 64-bit register") |
1507
|
|
|
|
|
|
|
if defined $index_reg; |
1508
|
4032
|
50
|
|
|
|
14976
|
$self->_append_possible_unknown('_encode_mathop32_mem_immed', [ $opcode8, $opcode32, $opcode_reg, $value, $base_reg, $disp, $index_reg, $scale ], 3, defined $disp? 12:8); |
1509
|
|
|
|
|
|
|
} |
1510
|
|
|
|
|
|
|
sub _encode_mathop32_mem_immed { |
1511
|
4032
|
|
|
4032
|
|
8660
|
my ($self, $opcode8, $opcode32, $opcode_reg, $value, $base_reg, $disp, $index_reg, $scale)= @_; |
1512
|
17
|
|
|
17
|
|
4592
|
use integer; |
|
17
|
|
|
|
|
41
|
|
|
17
|
|
|
|
|
73
|
|
1513
|
4032
|
50
|
100
|
|
|
20267
|
defined $opcode8 && (($value >> 7) == ($value >> 8) or ($value >> 8 == 0xFFFFFF))? |
|
|
100
|
|
|
|
|
|
1514
|
|
|
|
|
|
|
$self->_encode_op_reg_mem(0, $opcode8, $opcode_reg, $base_reg, $disp, $index_reg, $scale).pack('C',$value&0xFF) |
1515
|
|
|
|
|
|
|
: (($value >> 30 >> 2) == ($value >> 30 >> 3))? |
1516
|
|
|
|
|
|
|
$self->_encode_op_reg_mem(0, $opcode32, $opcode_reg, $base_reg, $disp, $index_reg, $scale).pack('V', $value&0xFFFFFFFF) |
1517
|
|
|
|
|
|
|
: croak "$value is wider than 32-bit"; |
1518
|
|
|
|
|
|
|
} |
1519
|
|
|
|
|
|
|
|
1520
|
|
|
|
|
|
|
sub _append_mathop16_const_to_mem { |
1521
|
3528
|
|
|
3528
|
|
7363
|
my ($self, $opcode8, $opcode16, $opcode_reg, $value, $mem)= @_; |
1522
|
3528
|
|
|
|
|
6989
|
my ($base_reg, $disp, $index_reg, $scale)= @$mem; |
1523
|
3528
|
100
|
33
|
|
|
10365
|
$base_reg= ($regnum64{$base_reg} // croak "$base_reg is not a 64-bit register") |
1524
|
|
|
|
|
|
|
if defined $base_reg; |
1525
|
3528
|
100
|
33
|
|
|
9094
|
$index_reg= ($regnum64{$index_reg} // croak "$index_reg is not a 64-bit register") |
1526
|
|
|
|
|
|
|
if defined $index_reg; |
1527
|
3528
|
|
|
|
|
7265
|
$self->{_buf} .= "\x66"; |
1528
|
3528
|
50
|
|
|
|
13521
|
$self->_append_possible_unknown('_encode_mathop16_mem_immed', [ $opcode8, $opcode16, $opcode_reg, $value, $base_reg, $disp, $index_reg, $scale ], 3, defined $disp? 10:6); |
1529
|
|
|
|
|
|
|
} |
1530
|
|
|
|
|
|
|
sub _encode_mathop16_mem_immed { |
1531
|
3528
|
|
|
3528
|
|
7779
|
my ($self, $opcode8, $opcode16, $opcode_reg, $value, $base_reg, $disp, $index_reg, $scale)= @_; |
1532
|
17
|
|
|
17
|
|
4732
|
use integer; |
|
17
|
|
|
|
|
50
|
|
|
17
|
|
|
|
|
77
|
|
1533
|
3528
|
50
|
100
|
|
|
18325
|
defined $opcode8 && (($value >> 7) == ($value >> 8) or ($value >> 8 == 0xFF))? |
|
|
100
|
|
|
|
|
|
1534
|
|
|
|
|
|
|
$self->_encode_op_reg_mem(0, $opcode8, $opcode_reg, $base_reg, $disp, $index_reg, $scale).pack('C',$value&0xFF) |
1535
|
|
|
|
|
|
|
: (($value >> 16) == ($value >> 17))? |
1536
|
|
|
|
|
|
|
$self->_encode_op_reg_mem(0, $opcode16, $opcode_reg, $base_reg, $disp, $index_reg, $scale).pack('v', $value&0xFFFF) |
1537
|
|
|
|
|
|
|
: croak "$value is wider than 16-bit"; |
1538
|
|
|
|
|
|
|
} |
1539
|
|
|
|
|
|
|
|
1540
|
|
|
|
|
|
|
sub _append_mathop8_const_to_mem { |
1541
|
2520
|
|
|
2520
|
|
5282
|
my ($self, $opcode8, $opcode_reg, $value, $mem)= @_; |
1542
|
2520
|
|
|
|
|
5101
|
my ($base_reg, $disp, $index_reg, $scale)= @$mem; |
1543
|
2520
|
100
|
33
|
|
|
7511
|
$base_reg= ($regnum64{$base_reg} // croak "$base_reg is not a 64-bit register") |
1544
|
|
|
|
|
|
|
if defined $base_reg; |
1545
|
2520
|
100
|
33
|
|
|
6550
|
$index_reg= ($regnum64{$index_reg} // croak "$index_reg is not a 64-bit register") |
1546
|
|
|
|
|
|
|
if defined $index_reg; |
1547
|
2520
|
50
|
|
|
|
9158
|
$self->_append_possible_unknown('_encode_mathop8_mem_immed', [ $opcode8, $opcode_reg, $value, $base_reg, $disp, $index_reg, $scale ], 2, defined $disp? 10:6); |
1548
|
|
|
|
|
|
|
} |
1549
|
|
|
|
|
|
|
sub _encode_mathop8_mem_immed { |
1550
|
2520
|
|
|
2520
|
|
5361
|
my ($self, $opcode8, $opcode_reg, $value, $base_reg, $disp, $index_reg, $scale)= @_; |
1551
|
17
|
|
|
17
|
|
4715
|
use integer; |
|
17
|
|
|
|
|
36
|
|
|
17
|
|
|
|
|
88
|
|
1552
|
2520
|
50
|
|
|
|
5876
|
(($value >> 8) == ($value >> 9)) or croak "$value is wider than 8 bit"; |
1553
|
2520
|
|
|
|
|
5459
|
$self->_encode_op_reg_mem(0, $opcode8, $opcode_reg, $base_reg, $disp, $index_reg, $scale).pack('C',$value&0xFF); |
1554
|
|
|
|
|
|
|
} |
1555
|
|
|
|
|
|
|
|
1556
|
|
|
|
|
|
|
#=head2 C<_append_shiftop_reg_imm( $bitwidth, $opcode_1, $opcode_imm, $opreg, $reg, $immed )> |
1557
|
|
|
|
|
|
|
# |
1558
|
|
|
|
|
|
|
#Shift instructions often have a special case for shifting by 1. This utility method |
1559
|
|
|
|
|
|
|
#selects that opcode if the immediate value is 1. |
1560
|
|
|
|
|
|
|
# |
1561
|
|
|
|
|
|
|
#It also allows the immediate to be an expression, though I doubt that will ever happen... |
1562
|
|
|
|
|
|
|
#Immediate values are always a single byte, and the processor masks them to 0..63 |
1563
|
|
|
|
|
|
|
#so the upper bits are irrelevant. |
1564
|
|
|
|
|
|
|
# |
1565
|
|
|
|
|
|
|
#=cut |
1566
|
|
|
|
|
|
|
|
1567
|
|
|
|
|
|
|
sub _append_shiftop_reg_imm { |
1568
|
732
|
|
|
732
|
|
1595
|
my ($self, $bits, $opcode_sh1, $opcode_imm, $opreg, $reg, $immed)= @_; |
1569
|
|
|
|
|
|
|
|
1570
|
|
|
|
|
|
|
# Select appropriate opcode |
1571
|
732
|
100
|
|
|
|
1581
|
my $op= $immed eq 1? $opcode_sh1 : $opcode_imm; |
1572
|
|
|
|
|
|
|
|
1573
|
732
|
100
|
|
|
|
2473
|
$bits == 64? $self->_append_op64_reg_reg($op, $opreg, $reg) |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1574
|
|
|
|
|
|
|
: $bits == 32? $self->_append_op32_reg_reg($op, $opreg, $reg) |
1575
|
|
|
|
|
|
|
: $bits == 16? $self->_append_op16_reg_reg($op, $opreg, $reg) |
1576
|
|
|
|
|
|
|
: $self->_append_op8_opreg_reg($op, $opreg, $reg); |
1577
|
|
|
|
|
|
|
|
1578
|
|
|
|
|
|
|
# If not using the shift-one opcode, append an immediate byte. |
1579
|
732
|
100
|
|
|
|
1582
|
unless ($immed eq 1) { |
1580
|
636
|
50
|
|
|
|
1503
|
$self->{_buf} .= pack('C', ref $immed? 0 : $immed); |
1581
|
636
|
50
|
|
|
|
1315
|
$self->_mark_unresolved(-1, encode => '_repack', bits => 8, value => $immed) |
1582
|
|
|
|
|
|
|
if ref $immed; |
1583
|
|
|
|
|
|
|
} |
1584
|
|
|
|
|
|
|
|
1585
|
732
|
|
|
|
|
1647
|
$self; |
1586
|
|
|
|
|
|
|
} |
1587
|
|
|
|
|
|
|
|
1588
|
|
|
|
|
|
|
#=head2 _append_shiftop_mem_imm |
1589
|
|
|
|
|
|
|
# |
1590
|
|
|
|
|
|
|
#Same as above, for memory locations |
1591
|
|
|
|
|
|
|
# |
1592
|
|
|
|
|
|
|
#=cut |
1593
|
|
|
|
|
|
|
|
1594
|
|
|
|
|
|
|
sub _append_shiftop_mem_imm { |
1595
|
3780
|
|
|
3780
|
|
7897
|
my ($self, $bits, $opcode_sh1, $opcode_imm, $opreg, $mem, $immed)= @_; |
1596
|
|
|
|
|
|
|
|
1597
|
|
|
|
|
|
|
# Select appropriate opcode |
1598
|
3780
|
100
|
|
|
|
7914
|
my $op= $immed eq 1? $opcode_sh1 : $opcode_imm; |
1599
|
|
|
|
|
|
|
|
1600
|
3780
|
100
|
|
|
|
13671
|
$bits == 64? $self->_append_op64_reg_mem(8, $op, $opreg, $mem) |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1601
|
|
|
|
|
|
|
: $bits == 32? $self->_append_op32_reg_mem(0, $op, $opreg, $mem) |
1602
|
|
|
|
|
|
|
: $bits == 16? $self->_append_op16_reg_mem(0, $op, $opreg, $mem) |
1603
|
|
|
|
|
|
|
: $self->_append_op8_opreg_mem(0, $op, $opreg, $mem); |
1604
|
|
|
|
|
|
|
|
1605
|
|
|
|
|
|
|
# If not using the shift-one opcode, append an immediate byte. |
1606
|
3780
|
100
|
|
|
|
9296
|
unless ($immed eq 1) { |
1607
|
3024
|
50
|
|
|
|
7457
|
$self->{_buf} .= pack('C', ref $immed? 0 : $immed); |
1608
|
3024
|
50
|
|
|
|
6287
|
$self->_mark_unresolved(-1, encode => '_repack', bits => 8, value => $immed) |
1609
|
|
|
|
|
|
|
if ref $immed; |
1610
|
|
|
|
|
|
|
} |
1611
|
|
|
|
|
|
|
|
1612
|
3780
|
|
|
|
|
9157
|
$self; |
1613
|
|
|
|
|
|
|
} |
1614
|
|
|
|
|
|
|
|
1615
|
|
|
|
|
|
|
#=head2 C<_append_jmp_cond($cond_code, $label)> |
1616
|
|
|
|
|
|
|
# |
1617
|
|
|
|
|
|
|
#Appends a conditional jump instruction, which is either the short 2-byte form for 8-bit offsets, |
1618
|
|
|
|
|
|
|
#or 6 bytes for jumps of 32-bit offsets. The implementation optimistically assumes the 2-byte |
1619
|
|
|
|
|
|
|
#length until L is called, when the actual length will be determined. |
1620
|
|
|
|
|
|
|
# |
1621
|
|
|
|
|
|
|
#Returns $self, for chaining. |
1622
|
|
|
|
|
|
|
# |
1623
|
|
|
|
|
|
|
#=cut |
1624
|
|
|
|
|
|
|
|
1625
|
|
|
|
|
|
|
sub _append_jmp_cond { |
1626
|
64
|
50
|
|
64
|
|
137
|
$_[2]= $_[0]->get_label unless defined $_[2]; |
1627
|
|
|
|
|
|
|
|
1628
|
64
|
|
|
|
|
134
|
my ($self, $cond, $label)= @_; |
1629
|
17
|
|
|
17
|
|
7219
|
use integer; |
|
17
|
|
|
|
|
55
|
|
|
17
|
|
|
|
|
80
|
|
1630
|
64
|
50
|
|
|
|
155
|
$label= $self->get_label($label) |
1631
|
|
|
|
|
|
|
unless ref $label; |
1632
|
|
|
|
|
|
|
$self->_mark_unresolved( |
1633
|
|
|
|
|
|
|
2, # estimated length |
1634
|
|
|
|
|
|
|
encode => sub { |
1635
|
160
|
|
|
160
|
|
307
|
my ($self, $params)= @_; |
1636
|
160
|
50
|
|
|
|
304
|
defined $label->{offset} or croak "Label $label is not marked"; |
1637
|
160
|
|
|
|
|
277
|
my $ofs= $label->{offset} - ($params->{offset}+$params->{len}); |
1638
|
160
|
|
|
|
|
280
|
my $short= (($ofs>>7) == ($ofs>>8)); |
1639
|
160
|
100
|
|
|
|
488
|
return $short? |
1640
|
|
|
|
|
|
|
pack('Cc', 0x70 + $cond, $ofs) |
1641
|
|
|
|
|
|
|
: pack('CCV', 0x0F, 0x80 + $cond, $ofs); |
1642
|
|
|
|
|
|
|
} |
1643
|
64
|
|
|
|
|
308
|
); |
1644
|
64
|
|
|
|
|
151
|
$self; |
1645
|
|
|
|
|
|
|
} |
1646
|
|
|
|
|
|
|
|
1647
|
|
|
|
|
|
|
#=head2 C<_append_jmp_cx($opcode, $label)> |
1648
|
|
|
|
|
|
|
# |
1649
|
|
|
|
|
|
|
#Appends one of the special CX-related jumps (like L). These can only have an 8-bit offset |
1650
|
|
|
|
|
|
|
#and are fixed-length. |
1651
|
|
|
|
|
|
|
# |
1652
|
|
|
|
|
|
|
#=cut |
1653
|
|
|
|
|
|
|
|
1654
|
|
|
|
|
|
|
sub _append_jmp_cx { |
1655
|
8
|
|
|
8
|
|
18
|
my ($self, $op, $label)= @_; |
1656
|
17
|
|
|
17
|
|
3689
|
use integer; |
|
17
|
|
|
|
|
46
|
|
|
17
|
|
|
|
|
94
|
|
1657
|
8
|
50
|
|
|
|
24
|
$label= $self->get_label($label) |
1658
|
|
|
|
|
|
|
unless ref $label; |
1659
|
|
|
|
|
|
|
$self->_mark_unresolved( |
1660
|
|
|
|
|
|
|
2, # estimated length |
1661
|
|
|
|
|
|
|
encode => sub { |
1662
|
8
|
|
|
8
|
|
26
|
my ($self, $params)= @_; |
1663
|
8
|
50
|
|
|
|
58
|
defined $label->{offset} or croak "Label $label is not marked"; |
1664
|
8
|
|
|
|
|
20
|
my $ofs= $label->{offset} - ($params->{offset}+$params->{len}); |
1665
|
8
|
50
|
|
|
|
19
|
(($ofs>>7) == ($ofs>>8)) or croak "Label too far, can only short-jump"; |
1666
|
8
|
|
|
|
|
32
|
return pack('Cc', $op, $ofs); |
1667
|
|
|
|
|
|
|
} |
1668
|
8
|
|
|
|
|
60
|
); |
1669
|
8
|
|
|
|
|
20
|
return $self; |
1670
|
|
|
|
|
|
|
} |
1671
|
|
|
|
|
|
|
|
1672
|
|
|
|
|
|
|
sub _append_possible_unknown { |
1673
|
51729
|
|
|
51729
|
|
101526
|
my ($self, $encoder, $encoder_args, $unknown_pos, $estimated_length)= @_; |
1674
|
51729
|
|
|
|
|
89675
|
my $u= $encoder_args->[$unknown_pos]; |
1675
|
51729
|
50
|
33
|
|
|
137912
|
if (ref $u && ref $u ne 'SCALAR' && !looks_like_number($u)) { |
|
|
|
33
|
|
|
|
|
1676
|
0
|
0
|
|
|
|
0
|
ref($u)->can('value') |
1677
|
|
|
|
|
|
|
or croak "Expected object with '->value' method"; |
1678
|
|
|
|
|
|
|
$self->_mark_unresolved( |
1679
|
|
|
|
|
|
|
$estimated_length, |
1680
|
|
|
|
|
|
|
encode => sub { |
1681
|
0
|
|
|
0
|
|
0
|
my $self= shift; |
1682
|
0
|
|
|
|
|
0
|
my @args= @$encoder_args; |
1683
|
0
|
|
0
|
|
|
0
|
$args[$unknown_pos]= $u->value |
1684
|
|
|
|
|
|
|
// croak "Value '$u->{name}' is still unresolved"; |
1685
|
0
|
|
|
|
|
0
|
$self->$encoder(@args); |
1686
|
|
|
|
|
|
|
}, |
1687
|
0
|
|
|
|
|
0
|
); |
1688
|
|
|
|
|
|
|
} |
1689
|
|
|
|
|
|
|
else { |
1690
|
51729
|
|
|
|
|
140113
|
$self->{_buf} .= $self->$encoder(@$encoder_args); |
1691
|
|
|
|
|
|
|
} |
1692
|
51729
|
|
|
|
|
157886
|
$self; |
1693
|
|
|
|
|
|
|
} |
1694
|
|
|
|
|
|
|
|
1695
|
|
|
|
|
|
|
#=head2 C<_mark_unresolved($location, encode => sub {...}, %other)> |
1696
|
|
|
|
|
|
|
# |
1697
|
|
|
|
|
|
|
#Creates a new unresolved marker in the instruction stream, indicating things which can't be known |
1698
|
|
|
|
|
|
|
#until the entire instruction stream is written. (such as jump instructions). |
1699
|
|
|
|
|
|
|
# |
1700
|
|
|
|
|
|
|
#The parameters 'offset' and 'len' will be filled in automatically based on the $location parameter. |
1701
|
|
|
|
|
|
|
#If C<$location> is negative, it indicates offset is that many bytes backward from the end of the |
1702
|
|
|
|
|
|
|
#buffer. If C<$location> is positive, it means the unresolved symbol hasn't been written yet and |
1703
|
|
|
|
|
|
|
#the 'offset' will be the current end of the buffer and 'len' is the value of $location. |
1704
|
|
|
|
|
|
|
# |
1705
|
|
|
|
|
|
|
#The other usual (but not required) parameter is 'encode'. This references a method callback which |
1706
|
|
|
|
|
|
|
#will return the encoded instruction (or die, if there is still not enough information to do so). |
1707
|
|
|
|
|
|
|
# |
1708
|
|
|
|
|
|
|
#All C<%other> parameters are passed to the callback as a HASHREF. |
1709
|
|
|
|
|
|
|
# |
1710
|
|
|
|
|
|
|
#=cut |
1711
|
|
|
|
|
|
|
|
1712
|
|
|
|
|
|
|
sub _mark_unresolved { |
1713
|
90
|
|
|
90
|
|
181
|
my ($self, $location)= (shift, shift); |
1714
|
90
|
|
|
|
|
154
|
my $offset= length($self->{_buf}); |
1715
|
|
|
|
|
|
|
|
1716
|
|
|
|
|
|
|
# If location is negative, move the 'offset' back that many bytes. |
1717
|
|
|
|
|
|
|
# The length is the abs of location. |
1718
|
90
|
50
|
|
|
|
193
|
if ($location < 0) { |
1719
|
0
|
|
|
|
|
0
|
$location= -$location; |
1720
|
0
|
|
|
|
|
0
|
$offset -= $location; |
1721
|
|
|
|
|
|
|
} |
1722
|
|
|
|
|
|
|
# If the location is positive, offset is the end of the string. |
1723
|
|
|
|
|
|
|
# Add padding bytes for the length of the instruction. |
1724
|
|
|
|
|
|
|
else { |
1725
|
90
|
|
|
|
|
216
|
$self->{_buf} .= "\0" x $location; |
1726
|
|
|
|
|
|
|
} |
1727
|
|
|
|
|
|
|
|
1728
|
90
|
50
|
|
|
|
204
|
if ($self->{debug}) { |
1729
|
0
|
|
|
|
|
0
|
my ($i, @caller); |
1730
|
|
|
|
|
|
|
# Walk up stack until the entry-point method |
1731
|
0
|
|
|
|
|
0
|
while (@caller= caller(++$i)) { |
1732
|
0
|
0
|
|
|
|
0
|
last if $caller[0] ne __PACKAGE__; |
1733
|
|
|
|
|
|
|
} |
1734
|
0
|
|
|
|
|
0
|
push @_, caller => \@caller; |
1735
|
|
|
|
|
|
|
} |
1736
|
|
|
|
|
|
|
#print "Unresolved at $offset ($location)\n"; |
1737
|
90
|
|
|
|
|
132
|
push @{ $self->_unresolved }, { offset => $offset, len => $location, @_ }; |
|
90
|
|
|
|
|
352
|
|
1738
|
|
|
|
|
|
|
} |
1739
|
|
|
|
|
|
|
|
1740
|
|
|
|
|
|
|
sub _repack { |
1741
|
0
|
|
|
0
|
|
0
|
my ($self, $params)= @_; |
1742
|
17
|
|
|
17
|
|
9908
|
use integer; |
|
17
|
|
|
|
|
54
|
|
|
17
|
|
|
|
|
105
|
|
1743
|
0
|
|
|
|
|
0
|
my $v= $params->{value}->value; |
1744
|
0
|
0
|
|
|
|
0
|
defined $v or croak "Placeholder $params->{value} has not been assigned"; |
1745
|
0
|
|
|
|
|
0
|
my $bits= $params->{bits}; |
1746
|
0
|
0
|
|
|
|
0
|
my $pack= $bits <= 8? 'C' : $bits <= 16? 'v' : $bits <= 32? 'V' : $bits <= 64? 'Q<' : die "Unhandled bits $bits\n"; |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
1747
|
0
|
0
|
0
|
|
|
0
|
$bits == 64 || (($v >> $bits) == ($v >> ($bits+1))) or croak "$v is wider than $bits bits"; |
1748
|
0
|
|
|
|
|
0
|
return pack($pack, $v & ~(~0 << $bits)); |
1749
|
|
|
|
|
|
|
} |
1750
|
|
|
|
|
|
|
|
1751
|
|
|
|
|
|
|
#=head2 C<_resovle> |
1752
|
|
|
|
|
|
|
# |
1753
|
|
|
|
|
|
|
#This is the algorithm that resolves the unresolved instructions. It takes an iterative approach |
1754
|
|
|
|
|
|
|
#that is relatively efficient as long as the predicted lengths of the unresolved instructions are |
1755
|
|
|
|
|
|
|
#correct. If many instructions guess the wrong length then this could get slow for very long |
1756
|
|
|
|
|
|
|
#instruction strings. |
1757
|
|
|
|
|
|
|
# |
1758
|
|
|
|
|
|
|
#=cut |
1759
|
|
|
|
|
|
|
|
1760
|
|
|
|
|
|
|
sub _resolve { |
1761
|
54830
|
|
|
54830
|
|
80661
|
my $self= shift; |
1762
|
|
|
|
|
|
|
|
1763
|
|
|
|
|
|
|
# We repeat the process any time something changed length |
1764
|
54830
|
|
|
|
|
81800
|
my $changed_len= 1; |
1765
|
54830
|
|
|
|
|
113338
|
while ($changed_len) { |
1766
|
54874
|
|
|
|
|
81039
|
$changed_len= 0; |
1767
|
|
|
|
|
|
|
|
1768
|
|
|
|
|
|
|
# Track the amount we have shifted the current instruction in $ofs |
1769
|
54874
|
|
|
|
|
78225
|
my $ofs= 0; |
1770
|
54874
|
|
|
|
|
81552
|
for my $p (@{ $self->_unresolved }) { |
|
54874
|
|
|
|
|
187396
|
|
1771
|
|
|
|
|
|
|
#print "Shifting $p by $ofs\n" if $ofs; |
1772
|
343
|
100
|
|
|
|
610
|
$p->{offset} += $ofs if $ofs; |
1773
|
|
|
|
|
|
|
|
1774
|
|
|
|
|
|
|
# Ignore things without an 'encode' callback (like labels) |
1775
|
|
|
|
|
|
|
my $fn= $p->{encode} |
1776
|
343
|
100
|
|
|
|
744
|
or next; |
1777
|
|
|
|
|
|
|
|
1778
|
|
|
|
|
|
|
# Get new encoding, then replace those bytes in the instruction string |
1779
|
214
|
|
|
|
|
322
|
eval { |
1780
|
214
|
|
|
|
|
384
|
my $enc= $self->$fn($p); |
1781
|
214
|
|
|
|
|
478
|
substr($self->{_buf}, $p->{offset}, $p->{len})= $enc; |
1782
|
|
|
|
|
|
|
|
1783
|
|
|
|
|
|
|
# If the length changed, update $ofs and current ->len |
1784
|
214
|
100
|
|
|
|
465
|
if (length($enc) != $p->{len}) { |
1785
|
|
|
|
|
|
|
#print "New size is ".length($enc)."\n"; |
1786
|
44
|
|
|
|
|
67
|
$changed_len= 1; |
1787
|
44
|
|
|
|
|
82
|
$ofs += (length($enc) - $p->{len}); |
1788
|
44
|
|
|
|
|
76
|
$p->{len}= length($enc); |
1789
|
|
|
|
|
|
|
} |
1790
|
|
|
|
|
|
|
}; |
1791
|
214
|
50
|
|
|
|
510
|
if ($@) { |
1792
|
0
|
0
|
|
|
|
|
if ($p->{caller}) { |
1793
|
0
|
|
|
|
|
|
croak "Failed to encode instruction $p->{caller}[3] from $p->{caller}[1] line $p->{caller}[2]:\n $@"; |
1794
|
|
|
|
|
|
|
} else { |
1795
|
0
|
|
|
|
|
|
croak "Failed to encode instruction (enable diagnostics with ->debug(1) ): $@"; |
1796
|
|
|
|
|
|
|
} |
1797
|
|
|
|
|
|
|
} |
1798
|
|
|
|
|
|
|
} |
1799
|
|
|
|
|
|
|
} |
1800
|
|
|
|
|
|
|
} |
1801
|
|
|
|
|
|
|
|
1802
|
|
|
|
|
|
|
1; |
1803
|
|
|
|
|
|
|
|
1804
|
|
|
|
|
|
|
__END__ |