line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package CPU::x86_64::InstructionWriter; |
2
|
|
|
|
|
|
|
$CPU::x86_64::InstructionWriter::VERSION = '0.000_002'; # TRIAL |
3
|
|
|
|
|
|
|
|
4
|
14
|
|
|
14
|
|
446212
|
$CPU::x86_64::InstructionWriter::VERSION = '0.000002';use v5.10; |
|
14
|
|
|
|
|
32
|
|
5
|
14
|
|
|
14
|
|
6173
|
use Moo 2; |
|
14
|
|
|
|
|
128641
|
|
|
14
|
|
|
|
|
56
|
|
6
|
14
|
|
|
14
|
|
13682
|
use Carp; |
|
14
|
|
|
|
|
20
|
|
|
14
|
|
|
|
|
600
|
|
7
|
14
|
|
|
14
|
|
44
|
use Exporter 'import'; |
|
14
|
|
|
|
|
15
|
|
|
14
|
|
|
|
|
256
|
|
8
|
14
|
|
|
14
|
|
4711
|
use CPU::x86_64::InstructionWriter::Unknown; |
|
14
|
|
|
|
|
104
|
|
|
14
|
|
|
|
|
623
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
# ABSTRACT: Assemble x86-64 instructions using a pure-perl API |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
(0x7FFFFFFE << 31) > 0 && (0x7FFFFFFE << 63) == 0 |
14
|
|
|
|
|
|
|
or die "Author is lazy and requires 64-bit perl integers\n"; |
15
|
14
|
|
|
14
|
|
63
|
no warnings 'portable'; |
|
14
|
|
|
|
|
11
|
|
|
14
|
|
|
|
|
1540
|
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
my @byte_registers= qw( AH AL BH BL CH CL DH DL SPL BPL SIL DIL R8B R9B R10B R11B R12B R13B R14B R15B ); |
18
|
|
|
|
|
|
|
my %byte_register_alias= ( map {; "R${_}L" => "R${_}B" } 8..15 ); |
19
|
|
|
|
|
|
|
my @word_registers= qw( AX BX CX DX SI DI SP BP R8W R9W R10W R11W R12W R13W R14W R15W ); |
20
|
|
|
|
|
|
|
my @long_registers= qw( EAX EBX ECX EDX ESI EDI ESP EBP R8D R9D R10D R11D R12D R13D R14D R15D ); |
21
|
|
|
|
|
|
|
my @quad_registers= qw( RAX RBX RCX RDX RSI RDI RSP RBP R8 R9 R10 R11 R12 R13 R14 R15 RIP RFLAGS ); |
22
|
|
|
|
|
|
|
my @registers= ( @byte_registers, @word_registers, @long_registers, @quad_registers ); |
23
|
|
|
|
|
|
|
{ |
24
|
|
|
|
|
|
|
# Create a constant for each register name |
25
|
14
|
|
|
14
|
|
56
|
no strict 'refs'; |
|
14
|
|
|
|
|
13
|
|
|
14
|
|
|
|
|
11151
|
|
26
|
|
|
|
|
|
|
eval 'sub '.$_.' { \''.$_.'\' } 1' || croak $@ |
27
|
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
|
|
28
|
|
|
|
|
|
|
*{__PACKAGE__."::$_"}= *{__PACKAGE__."::$byte_register_alias{$_}"} |
29
|
|
|
|
|
|
|
for keys %byte_register_alias; |
30
|
|
|
|
|
|
|
} |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
# Map 64-bit register names to the numeric register number |
33
|
|
|
|
|
|
|
my %regnum64= ( |
34
|
|
|
|
|
|
|
RAX => 0, RCX => 1, RDX => 2, RBX => 3, |
35
|
|
|
|
|
|
|
rax => 0, rcx => 1, rdx => 2, rbx => 3, |
36
|
|
|
|
|
|
|
RSP => 4, RBP => 5, RSI => 6, RDI => 7, |
37
|
|
|
|
|
|
|
rsp => 4, rbp => 5, rsi => 6, rdi => 7, |
38
|
|
|
|
|
|
|
map { $_ => $_, "R$_" => $_, "r$_" => $_ } 0..15 |
39
|
|
|
|
|
|
|
); |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
my %regnum32= ( |
42
|
|
|
|
|
|
|
EAX => 0, ECX => 1, EDX => 2, EBX => 3, |
43
|
|
|
|
|
|
|
eax => 0, ecx => 1, edx => 2, ebx => 3, |
44
|
|
|
|
|
|
|
ESP => 4, EBP => 5, ESI => 6, EDI => 7, |
45
|
|
|
|
|
|
|
esp => 4, ebp => 5, esi => 6, edi => 7, |
46
|
|
|
|
|
|
|
map { $_ => $_, "R${_}D" => $_, "r${_}d" => $_ } 0..15 |
47
|
|
|
|
|
|
|
); |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
my %regnum16= ( |
50
|
|
|
|
|
|
|
AX => 0, CX => 1, DX => 2, BX => 3, |
51
|
|
|
|
|
|
|
ax => 0, cx => 1, dx => 2, bx => 3, |
52
|
|
|
|
|
|
|
SP => 4, BP => 5, SI => 6, DI => 7, |
53
|
|
|
|
|
|
|
sp => 4, bp => 5, si => 6, di => 7, |
54
|
|
|
|
|
|
|
map { $_ => $_, "R${_}W" => $_, "r${_}w" => $_ } 0..15 |
55
|
|
|
|
|
|
|
); |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
my %regnum8= ( |
58
|
|
|
|
|
|
|
AL => 0, CL => 1, DL => 2, BL => 3, |
59
|
|
|
|
|
|
|
al => 0, cl => 1, dl => 2, bl => 3, |
60
|
|
|
|
|
|
|
SPL => 4, BPL => 5, SIL => 6, DIL => 7, |
61
|
|
|
|
|
|
|
spl => 4, bpl => 5, sil => 6, dil => 7, |
62
|
|
|
|
|
|
|
map { $_ => $_, "R${_}B" => $_, "r${_}b" => $_, "R${_}L" => $_, "r${_}l" => $_ } 0..15 |
63
|
|
|
|
|
|
|
); |
64
|
|
|
|
|
|
|
my %regnum8_high= ( |
65
|
|
|
|
|
|
|
AH => 4, CH => 5, DH => 6, BH => 7, |
66
|
|
|
|
|
|
|
ah => 4, ch => 5, dh => 6, bh => 7, |
67
|
|
|
|
|
|
|
); |
68
|
|
|
|
|
|
|
|
69
|
0
|
|
|
0
|
0
|
0
|
sub unknown { CPU::x86_64::InstructionWriter::Unknown->new(name => $_[0]); } |
70
|
0
|
|
|
0
|
0
|
0
|
sub unknown8 { CPU::x86_64::InstructionWriter::Unknown->new(bits => 8, name => $_[0]); } |
71
|
0
|
|
|
0
|
0
|
0
|
sub unknown16 { CPU::x86_64::InstructionWriter::Unknown->new(bits => 16, name => $_[0]); } |
72
|
0
|
|
|
0
|
0
|
0
|
sub unknown32 { CPU::x86_64::InstructionWriter::Unknown->new(bits => 32, name => $_[0]); } |
73
|
47479
|
|
|
47479
|
0
|
590262
|
sub unknown64 { CPU::x86_64::InstructionWriter::Unknown->new(bits => 64, name => $_[0]); } |
74
|
0
|
|
|
0
|
0
|
0
|
sub unknown7 { CPU::x86_64::InstructionWriter::Unknown->new(bits => 7, name => $_[0]); } |
75
|
0
|
|
|
0
|
0
|
0
|
sub unknown15 { CPU::x86_64::InstructionWriter::Unknown->new(bits => 15, name => $_[0]); } |
76
|
0
|
|
|
0
|
0
|
0
|
sub unknown31 { CPU::x86_64::InstructionWriter::Unknown->new(bits => 31, name => $_[0]); } |
77
|
0
|
|
|
0
|
0
|
0
|
sub unknown63 { CPU::x86_64::InstructionWriter::Unknown->new(bits => 63, name => $_[0]); } |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
our %EXPORT_TAGS= ( |
80
|
|
|
|
|
|
|
registers => \@registers, |
81
|
|
|
|
|
|
|
unknown => [qw( unknown unknown8 unknown16 unknown32 unknown64 unknown7 unknown15 unknown31 unknown63 )], |
82
|
|
|
|
|
|
|
); |
83
|
|
|
|
|
|
|
our @EXPORT_OK= ( map { @{$_} } values %EXPORT_TAGS ); |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
has start_address => ( is => 'rw', default => sub { unknown64() } ); |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
has _buf => ( is => 'rw', default => sub { '' } ); |
88
|
|
|
|
|
|
|
has _unresolved => ( is => 'rw', default => sub { [] } ); |
89
|
|
|
|
|
|
|
has labels => ( is => 'rw', default => sub {; {} } ); |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
sub get_label { |
93
|
139
|
|
|
139
|
1
|
96
|
my ($self, $name)= @_; |
94
|
139
|
|
|
|
|
134
|
my $labels= $self->labels; |
95
|
139
|
100
|
66
|
|
|
409
|
unless (defined $name && defined $labels->{$name}) { |
96
|
61
|
|
|
|
|
59
|
my $label= {}; |
97
|
61
|
50
|
|
|
|
74
|
$name= "$label" unless defined $name; |
98
|
61
|
|
|
|
|
65
|
$label->{name}= $name; |
99
|
61
|
|
|
|
|
67
|
$labels->{$name}= $label; |
100
|
|
|
|
|
|
|
} |
101
|
139
|
|
|
|
|
146
|
$labels->{$name}; |
102
|
|
|
|
|
|
|
} |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
sub mark { |
106
|
61
|
50
|
|
61
|
1
|
599
|
@_ == 2 or croak "Invalid arguments to 'mark'"; |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
# If they gave an undefined label, we auto-populate it, which modifies |
109
|
|
|
|
|
|
|
# the variable they passed to this function. |
110
|
61
|
50
|
|
|
|
69
|
$_[1]= $_[0]->get_label |
111
|
|
|
|
|
|
|
unless defined $_[1]; |
112
|
|
|
|
|
|
|
|
113
|
61
|
|
|
|
|
56
|
my ($self, $label)= @_; |
114
|
|
|
|
|
|
|
# If they give a label by name, auto-inflate it |
115
|
61
|
50
|
|
|
|
95
|
$label= $self->get_label($label) |
116
|
|
|
|
|
|
|
unless ref $label; |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
# A label can only exist once |
119
|
61
|
50
|
|
|
|
95
|
defined $label->{start} and croak "Can't mark label '$label->{name}' twice"; |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
# Set the label's current location |
122
|
61
|
|
|
|
|
58
|
$label->{start}= length($self->{_buf}); |
123
|
61
|
|
|
|
|
49
|
$label->{len}= 0; |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
# Add it to the list of unresolved things, so its position can be updated |
126
|
61
|
|
|
|
|
38
|
push @{ $self->_unresolved }, $label; |
|
61
|
|
|
|
|
70
|
|
127
|
61
|
|
|
|
|
76
|
return $self; |
128
|
|
|
|
|
|
|
} |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
sub bytes { |
132
|
47496
|
|
|
47496
|
1
|
36250
|
my $self= shift; |
133
|
47496
|
|
|
|
|
55620
|
$self->_resolve; |
134
|
47496
|
|
|
|
|
163436
|
return $self->_buf; |
135
|
|
|
|
|
|
|
} |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
sub nop { |
139
|
117
|
100
|
|
117
|
1
|
249
|
$_[0]{_buf} .= (defined $_[1]? "\x90" x $_[1] : "\x90"); |
140
|
117
|
|
|
|
|
180
|
$_[0]; |
141
|
|
|
|
|
|
|
} |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
sub pause { |
144
|
0
|
0
|
|
0
|
1
|
0
|
$_[0]{_buf} .= (defined $_[1]? "\xF3\x90" x $_[1] : "\xF3\x90"); |
145
|
0
|
|
|
|
|
0
|
$_[0] |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
sub call_label { |
150
|
2
|
50
|
|
2
|
1
|
671
|
@_ == 2 or croak "Wrong arguments"; |
151
|
2
|
50
|
|
|
|
6
|
$_[1]= $_[0]->get_label |
152
|
|
|
|
|
|
|
unless defined $_[1]; |
153
|
2
|
|
|
|
|
3
|
my ($self, $label)= @_; |
154
|
14
|
|
|
14
|
|
5567
|
use integer; |
|
14
|
|
|
|
|
106
|
|
|
14
|
|
|
|
|
47
|
|
155
|
2
|
50
|
|
|
|
7
|
$label= $self->get_label($label) |
156
|
|
|
|
|
|
|
unless ref $label; |
157
|
|
|
|
|
|
|
$self->_mark_unresolved( |
158
|
|
|
|
|
|
|
5, # estimated length |
159
|
|
|
|
|
|
|
encode => sub { |
160
|
2
|
|
|
2
|
|
2
|
my ($self, $params)= @_; |
161
|
2
|
50
|
|
|
|
4
|
defined $label->{start} or croak "Label $label is not marked"; |
162
|
2
|
|
|
|
|
4
|
my $ofs= $label->{start} - ($params->{start}+$params->{len}); |
163
|
2
|
50
|
|
|
|
4
|
($ofs >> 31) == ($ofs >> 32) or croak "Offset must be within 31 bits"; |
164
|
2
|
|
|
|
|
13
|
return pack('CV', 0xE8, $ofs); |
165
|
|
|
|
|
|
|
} |
166
|
2
|
|
|
|
|
10
|
); |
167
|
2
|
|
|
|
|
5
|
$self; |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
sub call_rel { |
171
|
0
|
|
|
0
|
1
|
0
|
my ($self, $immed)= @_; |
172
|
0
|
0
|
|
|
|
0
|
$self->{_buf} .= pack('CV', 0xE8, ref $immed? 0 : $immed); |
173
|
0
|
0
|
|
|
|
0
|
$self->_mark_unresolved(-4, encode => '_repack', bits => 32, value => $immed) |
174
|
|
|
|
|
|
|
if ref $immed; |
175
|
0
|
|
|
|
|
0
|
$self; |
176
|
|
|
|
|
|
|
} |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
sub call_abs_reg { |
179
|
7
|
|
|
7
|
1
|
157
|
my ($self, $reg)= @_; |
180
|
|
|
|
|
|
|
$self->{_buf} .= $self->_encode_op_reg_reg(0, 0xFF, 2, |
181
|
7
|
|
33
|
|
|
22
|
$regnum64{$reg} // croak("$reg is not a 64-bit register"), |
182
|
|
|
|
|
|
|
); |
183
|
7
|
|
|
|
|
12
|
$self; |
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
|
186
|
63
|
|
|
63
|
1
|
1496
|
sub call_abs_mem { $_[0]->_append_op64_reg_mem(0, 0xFF, 2, $_[1]) } |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
sub ret { |
190
|
3
|
|
|
3
|
0
|
73
|
my ($self, $pop_bytes)= @_; |
191
|
3
|
100
|
|
|
|
5
|
if ($pop_bytes) { |
192
|
2
|
50
|
|
|
|
10
|
$self->{_buf} .= pack('Cv', 0xC2, ref $pop_bytes? 0 : $pop_bytes); |
193
|
2
|
50
|
|
|
|
4
|
$self->_mark_unresolved(-2, encode => '_repack', bits => 16, value => $pop_bytes) |
194
|
|
|
|
|
|
|
if ref $pop_bytes; |
195
|
|
|
|
|
|
|
} |
196
|
|
|
|
|
|
|
else { |
197
|
1
|
|
|
|
|
2
|
$self->{_buf} .= "\xC3"; |
198
|
|
|
|
|
|
|
} |
199
|
3
|
|
|
|
|
6
|
$self; |
200
|
|
|
|
|
|
|
} |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
sub jmp { |
204
|
4
|
50
|
|
4
|
1
|
671
|
@_ == 2 or croak "Wrong arguments"; |
205
|
4
|
50
|
|
|
|
10
|
$_[1]= $_[0]->get_label |
206
|
|
|
|
|
|
|
unless defined $_[1]; |
207
|
4
|
|
|
|
|
5
|
my ($self, $label)= @_; |
208
|
14
|
|
|
14
|
|
4349
|
use integer; |
|
14
|
|
|
|
|
21
|
|
|
14
|
|
|
|
|
34
|
|
209
|
4
|
50
|
|
|
|
9
|
$label= $self->get_label($label) |
210
|
|
|
|
|
|
|
unless ref $label; |
211
|
|
|
|
|
|
|
$self->_mark_unresolved( |
212
|
|
|
|
|
|
|
2, # estimated length |
213
|
|
|
|
|
|
|
encode => sub { |
214
|
8
|
|
|
8
|
|
5
|
my ($self, $params)= @_; |
215
|
8
|
50
|
|
|
|
11
|
defined $label->{start} or croak "Label $label is not marked"; |
216
|
8
|
|
|
|
|
9
|
my $ofs= $label->{start} - ($params->{start}+$params->{len}); |
217
|
8
|
|
|
|
|
9
|
my $short= (($ofs>>7) == ($ofs>>8)); |
218
|
8
|
100
|
|
|
|
25
|
return $short? |
219
|
|
|
|
|
|
|
pack('Cc', 0xEB, $ofs) |
220
|
|
|
|
|
|
|
: pack('CV', 0xE9, $ofs); |
221
|
|
|
|
|
|
|
} |
222
|
4
|
|
|
|
|
13
|
); |
223
|
4
|
|
|
|
|
9
|
$self; |
224
|
|
|
|
|
|
|
} |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
sub jmp_abs_reg { |
228
|
7
|
|
|
7
|
1
|
183
|
my ($self, $reg)= @_; |
229
|
|
|
|
|
|
|
$self->{_buf} .= $self->_encode_op_reg_reg(0, 0xFF, 4, |
230
|
7
|
|
33
|
|
|
23
|
$regnum64{$reg} // croak("$reg is not a 64-bit register"), |
231
|
|
|
|
|
|
|
); |
232
|
7
|
|
|
|
|
12
|
$self; |
233
|
|
|
|
|
|
|
} |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
sub jmp_abs_mem { |
237
|
63
|
|
|
63
|
1
|
1515
|
$_[0]->_append_op64_reg_mem(0, 0xFF, 4, $_[1]); |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
|
241
|
4
|
|
|
4
|
1
|
37
|
sub jmp_if_eq { shift->_append_jmp_cond(4, shift) } |
242
|
|
|
|
|
|
|
*jz= *jmp_if_eq; |
243
|
|
|
|
|
|
|
*je= *jmp_if_eq; |
244
|
|
|
|
|
|
|
|
245
|
4
|
|
|
4
|
1
|
37
|
sub jmp_if_ne { shift->_append_jmp_cond(5, shift) } |
246
|
|
|
|
|
|
|
*jne= *jmp_if_ne; |
247
|
|
|
|
|
|
|
*jnz= *jmp_if_ne; |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
|
250
|
4
|
|
|
4
|
1
|
40
|
sub jmp_if_unsigned_lt { shift->_append_jmp_cond(2, shift) } |
251
|
|
|
|
|
|
|
*jb= *jmp_if_unsigned_lt; |
252
|
|
|
|
|
|
|
*jc= *jmp_if_unsigned_lt; |
253
|
|
|
|
|
|
|
|
254
|
4
|
|
|
4
|
1
|
36
|
sub jmp_if_unsigned_gt { shift->_append_jmp_cond(7, shift) } |
255
|
|
|
|
|
|
|
*ja= *jmp_if_unsigned_gt; |
256
|
|
|
|
|
|
|
|
257
|
4
|
|
|
4
|
1
|
36
|
sub jmp_if_unsigned_le { shift->_append_jmp_cond(6, shift) } |
258
|
|
|
|
|
|
|
*jbe= *jmp_if_unsigned_le; |
259
|
|
|
|
|
|
|
|
260
|
4
|
|
|
4
|
1
|
34
|
sub jmp_if_unsigned_ge { shift->_append_jmp_cond(3, shift) } |
261
|
|
|
|
|
|
|
*jae= *jmp_if_unsigned_ge; |
262
|
|
|
|
|
|
|
*jnc= *jmp_if_unsigned_ge; |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
|
265
|
4
|
|
|
4
|
1
|
35
|
sub jmp_if_signed_lt { shift->_append_jmp_cond(12, shift) } |
266
|
|
|
|
|
|
|
*jl= *jmp_if_signed_lt; |
267
|
|
|
|
|
|
|
|
268
|
4
|
|
|
4
|
1
|
33
|
sub jmp_if_signed_gt { shift->_append_jmp_cond(15, shift) } |
269
|
|
|
|
|
|
|
*jg= *jmp_if_signed_gt; |
270
|
|
|
|
|
|
|
|
271
|
4
|
|
|
4
|
1
|
33
|
sub jmp_if_signed_le { shift->_append_jmp_cond(14, shift) } |
272
|
|
|
|
|
|
|
*jle= *jmp_if_signed_le; |
273
|
|
|
|
|
|
|
|
274
|
4
|
|
|
4
|
1
|
34
|
sub jmp_if_signed_ge { shift->_append_jmp_cond(13, shift) } |
275
|
|
|
|
|
|
|
*jge= *jmp_if_signed_ge; |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
|
278
|
4
|
|
|
4
|
1
|
48
|
sub jmp_if_sign { shift->_append_jmp_cond(8, shift) } |
279
|
|
|
|
|
|
|
*js= *jmp_if_sign; |
280
|
|
|
|
|
|
|
|
281
|
4
|
|
|
4
|
1
|
37
|
sub jmp_unless_sign { shift->_append_jmp_cond(9, shift) } |
282
|
|
|
|
|
|
|
*jns= *jmp_unless_sign; |
283
|
|
|
|
|
|
|
|
284
|
4
|
|
|
4
|
1
|
36
|
sub jmp_if_overflow { shift->_append_jmp_cond(0, shift) } |
285
|
|
|
|
|
|
|
*jo= *jmp_if_overflow; |
286
|
|
|
|
|
|
|
|
287
|
4
|
|
|
4
|
1
|
33
|
sub jmp_unless_overflow { shift->_append_jmp_cond(1, shift) } |
288
|
|
|
|
|
|
|
*jno= *jmp_unless_overflow; |
289
|
|
|
|
|
|
|
|
290
|
4
|
|
|
4
|
1
|
69
|
sub jmp_if_parity_even { shift->_append_jmp_cond(10, shift) } |
291
|
|
|
|
|
|
|
*jpe= *jmp_if_parity_even; |
292
|
|
|
|
|
|
|
*jp= *jmp_if_parity_even; |
293
|
|
|
|
|
|
|
|
294
|
4
|
|
|
4
|
1
|
35
|
sub jmp_if_parity_odd { shift->_append_jmp_cond(11, shift) } |
295
|
|
|
|
|
|
|
*jpo= *jmp_if_parity_odd; |
296
|
|
|
|
|
|
|
*jnp= *jmp_if_parity_odd; |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
|
299
|
2
|
|
|
2
|
1
|
27
|
sub jmp_cx_zero { shift->_append_jmp_cx(0xE3, shift) } |
300
|
|
|
|
|
|
|
*jrcxz= *jmp_cx_zero; |
301
|
|
|
|
|
|
|
|
302
|
2
|
|
|
2
|
1
|
26
|
sub loop { shift->_append_jmp_cx(0xE2, shift) } |
303
|
|
|
|
|
|
|
|
304
|
2
|
|
|
2
|
1
|
25
|
sub loopz { shift->_append_jmp_cx(0xE1, shift) } |
305
|
|
|
|
|
|
|
*loope= *loopz; |
306
|
|
|
|
|
|
|
|
307
|
2
|
|
|
2
|
1
|
27
|
sub loopnz { shift->_append_jmp_cx(0xE0, shift) } |
308
|
|
|
|
|
|
|
*loopne= *loopnz; |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
|
311
|
49
|
|
|
49
|
1
|
1654
|
sub mov64_reg_reg { shift->_append_op64_reg_reg(0x89, $_[1], $_[0]) } |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
|
314
|
441
|
|
|
441
|
0
|
10384
|
sub mov64_mem_reg { $_[0]->_append_op64_reg_mem(8, 0x89, $_[2], $_[1]); } |
315
|
441
|
|
|
441
|
0
|
10493
|
sub mov32_mem_reg { $_[0]->_append_op32_reg_mem(0, 0x89, $_[2], $_[1]); } |
316
|
441
|
|
|
441
|
0
|
10592
|
sub mov16_mem_reg { $_[0]->_append_op16_reg_mem(0, 0x89, $_[2], $_[1]); } |
317
|
441
|
|
|
441
|
0
|
10533
|
sub mov8_mem_reg { $_[0]->_append_op8_reg_mem (0, 0x88, $_[2], $_[1]); } |
318
|
|
|
|
|
|
|
|
319
|
441
|
|
|
441
|
0
|
10301
|
sub mov64_reg_mem { $_[0]->_append_op64_reg_mem(8, 0x8B, $_[1], $_[2]); } |
320
|
441
|
|
|
441
|
0
|
10314
|
sub mov32_reg_mem { $_[0]->_append_op32_reg_mem(0, 0x8B, $_[1], $_[2]); } |
321
|
441
|
|
|
441
|
0
|
10351
|
sub mov16_reg_mem { $_[0]->_append_op16_reg_mem(0, 0x8B, $_[1], $_[2]); } |
322
|
441
|
|
|
441
|
0
|
10211
|
sub mov8_reg_mem { $_[0]->_append_op8_reg_mem (0, 0x8A, $_[1], $_[2]); } |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
sub mov64_reg_imm { |
326
|
63
|
|
|
63
|
1
|
1390
|
my ($self, $reg, $immed)= @_; |
327
|
63
|
|
33
|
|
|
100
|
$reg= $regnum64{$reg} // croak("$reg is not a 64-bit register"); |
328
|
63
|
|
|
|
|
106
|
$self->_append_possible_unknown('_encode_mov64_imm', [$reg, $immed], 1, 10); |
329
|
|
|
|
|
|
|
} |
330
|
|
|
|
|
|
|
sub _encode_mov64_imm { |
331
|
63
|
|
|
63
|
|
51
|
my ($self, $reg, $immed)= @_; |
332
|
14
|
|
|
14
|
|
11312
|
use integer; |
|
14
|
|
|
|
|
14
|
|
|
14
|
|
|
|
|
36
|
|
333
|
|
|
|
|
|
|
# If the number fits in 32-bits, encode as the classic instruction |
334
|
63
|
100
|
|
|
|
81
|
if (!($immed >> 32)) { |
|
|
100
|
|
|
|
|
|
335
|
28
|
100
|
|
|
|
82
|
return $reg > 7? # need REX byte if extended register |
336
|
|
|
|
|
|
|
pack('CCL<', 0x41, 0xB8 + ($reg&7), $immed) |
337
|
|
|
|
|
|
|
: pack('CL<', 0xB8 + $reg, $immed); |
338
|
|
|
|
|
|
|
} |
339
|
|
|
|
|
|
|
# If the number can sign-extend from 32-bits, encode as 32-bit sign-extend |
340
|
|
|
|
|
|
|
elsif (($immed >> 31) == -1) { |
341
|
21
|
|
|
|
|
66
|
return pack('CCCl<', 0x48 | (($reg & 8) >> 3), 0xC7, 0xC0 + ($reg & 7), $immed); |
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
# else encode as new 64-bit immediate |
344
|
|
|
|
|
|
|
else { |
345
|
14
|
|
|
|
|
45
|
return pack('CCQ<', 0x48 | (($reg & 8) >> 3), 0xB8 + ($reg & 7), $immed); |
346
|
|
|
|
|
|
|
} |
347
|
|
|
|
|
|
|
} |
348
|
|
|
|
|
|
|
sub mov32_reg_imm { |
349
|
56
|
|
|
56
|
0
|
1202
|
my ($self, $reg, $immed)= @_; |
350
|
56
|
|
33
|
|
|
93
|
$reg= $regnum32{$reg} // croak("$reg is not a 32-bit register"); |
351
|
56
|
100
|
|
|
|
78
|
$self->{_buf} .= "\x41" if $reg > 7; |
352
|
56
|
|
|
|
|
99
|
$self->{_buf} .= pack('C' , 0xB8 | ($reg & 7)); |
353
|
56
|
|
|
56
|
|
154
|
$self->_append_possible_unknown(sub { pack('V', $_[1]) }, [$immed], 0, 4); |
|
56
|
|
|
|
|
82
|
|
354
|
|
|
|
|
|
|
} |
355
|
|
|
|
|
|
|
sub mov16_reg_imm { |
356
|
49
|
|
|
49
|
0
|
1037
|
my ($self, $reg, $immed)= @_; |
357
|
49
|
|
33
|
|
|
84
|
$reg= $regnum16{$reg} // croak("$reg is not a 16-bit register"); |
358
|
49
|
|
|
|
|
48
|
$self->{_buf} .= "\x66"; |
359
|
49
|
100
|
|
|
|
66
|
$self->{_buf} .= "\x41" if $reg > 7; |
360
|
49
|
|
|
|
|
66
|
$self->{_buf} .= pack('C', 0xB8 | ($reg & 7)); |
361
|
49
|
|
|
49
|
|
144
|
$self->_append_possible_unknown(sub { pack('v', $_[1]) }, [$immed], 0, 2); |
|
49
|
|
|
|
|
65
|
|
362
|
|
|
|
|
|
|
} |
363
|
|
|
|
|
|
|
sub mov8_reg_imm { |
364
|
55
|
|
|
55
|
0
|
1152
|
my ($self, $reg, $immed)= @_; |
365
|
55
|
|
|
|
|
48
|
$reg= $regnum8{$reg}; |
366
|
|
|
|
|
|
|
# Special case for the high-byte registers available without the REX prefix |
367
|
55
|
100
|
|
|
|
65
|
if (!defined $reg) { |
368
|
20
|
|
33
|
|
|
36
|
$reg= $regnum8_high{$_[1]} // croak("$_[1] is not a 8-bit register"); |
369
|
|
|
|
|
|
|
} else { |
370
|
35
|
100
|
|
|
|
85
|
$self->{_buf} .= pack('C', 0x40|(($reg&8)>>3)) if $reg > 3; |
371
|
|
|
|
|
|
|
} |
372
|
55
|
|
|
|
|
78
|
$self->{_buf} .= pack('C', 0xB0 | ($reg & 7)); |
373
|
55
|
|
|
55
|
|
139
|
$self->_append_possible_unknown(sub { pack('C', $_[1]&0xFF) }, [$immed], 0, 1); |
|
55
|
|
|
|
|
84
|
|
374
|
|
|
|
|
|
|
} |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
|
377
|
0
|
|
|
0
|
0
|
0
|
sub mov64_mem_imm { $_[0]->_append_op64_const_mem(0xC7, 0, $_[2], $_[1]) } |
378
|
0
|
|
|
0
|
0
|
0
|
sub mov32_mem_imm { $_[0]->_append_op32_const_mem(0xC7, 0, $_[2], $_[1]) } |
379
|
0
|
|
|
0
|
0
|
0
|
sub mov16_mem_imm { $_[0]->_append_op16_const_mem(0xC7, 0, $_[2], $_[1]) } |
380
|
0
|
|
|
0
|
0
|
0
|
sub mov8_mem_imm { $_[0]->_append_op8_const_mem (0xC6, 0, $_[2], $_[1]) } |
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
|
383
|
49
|
|
|
49
|
0
|
1782
|
sub add64_reg_reg { $_[0]->_append_op64_reg_reg(0x01, $_[2], $_[1]) } |
384
|
49
|
|
|
49
|
0
|
1105
|
sub add32_reg_reg { $_[0]->_append_op32_reg_reg(0x01, $_[2], $_[1]) } |
385
|
49
|
|
|
49
|
0
|
1111
|
sub add16_reg_reg { $_[0]->_append_op16_reg_reg(0x01, $_[2], $_[1]) } |
386
|
49
|
|
|
49
|
0
|
1106
|
sub add8_reg_reg { $_[0]->_append_op8_reg_reg (0x00, $_[2], $_[1]) } |
387
|
|
|
|
|
|
|
|
388
|
441
|
|
|
441
|
0
|
10472
|
sub add64_reg_mem { $_[0]->_append_op64_reg_mem(8, 0x03, $_[1], $_[2]); } |
389
|
441
|
|
|
441
|
0
|
10356
|
sub add32_reg_mem { $_[0]->_append_op32_reg_mem(0, 0x03, $_[1], $_[2]); } |
390
|
441
|
|
|
441
|
0
|
10362
|
sub add16_reg_mem { $_[0]->_append_op16_reg_mem(0, 0x03, $_[1], $_[2]); } |
391
|
441
|
|
|
441
|
0
|
10457
|
sub add8_reg_mem { $_[0]->_append_op8_reg_mem (0, 0x02, $_[1], $_[2]); } |
392
|
|
|
|
|
|
|
|
393
|
441
|
|
|
441
|
0
|
10424
|
sub add64_mem_reg { $_[0]->_append_op64_reg_mem(8, 0x01, $_[2], $_[1]); } |
394
|
441
|
|
|
441
|
0
|
10306
|
sub add32_mem_reg { $_[0]->_append_op32_reg_mem(0, 0x01, $_[2], $_[1]); } |
395
|
441
|
|
|
441
|
0
|
10422
|
sub add16_mem_reg { $_[0]->_append_op16_reg_mem(0, 0x01, $_[2], $_[1]); } |
396
|
441
|
|
|
441
|
0
|
10468
|
sub add8_mem_reg { $_[0]->_append_op8_reg_mem (0, 0x00, $_[2], $_[1]); } |
397
|
|
|
|
|
|
|
|
398
|
56
|
|
|
56
|
0
|
1554
|
sub add64_reg_imm { shift->_append_mathop64_const(0x05, 0x83, 0x81, 0, @_) } |
399
|
56
|
|
|
56
|
0
|
1302
|
sub add32_reg_imm { shift->_append_mathop32_const(0x05, 0x83, 0x81, 0, @_) } |
400
|
49
|
|
|
49
|
0
|
1097
|
sub add16_reg_imm { shift->_append_mathop16_const(0x05, 0x83, 0x81, 0, @_) } |
401
|
35
|
|
|
35
|
0
|
840
|
sub add8_reg_imm { shift->_append_mathop8_const (0x04, 0x80, 0, @_) } |
402
|
|
|
|
|
|
|
|
403
|
504
|
|
|
504
|
0
|
11885
|
sub add64_mem_imm { $_[0]->_append_mathop64_const_to_mem(0x83, 0x81, 0, $_[2], $_[1]) } |
404
|
504
|
|
|
504
|
0
|
11985
|
sub add32_mem_imm { $_[0]->_append_mathop32_const_to_mem(0x83, 0x81, 0, $_[2], $_[1]) } |
405
|
441
|
|
|
441
|
0
|
10413
|
sub add16_mem_imm { $_[0]->_append_mathop16_const_to_mem(0x83, 0x81, 0, $_[2], $_[1]) } |
406
|
315
|
|
|
315
|
0
|
7489
|
sub add8_mem_imm { $_[0]->_append_mathop8_const_to_mem (0x80, 0, $_[2], $_[1]) } |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
|
409
|
49
|
|
|
49
|
0
|
1101
|
sub addcarry64_reg_reg { $_[0]->_append_op64_reg_reg(0x11, $_[2], $_[1]) } |
410
|
49
|
|
|
49
|
0
|
1093
|
sub addcarry32_reg_reg { $_[0]->_append_op32_reg_reg(0x11, $_[2], $_[1]) } |
411
|
49
|
|
|
49
|
0
|
1105
|
sub addcarry16_reg_reg { $_[0]->_append_op16_reg_reg(0x11, $_[2], $_[1]) } |
412
|
49
|
|
|
49
|
0
|
1103
|
sub addcarry8_reg_reg { $_[0]->_append_op8_reg_reg (0x10, $_[2], $_[1]) } |
413
|
|
|
|
|
|
|
|
414
|
441
|
|
|
441
|
0
|
10548
|
sub addcarry64_reg_mem { $_[0]->_append_op64_reg_mem(8, 0x13, $_[1], $_[2]); } |
415
|
441
|
|
|
441
|
0
|
10634
|
sub addcarry32_reg_mem { $_[0]->_append_op32_reg_mem(0, 0x13, $_[1], $_[2]); } |
416
|
441
|
|
|
441
|
0
|
10422
|
sub addcarry16_reg_mem { $_[0]->_append_op16_reg_mem(0, 0x13, $_[1], $_[2]); } |
417
|
441
|
|
|
441
|
0
|
10470
|
sub addcarry8_reg_mem { $_[0]->_append_op8_reg_mem (0, 0x12, $_[1], $_[2]); } |
418
|
|
|
|
|
|
|
|
419
|
441
|
|
|
441
|
0
|
10498
|
sub addcarry64_mem_reg { $_[0]->_append_op64_reg_mem(8, 0x11, $_[2], $_[1]); } |
420
|
441
|
|
|
441
|
0
|
10439
|
sub addcarry32_mem_reg { $_[0]->_append_op32_reg_mem(0, 0x11, $_[2], $_[1]); } |
421
|
441
|
|
|
441
|
0
|
10479
|
sub addcarry16_mem_reg { $_[0]->_append_op16_reg_mem(0, 0x11, $_[2], $_[1]); } |
422
|
441
|
|
|
441
|
0
|
10275
|
sub addcarry8_mem_reg { $_[0]->_append_op8_reg_mem (0, 0x10, $_[2], $_[1]); } |
423
|
|
|
|
|
|
|
|
424
|
56
|
|
|
56
|
0
|
1285
|
sub addcarry64_reg_imm { shift->_append_mathop64_const(0x15, 0x83, 0x81, 2, @_) } |
425
|
56
|
|
|
56
|
0
|
1284
|
sub addcarry32_reg_imm { shift->_append_mathop32_const(0x15, 0x83, 0x81, 2, @_) } |
426
|
49
|
|
|
49
|
0
|
1116
|
sub addcarry16_reg_imm { shift->_append_mathop16_const(0x15, 0x83, 0x81, 2, @_) } |
427
|
35
|
|
|
35
|
0
|
793
|
sub addcarry8_reg_imm { shift->_append_mathop8_const (0x14, 0x80, 2, @_) } |
428
|
|
|
|
|
|
|
|
429
|
504
|
|
|
504
|
0
|
11990
|
sub addcarry64_mem_imm { $_[0]->_append_mathop64_const_to_mem(0x83, 0x81, 2, $_[2], $_[1]) } |
430
|
504
|
|
|
504
|
0
|
12097
|
sub addcarry32_mem_imm { $_[0]->_append_mathop32_const_to_mem(0x83, 0x81, 2, $_[2], $_[1]) } |
431
|
441
|
|
|
441
|
0
|
10625
|
sub addcarry16_mem_imm { $_[0]->_append_mathop16_const_to_mem(0x83, 0x81, 2, $_[2], $_[1]) } |
432
|
315
|
|
|
315
|
0
|
7557
|
sub addcarry8_mem_imm { $_[0]->_append_mathop8_const_to_mem (0x80, 2, $_[2], $_[1]) } |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
|
435
|
49
|
|
|
49
|
0
|
2040
|
sub and64_reg_reg { $_[0]->_append_op64_reg_reg(0x21, $_[2], $_[1]) } |
436
|
49
|
|
|
49
|
0
|
1279
|
sub and32_reg_reg { $_[0]->_append_op32_reg_reg(0x21, $_[2], $_[1]) } |
437
|
49
|
|
|
49
|
0
|
1271
|
sub and16_reg_reg { $_[0]->_append_op16_reg_reg(0x21, $_[2], $_[1]) } |
438
|
49
|
|
|
49
|
0
|
1248
|
sub and8_reg_reg { $_[0]->_append_op8_reg_reg (0x20, $_[2], $_[1]) } |
439
|
|
|
|
|
|
|
|
440
|
441
|
|
|
441
|
0
|
12259
|
sub and64_reg_mem { $_[0]->_append_op64_reg_mem(8, 0x23, $_[1], $_[2]); } |
441
|
441
|
|
|
441
|
0
|
12122
|
sub and32_reg_mem { $_[0]->_append_op32_reg_mem(0, 0x23, $_[1], $_[2]); } |
442
|
441
|
|
|
441
|
0
|
12481
|
sub and16_reg_mem { $_[0]->_append_op16_reg_mem(0, 0x23, $_[1], $_[2]); } |
443
|
441
|
|
|
441
|
0
|
13232
|
sub and8_reg_mem { $_[0]->_append_op8_reg_mem (0, 0x22, $_[1], $_[2]); } |
444
|
|
|
|
|
|
|
|
445
|
441
|
|
|
441
|
0
|
12135
|
sub and64_mem_reg { $_[0]->_append_op64_reg_mem(8, 0x21, $_[2], $_[1]); } |
446
|
441
|
|
|
441
|
0
|
12315
|
sub and32_mem_reg { $_[0]->_append_op32_reg_mem(0, 0x21, $_[2], $_[1]); } |
447
|
441
|
|
|
441
|
0
|
12272
|
sub and16_mem_reg { $_[0]->_append_op16_reg_mem(0, 0x21, $_[2], $_[1]); } |
448
|
441
|
|
|
441
|
0
|
14181
|
sub and8_mem_reg { $_[0]->_append_op8_reg_mem (0, 0x20, $_[2], $_[1]); } |
449
|
|
|
|
|
|
|
|
450
|
56
|
|
|
56
|
0
|
1437
|
sub and64_reg_imm { shift->_append_mathop64_const(0x25, 0x83, 0x81, 4, @_) } |
451
|
56
|
|
|
56
|
0
|
1574
|
sub and32_reg_imm { shift->_append_mathop32_const(0x25, 0x83, 0x81, 4, @_) } |
452
|
49
|
|
|
49
|
0
|
1278
|
sub and16_reg_imm { shift->_append_mathop16_const(0x25, 0x83, 0x81, 4, @_) } |
453
|
35
|
|
|
35
|
0
|
786
|
sub and8_reg_imm { shift->_append_mathop8_const (0x24, 0x80, 4, @_) } |
454
|
|
|
|
|
|
|
|
455
|
504
|
|
|
504
|
0
|
15782
|
sub and64_mem_imm { $_[0]->_append_mathop64_const_to_mem(0x83, 0x81, 4, $_[2], $_[1]) } |
456
|
504
|
|
|
504
|
0
|
13909
|
sub and32_mem_imm { $_[0]->_append_mathop32_const_to_mem(0x83, 0x81, 4, $_[2], $_[1]) } |
457
|
441
|
|
|
441
|
0
|
12168
|
sub and16_mem_imm { $_[0]->_append_mathop16_const_to_mem(0x83, 0x81, 4, $_[2], $_[1]) } |
458
|
315
|
|
|
315
|
0
|
8709
|
sub and8_mem_imm { $_[0]->_append_mathop8_const_to_mem (0x80, 4, $_[2], $_[1]) } |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
|
461
|
49
|
|
|
49
|
0
|
2167
|
sub or64_reg_reg { $_[0]->_append_op64_reg_reg(0x09, $_[2], $_[1]) } |
462
|
49
|
|
|
49
|
0
|
1183
|
sub or32_reg_reg { $_[0]->_append_op32_reg_reg(0x09, $_[2], $_[1]) } |
463
|
49
|
|
|
49
|
0
|
1136
|
sub or16_reg_reg { $_[0]->_append_op16_reg_reg(0x09, $_[2], $_[1]) } |
464
|
49
|
|
|
49
|
0
|
1164
|
sub or8_reg_reg { $_[0]->_append_op8_reg_reg (0x08, $_[2], $_[1]) } |
465
|
|
|
|
|
|
|
|
466
|
441
|
|
|
441
|
0
|
11024
|
sub or64_reg_mem { $_[0]->_append_op64_reg_mem(8, 0x0B, $_[1], $_[2]); } |
467
|
441
|
|
|
441
|
0
|
10580
|
sub or32_reg_mem { $_[0]->_append_op32_reg_mem(0, 0x0B, $_[1], $_[2]); } |
468
|
441
|
|
|
441
|
0
|
10617
|
sub or16_reg_mem { $_[0]->_append_op16_reg_mem(0, 0x0B, $_[1], $_[2]); } |
469
|
441
|
|
|
441
|
0
|
10574
|
sub or8_reg_mem { $_[0]->_append_op8_reg_mem (0, 0x0A, $_[1], $_[2]); } |
470
|
|
|
|
|
|
|
|
471
|
441
|
|
|
441
|
0
|
10559
|
sub or64_mem_reg { $_[0]->_append_op64_reg_mem(8, 0x09, $_[2], $_[1]); } |
472
|
441
|
|
|
441
|
0
|
10839
|
sub or32_mem_reg { $_[0]->_append_op32_reg_mem(0, 0x09, $_[2], $_[1]); } |
473
|
441
|
|
|
441
|
0
|
10561
|
sub or16_mem_reg { $_[0]->_append_op16_reg_mem(0, 0x09, $_[2], $_[1]); } |
474
|
441
|
|
|
441
|
0
|
10737
|
sub or8_mem_reg { $_[0]->_append_op8_reg_mem (0, 0x08, $_[2], $_[1]); } |
475
|
|
|
|
|
|
|
|
476
|
56
|
|
|
56
|
0
|
1265
|
sub or64_reg_imm { shift->_append_mathop64_const(0x0D, 0x83, 0x81, 1, @_) } |
477
|
56
|
|
|
56
|
0
|
1287
|
sub or32_reg_imm { shift->_append_mathop32_const(0x0D, 0x83, 0x81, 1, @_) } |
478
|
49
|
|
|
49
|
0
|
1116
|
sub or16_reg_imm { shift->_append_mathop16_const(0x0D, 0x83, 0x81, 1, @_) } |
479
|
35
|
|
|
35
|
0
|
799
|
sub or8_reg_imm { shift->_append_mathop8_const (0x0C, 0x80, 1, @_) } |
480
|
|
|
|
|
|
|
|
481
|
504
|
|
|
504
|
0
|
12059
|
sub or64_mem_imm { $_[0]->_append_mathop64_const_to_mem(0x83, 0x81, 1, $_[2], $_[1]) } |
482
|
504
|
|
|
504
|
0
|
12062
|
sub or32_mem_imm { $_[0]->_append_mathop32_const_to_mem(0x83, 0x81, 1, $_[2], $_[1]) } |
483
|
441
|
|
|
441
|
0
|
10351
|
sub or16_mem_imm { $_[0]->_append_mathop16_const_to_mem(0x83, 0x81, 1, $_[2], $_[1]) } |
484
|
315
|
|
|
315
|
0
|
7563
|
sub or8_mem_imm { $_[0]->_append_mathop8_const_to_mem (0x80, 1, $_[2], $_[1]) } |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
|
487
|
49
|
|
|
49
|
0
|
1829
|
sub xor64_reg_reg { $_[0]->_append_op64_reg_reg(0x31, $_[2], $_[1]) } |
488
|
49
|
|
|
49
|
0
|
1149
|
sub xor32_reg_reg { $_[0]->_append_op32_reg_reg(0x31, $_[2], $_[1]) } |
489
|
49
|
|
|
49
|
0
|
1177
|
sub xor16_reg_reg { $_[0]->_append_op16_reg_reg(0x31, $_[2], $_[1]) } |
490
|
49
|
|
|
49
|
0
|
1169
|
sub xor8_reg_reg { $_[0]->_append_op8_reg_reg (0x30, $_[2], $_[1]) } |
491
|
|
|
|
|
|
|
|
492
|
441
|
|
|
441
|
0
|
10994
|
sub xor64_reg_mem { $_[0]->_append_op64_reg_mem(8, 0x33, $_[1], $_[2]); } |
493
|
441
|
|
|
441
|
0
|
10997
|
sub xor32_reg_mem { $_[0]->_append_op32_reg_mem(0, 0x33, $_[1], $_[2]); } |
494
|
441
|
|
|
441
|
0
|
10966
|
sub xor16_reg_mem { $_[0]->_append_op16_reg_mem(0, 0x33, $_[1], $_[2]); } |
495
|
441
|
|
|
441
|
0
|
11094
|
sub xor8_reg_mem { $_[0]->_append_op8_reg_mem (0, 0x32, $_[1], $_[2]); } |
496
|
|
|
|
|
|
|
|
497
|
441
|
|
|
441
|
0
|
11023
|
sub xor64_mem_reg { $_[0]->_append_op64_reg_mem(8, 0x31, $_[2], $_[1]); } |
498
|
441
|
|
|
441
|
0
|
10930
|
sub xor32_mem_reg { $_[0]->_append_op32_reg_mem(0, 0x31, $_[2], $_[1]); } |
499
|
441
|
|
|
441
|
0
|
10879
|
sub xor16_mem_reg { $_[0]->_append_op16_reg_mem(0, 0x31, $_[2], $_[1]); } |
500
|
441
|
|
|
441
|
0
|
11055
|
sub xor8_mem_reg { $_[0]->_append_op8_reg_mem (0, 0x30, $_[2], $_[1]); } |
501
|
|
|
|
|
|
|
|
502
|
56
|
|
|
56
|
0
|
1643
|
sub xor64_reg_imm { shift->_append_mathop64_const(0x35, 0x83, 0x81, 6, @_) } |
503
|
56
|
|
|
56
|
0
|
1294
|
sub xor32_reg_imm { shift->_append_mathop32_const(0x35, 0x83, 0x81, 6, @_) } |
504
|
49
|
|
|
49
|
0
|
1192
|
sub xor16_reg_imm { shift->_append_mathop16_const(0x35, 0x83, 0x81, 6, @_) } |
505
|
35
|
|
|
35
|
0
|
826
|
sub xor8_reg_imm { shift->_append_mathop8_const (0x34, 0x80, 6, @_) } |
506
|
|
|
|
|
|
|
|
507
|
504
|
|
|
504
|
0
|
12803
|
sub xor64_mem_imm { $_[0]->_append_mathop64_const_to_mem(0x83, 0x81, 6, $_[2], $_[1]) } |
508
|
504
|
|
|
504
|
0
|
12541
|
sub xor32_mem_imm { $_[0]->_append_mathop32_const_to_mem(0x83, 0x81, 6, $_[2], $_[1]) } |
509
|
441
|
|
|
441
|
0
|
11024
|
sub xor16_mem_imm { $_[0]->_append_mathop16_const_to_mem(0x83, 0x81, 6, $_[2], $_[1]) } |
510
|
315
|
|
|
315
|
0
|
7822
|
sub xor8_mem_imm { $_[0]->_append_mathop8_const_to_mem (0x80, 6, $_[2], $_[1]) } |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
|
513
|
77
|
|
|
77
|
0
|
1720
|
sub shl64_reg_imm { $_[0]->_append_shiftop_reg_imm(64, 0xD1, 0xC1, 4, $_[1], $_[2]) } |
514
|
63
|
|
|
63
|
0
|
1389
|
sub shl32_reg_imm { $_[0]->_append_shiftop_reg_imm(32, 0xD1, 0xC1, 4, $_[1], $_[2]) } |
515
|
49
|
|
|
49
|
0
|
1083
|
sub shl16_reg_imm { $_[0]->_append_shiftop_reg_imm(16, 0xD1, 0xC1, 4, $_[1], $_[2]) } |
516
|
55
|
|
|
55
|
0
|
1224
|
sub shl8_reg_imm { $_[0]->_append_shiftop_reg_imm( 8, 0xD0, 0xC0, 4, $_[1], $_[2]) } |
517
|
|
|
|
|
|
|
|
518
|
7
|
|
|
7
|
0
|
157
|
sub shl64_reg_cl { $_[0]->_append_op64_reg_reg(0xD3, 4, $_[1]) } |
519
|
7
|
|
|
7
|
0
|
156
|
sub shl32_reg_cl { $_[0]->_append_op32_reg_reg(0xD3, 4, $_[1]) } |
520
|
7
|
|
|
7
|
0
|
153
|
sub shl16_reg_cl { $_[0]->_append_op16_reg_reg(0xD3, 4, $_[1]) } |
521
|
11
|
|
|
11
|
0
|
236
|
sub shl8_reg_cl { $_[0]->_append_op8_opreg_reg(0xD2, 4, $_[1]) } |
522
|
|
|
|
|
|
|
|
523
|
315
|
|
|
315
|
0
|
7316
|
sub shl64_mem_imm { $_[0]->_append_shiftop_mem_imm(64, 0xD1, 0xC1, 4, $_[1], $_[2]) } |
524
|
315
|
|
|
315
|
0
|
7234
|
sub shl32_mem_imm { $_[0]->_append_shiftop_mem_imm(32, 0xD1, 0xC1, 4, $_[1], $_[2]) } |
525
|
315
|
|
|
315
|
0
|
7139
|
sub shl16_mem_imm { $_[0]->_append_shiftop_mem_imm(16, 0xD1, 0xC1, 4, $_[1], $_[2]) } |
526
|
315
|
|
|
315
|
0
|
7178
|
sub shl8_mem_imm { $_[0]->_append_shiftop_mem_imm( 8, 0xD0, 0xC0, 4, $_[1], $_[2]) } |
527
|
|
|
|
|
|
|
|
528
|
63
|
|
|
63
|
0
|
1427
|
sub shl64_mem_cl { $_[0]->_append_op64_reg_mem(8, 0xD3, 4, $_[1]) } |
529
|
63
|
|
|
63
|
0
|
1425
|
sub shl32_mem_cl { $_[0]->_append_op32_reg_mem(0, 0xD3, 4, $_[1]) } |
530
|
63
|
|
|
63
|
0
|
1431
|
sub shl16_mem_cl { $_[0]->_append_op16_reg_mem(0, 0xD3, 4, $_[1]) } |
531
|
63
|
|
|
63
|
0
|
1450
|
sub shl8_mem_cl { $_[0]->_append_op8_opreg_mem(0, 0xD2, 4, $_[1]) } |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
|
534
|
77
|
|
|
77
|
0
|
2349
|
sub shr64_reg_imm { $_[0]->_append_shiftop_reg_imm(64, 0xD1, 0xC1, 5, $_[1], $_[2]) } |
535
|
63
|
|
|
63
|
0
|
1392
|
sub shr32_reg_imm { $_[0]->_append_shiftop_reg_imm(32, 0xD1, 0xC1, 5, $_[1], $_[2]) } |
536
|
49
|
|
|
49
|
0
|
1087
|
sub shr16_reg_imm { $_[0]->_append_shiftop_reg_imm(16, 0xD1, 0xC1, 5, $_[1], $_[2]) } |
537
|
55
|
|
|
55
|
0
|
1219
|
sub shr8_reg_imm { $_[0]->_append_shiftop_reg_imm( 8, 0xD0, 0xC0, 5, $_[1], $_[2]) } |
538
|
|
|
|
|
|
|
|
539
|
7
|
|
|
7
|
0
|
147
|
sub shr64_reg_cl { $_[0]->_append_op64_reg_reg(0xD3, 5, $_[1]) } |
540
|
7
|
|
|
7
|
0
|
144
|
sub shr32_reg_cl { $_[0]->_append_op32_reg_reg(0xD3, 5, $_[1]) } |
541
|
7
|
|
|
7
|
0
|
145
|
sub shr16_reg_cl { $_[0]->_append_op16_reg_reg(0xD3, 5, $_[1]) } |
542
|
11
|
|
|
11
|
0
|
257
|
sub shr8_reg_cl { $_[0]->_append_op8_opreg_reg(0xD2, 5, $_[1]) } |
543
|
|
|
|
|
|
|
|
544
|
315
|
|
|
315
|
0
|
7156
|
sub shr64_mem_imm { $_[0]->_append_shiftop_mem_imm(64, 0xD1, 0xC1, 5, $_[1], $_[2]) } |
545
|
315
|
|
|
315
|
0
|
7169
|
sub shr32_mem_imm { $_[0]->_append_shiftop_mem_imm(32, 0xD1, 0xC1, 5, $_[1], $_[2]) } |
546
|
315
|
|
|
315
|
0
|
7179
|
sub shr16_mem_imm { $_[0]->_append_shiftop_mem_imm(16, 0xD1, 0xC1, 5, $_[1], $_[2]) } |
547
|
315
|
|
|
315
|
0
|
7395
|
sub shr8_mem_imm { $_[0]->_append_shiftop_mem_imm( 8, 0xD0, 0xC0, 5, $_[1], $_[2]) } |
548
|
|
|
|
|
|
|
|
549
|
63
|
|
|
63
|
0
|
1486
|
sub shr64_mem_cl { $_[0]->_append_op64_reg_mem(8, 0xD3, 5, $_[1]) } |
550
|
63
|
|
|
63
|
0
|
1445
|
sub shr32_mem_cl { $_[0]->_append_op32_reg_mem(0, 0xD3, 5, $_[1]) } |
551
|
63
|
|
|
63
|
0
|
1456
|
sub shr16_mem_cl { $_[0]->_append_op16_reg_mem(0, 0xD3, 5, $_[1]) } |
552
|
63
|
|
|
63
|
0
|
1494
|
sub shr8_mem_cl { $_[0]->_append_op8_opreg_mem(0, 0xD2, 5, $_[1]) } |
553
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
|
555
|
77
|
|
|
77
|
0
|
1672
|
sub sar64_reg_imm { $_[0]->_append_shiftop_reg_imm(64, 0xD1, 0xC1, 7, $_[1], $_[2]) } |
556
|
63
|
|
|
63
|
0
|
1373
|
sub sar32_reg_imm { $_[0]->_append_shiftop_reg_imm(32, 0xD1, 0xC1, 7, $_[1], $_[2]) } |
557
|
49
|
|
|
49
|
0
|
1058
|
sub sar16_reg_imm { $_[0]->_append_shiftop_reg_imm(16, 0xD1, 0xC1, 7, $_[1], $_[2]) } |
558
|
55
|
|
|
55
|
0
|
1519
|
sub sar8_reg_imm { $_[0]->_append_shiftop_reg_imm( 8, 0xD0, 0xC0, 7, $_[1], $_[2]) } |
559
|
|
|
|
|
|
|
|
560
|
7
|
|
|
7
|
0
|
151
|
sub sar64_reg_cl { $_[0]->_append_op64_reg_reg(0xD3, 7, $_[1]) } |
561
|
7
|
|
|
7
|
0
|
149
|
sub sar32_reg_cl { $_[0]->_append_op32_reg_reg(0xD3, 7, $_[1]) } |
562
|
7
|
|
|
7
|
0
|
155
|
sub sar16_reg_cl { $_[0]->_append_op16_reg_reg(0xD3, 7, $_[1]) } |
563
|
11
|
|
|
11
|
0
|
237
|
sub sar8_reg_cl { $_[0]->_append_op8_opreg_reg(0xD2, 7, $_[1]) } |
564
|
|
|
|
|
|
|
|
565
|
315
|
|
|
315
|
0
|
7486
|
sub sar64_mem_imm { $_[0]->_append_shiftop_mem_imm(64, 0xD1, 0xC1, 7, $_[1], $_[2]) } |
566
|
315
|
|
|
315
|
0
|
7320
|
sub sar32_mem_imm { $_[0]->_append_shiftop_mem_imm(32, 0xD1, 0xC1, 7, $_[1], $_[2]) } |
567
|
315
|
|
|
315
|
0
|
7480
|
sub sar16_mem_imm { $_[0]->_append_shiftop_mem_imm(16, 0xD1, 0xC1, 7, $_[1], $_[2]) } |
568
|
315
|
|
|
315
|
0
|
7484
|
sub sar8_mem_imm { $_[0]->_append_shiftop_mem_imm( 8, 0xD0, 0xC0, 7, $_[1], $_[2]) } |
569
|
|
|
|
|
|
|
|
570
|
63
|
|
|
63
|
0
|
1472
|
sub sar64_mem_cl { $_[0]->_append_op64_reg_mem(8, 0xD3, 7, $_[1]) } |
571
|
63
|
|
|
63
|
0
|
1499
|
sub sar32_mem_cl { $_[0]->_append_op32_reg_mem(0, 0xD3, 7, $_[1]) } |
572
|
63
|
|
|
63
|
0
|
1432
|
sub sar16_mem_cl { $_[0]->_append_op16_reg_mem(0, 0xD3, 7, $_[1]) } |
573
|
63
|
|
|
63
|
0
|
1502
|
sub sar8_mem_cl { $_[0]->_append_op8_opreg_mem(0, 0xD2, 7, $_[1]) } |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
|
576
|
49
|
|
|
49
|
0
|
1746
|
sub cmp64_reg_reg { $_[0]->_append_op64_reg_reg(0x39, $_[2], $_[1]) } |
577
|
49
|
|
|
49
|
0
|
1088
|
sub cmp32_reg_reg { $_[0]->_append_op32_reg_reg(0x39, $_[2], $_[1]) } |
578
|
49
|
|
|
49
|
0
|
1087
|
sub cmp16_reg_reg { $_[0]->_append_op16_reg_reg(0x39, $_[2], $_[1]) } |
579
|
49
|
|
|
49
|
0
|
1085
|
sub cmp8_reg_reg { $_[0]->_append_op8_reg_reg (0x38, $_[2], $_[1]) } |
580
|
|
|
|
|
|
|
|
581
|
441
|
|
|
441
|
0
|
10312
|
sub cmp64_reg_mem { $_[0]->_append_op64_reg_mem(8, 0x3B, $_[1], $_[2]); } |
582
|
441
|
|
|
441
|
0
|
10268
|
sub cmp32_reg_mem { $_[0]->_append_op32_reg_mem(0, 0x3B, $_[1], $_[2]); } |
583
|
441
|
|
|
441
|
0
|
10367
|
sub cmp16_reg_mem { $_[0]->_append_op16_reg_mem(0, 0x3B, $_[1], $_[2]); } |
584
|
441
|
|
|
441
|
0
|
10339
|
sub cmp8_reg_mem { $_[0]->_append_op8_reg_mem (0, 0x3A, $_[1], $_[2]); } |
585
|
|
|
|
|
|
|
|
586
|
0
|
|
|
0
|
0
|
0
|
sub cmp64_mem_reg { $_[0]->_append_op64_reg_mem(8, 0x39, $_[2], $_[1]); } |
587
|
0
|
|
|
0
|
0
|
0
|
sub cmp32_mem_reg { $_[0]->_append_op32_reg_mem(0, 0x39, $_[2], $_[1]); } |
588
|
0
|
|
|
0
|
0
|
0
|
sub cmp16_mem_reg { $_[0]->_append_op16_reg_mem(0, 0x39, $_[2], $_[1]); } |
589
|
0
|
|
|
0
|
0
|
0
|
sub cmp8_mem_reg { $_[0]->_append_op8_reg_mem (0, 0x38, $_[2], $_[1]); } |
590
|
|
|
|
|
|
|
|
591
|
56
|
|
|
56
|
0
|
1248
|
sub cmp64_reg_imm { shift->_append_mathop64_const(0x3D, 0x83, 0x81, 7, @_) } |
592
|
56
|
|
|
56
|
0
|
1248
|
sub cmp32_reg_imm { shift->_append_mathop32_const(0x3D, 0x83, 0x81, 7, @_) } |
593
|
49
|
|
|
49
|
0
|
1153
|
sub cmp16_reg_imm { shift->_append_mathop16_const(0x3D, 0x83, 0x81, 7, @_) } |
594
|
35
|
|
|
35
|
0
|
777
|
sub cmp8_reg_imm { shift->_append_mathop8_const (0x3C, 0x80, 7, @_) } |
595
|
|
|
|
|
|
|
|
596
|
504
|
|
|
504
|
0
|
11895
|
sub cmp64_mem_imm { $_[0]->_append_mathop64_const_to_mem(0x83, 0x81, 7, $_[2], $_[1]) } |
597
|
504
|
|
|
504
|
0
|
11856
|
sub cmp32_mem_imm { $_[0]->_append_mathop32_const_to_mem(0x83, 0x81, 7, $_[2], $_[1]) } |
598
|
441
|
|
|
441
|
0
|
10449
|
sub cmp16_mem_imm { $_[0]->_append_mathop16_const_to_mem(0x83, 0x81, 7, $_[2], $_[1]) } |
599
|
315
|
|
|
315
|
0
|
7577
|
sub cmp8_mem_imm { $_[0]->_append_mathop8_const_to_mem (0x80, 7, $_[2], $_[1]) } |
600
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
|
602
|
49
|
|
|
49
|
0
|
1725
|
sub test64_reg_reg { $_[0]->_append_op64_reg_reg(0x85, $_[2], $_[1]) } |
603
|
49
|
|
|
49
|
0
|
1139
|
sub test32_reg_reg { $_[0]->_append_op32_reg_reg(0x85, $_[2], $_[1]) } |
604
|
49
|
|
|
49
|
0
|
1085
|
sub test16_reg_reg { $_[0]->_append_op16_reg_reg(0x85, $_[2], $_[1]) } |
605
|
49
|
|
|
49
|
0
|
1080
|
sub test8_reg_reg { $_[0]->_append_op8_reg_reg (0x84, $_[2], $_[1]) } |
606
|
|
|
|
|
|
|
|
607
|
441
|
|
|
441
|
0
|
10094
|
sub test64_reg_mem { $_[0]->_append_op64_reg_mem(8, 0x85, $_[1], $_[2]); } |
608
|
441
|
|
|
441
|
0
|
10022
|
sub test32_reg_mem { $_[0]->_append_op32_reg_mem(0, 0x85, $_[1], $_[2]); } |
609
|
441
|
|
|
441
|
0
|
10143
|
sub test16_reg_mem { $_[0]->_append_op16_reg_mem(0, 0x85, $_[1], $_[2]); } |
610
|
441
|
|
|
441
|
0
|
10129
|
sub test8_reg_mem { $_[0]->_append_op8_reg_mem (0, 0x84, $_[1], $_[2]); } |
611
|
|
|
|
|
|
|
|
612
|
56
|
|
|
56
|
0
|
1269
|
sub test64_reg_imm { $_[0]->_append_mathop64_const(0xA9, undef, 0xF7, 0, $_[1], $_[2]) } |
613
|
56
|
|
|
56
|
0
|
1218
|
sub test32_reg_imm { $_[0]->_append_mathop32_const(0xA9, undef, 0xF7, 0, $_[1], $_[2]) } |
614
|
49
|
|
|
49
|
0
|
1063
|
sub test16_reg_imm { $_[0]->_append_mathop16_const(0xA9, undef, 0xF7, 0, $_[1], $_[2]) } |
615
|
35
|
|
|
35
|
0
|
770
|
sub test8_reg_imm { $_[0]->_append_mathop8_const (0xA8, 0xF6, 0, $_[1], $_[2]) } |
616
|
|
|
|
|
|
|
|
617
|
504
|
|
|
504
|
0
|
11608
|
sub test64_mem_imm { $_[0]->_append_mathop64_const_to_mem(undef, 0xF7, 0, $_[2], $_[1]) } |
618
|
504
|
|
|
504
|
0
|
11961
|
sub test32_mem_imm { $_[0]->_append_mathop32_const_to_mem(undef, 0xF7, 0, $_[2], $_[1]) } |
619
|
441
|
|
|
441
|
0
|
10081
|
sub test16_mem_imm { $_[0]->_append_mathop16_const_to_mem(undef, 0xF7, 0, $_[2], $_[1]) } |
620
|
315
|
|
|
315
|
0
|
7126
|
sub test8_mem_imm { $_[0]->_append_mathop8_const_to_mem (0xF6, 0, $_[2], $_[1]) } |
621
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
|
623
|
7
|
|
|
7
|
0
|
162
|
sub dec64_reg { $_[0]->_append_op64_reg_reg(0xFF, 1, $_[1]) } |
624
|
7
|
|
|
7
|
0
|
160
|
sub dec32_reg { $_[0]->_append_op32_reg_reg(0xFF, 1, $_[1]) } |
625
|
7
|
|
|
7
|
0
|
157
|
sub dec16_reg { $_[0]->_append_op16_reg_reg(0xFF, 1, $_[1]) } |
626
|
7
|
|
|
7
|
0
|
158
|
sub dec8_reg { $_[0]->_append_op8_reg_reg (0xFE, 1, $_[1]) } |
627
|
|
|
|
|
|
|
|
628
|
63
|
|
|
63
|
0
|
1445
|
sub dec64_mem { $_[0]->_append_op64_reg_mem(8, 0xFF, 1, $_[1]) } |
629
|
63
|
|
|
63
|
0
|
1444
|
sub dec32_mem { $_[0]->_append_op32_reg_mem(0, 0xFF, 1, $_[1]) } |
630
|
63
|
|
|
63
|
0
|
1439
|
sub dec16_mem { $_[0]->_append_op16_reg_mem(0, 0xFF, 1, $_[1]) } |
631
|
63
|
|
|
63
|
0
|
1459
|
sub dec8_mem { $_[0]->_append_op8_reg_mem (0, 0xFE, 1, $_[1]) } |
632
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
|
634
|
7
|
|
|
7
|
0
|
807
|
sub inc64_reg { $_[0]->_append_op64_reg_reg(0xFF, 0, $_[1]) } |
635
|
7
|
|
|
7
|
0
|
155
|
sub inc32_reg { $_[0]->_append_op32_reg_reg(0xFF, 0, $_[1]) } |
636
|
7
|
|
|
7
|
0
|
156
|
sub inc16_reg { $_[0]->_append_op16_reg_reg(0xFF, 0, $_[1]) } |
637
|
7
|
|
|
7
|
0
|
159
|
sub inc8_reg { $_[0]->_append_op8_reg_reg (0xFE, 0, $_[1]) } |
638
|
|
|
|
|
|
|
|
639
|
63
|
|
|
63
|
0
|
1494
|
sub inc64_mem { $_[0]->_append_op64_reg_mem(8, 0xFF, 0, $_[1]) } |
640
|
63
|
|
|
63
|
0
|
1431
|
sub inc32_mem { $_[0]->_append_op32_reg_mem(0, 0xFF, 0, $_[1]) } |
641
|
63
|
|
|
63
|
0
|
1460
|
sub inc16_mem { $_[0]->_append_op16_reg_mem(0, 0xFF, 0, $_[1]) } |
642
|
63
|
|
|
63
|
0
|
1502
|
sub inc8_mem { $_[0]->_append_op8_reg_mem (0, 0xFE, 0, $_[1]) } |
643
|
|
|
|
|
|
|
|
644
|
|
|
|
|
|
|
|
645
|
7
|
|
|
7
|
0
|
791
|
sub not64_reg { $_[0]->_append_op64_reg_reg(0xF7, 2, $_[1]) } |
646
|
7
|
|
|
7
|
0
|
158
|
sub not32_reg { $_[0]->_append_op32_reg_reg(0xF7, 2, $_[1]) } |
647
|
7
|
|
|
7
|
0
|
159
|
sub not16_reg { $_[0]->_append_op16_reg_reg(0xF7, 2, $_[1]) } |
648
|
7
|
|
|
7
|
0
|
158
|
sub not8_reg { $_[0]->_append_op8_reg_reg (0xF6, 2, $_[1]) } |
649
|
|
|
|
|
|
|
|
650
|
63
|
|
|
63
|
0
|
1457
|
sub not64_mem { $_[0]->_append_op64_reg_mem(8, 0xF7, 2, $_[1]) } |
651
|
63
|
|
|
63
|
0
|
1450
|
sub not32_mem { $_[0]->_append_op32_reg_mem(0, 0xF7, 2, $_[1]) } |
652
|
63
|
|
|
63
|
0
|
1456
|
sub not16_mem { $_[0]->_append_op16_reg_mem(0, 0xF7, 2, $_[1]) } |
653
|
63
|
|
|
63
|
0
|
1440
|
sub not8_mem { $_[0]->_append_op8_reg_mem (0, 0xF6, 2, $_[1]) } |
654
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
|
656
|
7
|
|
|
7
|
0
|
161
|
sub neg64_reg { $_[0]->_append_op64_reg_reg(0xF7, 3, $_[1]) } |
657
|
7
|
|
|
7
|
0
|
162
|
sub neg32_reg { $_[0]->_append_op32_reg_reg(0xF7, 3, $_[1]) } |
658
|
7
|
|
|
7
|
0
|
160
|
sub neg16_reg { $_[0]->_append_op16_reg_reg(0xF7, 3, $_[1]) } |
659
|
7
|
|
|
7
|
0
|
153
|
sub neg8_reg { $_[0]->_append_op8_reg_reg (0xF6, 3, $_[1]) } |
660
|
|
|
|
|
|
|
|
661
|
63
|
|
|
63
|
0
|
1486
|
sub neg64_mem { $_[0]->_append_op64_reg_mem(8, 0xF7, 3, $_[1]) } |
662
|
63
|
|
|
63
|
0
|
1450
|
sub neg32_mem { $_[0]->_append_op32_reg_mem(0, 0xF7, 3, $_[1]) } |
663
|
63
|
|
|
63
|
0
|
1473
|
sub neg16_mem { $_[0]->_append_op16_reg_mem(0, 0xF7, 3, $_[1]) } |
664
|
63
|
|
|
63
|
0
|
1495
|
sub neg8_mem { $_[0]->_append_op8_reg_mem (0, 0xF6, 3, $_[1]) } |
665
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
|
667
|
7
|
|
|
7
|
0
|
778
|
sub div64u_reg { $_[0]->_append_op64_reg_reg (0xF7, 6, $_[1]) } |
668
|
7
|
|
|
7
|
0
|
159
|
sub div32u_reg { $_[0]->_append_op32_reg_reg (0xF7, 6, $_[1]) } |
669
|
7
|
|
|
7
|
0
|
162
|
sub div16u_reg { $_[0]->_append_op16_reg_reg (0xF7, 6, $_[1]) } |
670
|
7
|
|
|
7
|
0
|
161
|
sub div8u_reg { $_[0]->_append_op8_opreg_reg(0xF6, 6, $_[1]) } |
671
|
|
|
|
|
|
|
|
672
|
63
|
|
|
63
|
0
|
1460
|
sub div64u_mem { $_[0]->_append_op64_reg_mem (8, 0xF7, 6, $_[1]) } |
673
|
63
|
|
|
63
|
0
|
1468
|
sub div32u_mem { $_[0]->_append_op32_reg_mem (0, 0xF7, 6, $_[1]) } |
674
|
63
|
|
|
63
|
0
|
1455
|
sub div16u_mem { $_[0]->_append_op16_reg_mem (0, 0xF7, 6, $_[1]) } |
675
|
63
|
|
|
63
|
0
|
1478
|
sub div8u_mem { $_[0]->_append_op8_opreg_mem(0, 0xF6, 6, $_[1]) } |
676
|
|
|
|
|
|
|
|
677
|
7
|
|
|
7
|
0
|
165
|
sub div64s_reg { $_[0]->_append_op64_reg_reg (0xF7, 7, $_[1]) } |
678
|
7
|
|
|
7
|
0
|
158
|
sub div32s_reg { $_[0]->_append_op32_reg_reg (0xF7, 7, $_[1]) } |
679
|
7
|
|
|
7
|
0
|
157
|
sub div16s_reg { $_[0]->_append_op16_reg_reg (0xF7, 7, $_[1]) } |
680
|
7
|
|
|
7
|
0
|
157
|
sub div8s_reg { $_[0]->_append_op8_opreg_reg(0xF6, 7, $_[1]) } |
681
|
|
|
|
|
|
|
|
682
|
63
|
|
|
63
|
0
|
1452
|
sub div64s_mem { $_[0]->_append_op64_reg_mem (8, 0xF7, 7, $_[1]) } |
683
|
63
|
|
|
63
|
0
|
1451
|
sub div32s_mem { $_[0]->_append_op32_reg_mem (0, 0xF7, 7, $_[1]) } |
684
|
63
|
|
|
63
|
0
|
1462
|
sub div16s_mem { $_[0]->_append_op16_reg_mem (0, 0xF7, 7, $_[1]) } |
685
|
63
|
|
|
63
|
0
|
1478
|
sub div8s_mem { $_[0]->_append_op8_opreg_mem(0, 0xF6, 7, $_[1]) } |
686
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
|
688
|
0
|
|
|
0
|
1
|
0
|
sub mul64s_dxax_reg { shift->_append_op64_reg_reg(8, 0xF7, 5, @_) } |
689
|
0
|
|
|
0
|
1
|
0
|
sub mul32s_dxax_reg { shift->_append_op32_reg_reg(0, 0xF7, 5, @_) } |
690
|
0
|
|
|
0
|
1
|
0
|
sub mul16s_dxax_reg { shift->_append_op16_reg_reg(0, 0xF7, 5, @_) } |
691
|
0
|
|
|
0
|
1
|
0
|
sub mul8s_ax_reg { shift->_append_op8_reg_reg (0, 0xF6, 5, @_) } |
692
|
|
|
|
|
|
|
|
693
|
|
|
|
|
|
|
#sub mul64s_reg { shift->_append_op64_reg_reg(8, |
694
|
|
|
|
|
|
|
|
695
|
|
|
|
|
|
|
|
696
|
1
|
|
|
1
|
1
|
28
|
sub sign_extend_al_ax { $_[0]{_buf} .= "\x66\x98"; $_[0] } |
|
1
|
|
|
|
|
3
|
|
697
|
|
|
|
|
|
|
*cbw= *sign_extend_al_ax; |
698
|
|
|
|
|
|
|
|
699
|
1
|
|
|
1
|
1
|
26
|
sub sign_extend_ax_eax { $_[0]{_buf} .= "\x98"; $_[0] } |
|
1
|
|
|
|
|
2
|
|
700
|
|
|
|
|
|
|
*cwde= *sign_extend_ax_eax; |
701
|
|
|
|
|
|
|
|
702
|
1
|
|
|
1
|
1
|
24
|
sub sign_extend_eax_rax { $_[0]{_buf} .= "\x48\x98"; $_[0] } |
|
1
|
|
|
|
|
2
|
|
703
|
|
|
|
|
|
|
*cdqe= *sign_extend_eax_rax; |
704
|
|
|
|
|
|
|
|
705
|
1
|
|
|
1
|
1
|
23
|
sub sign_extend_ax_dx { $_[0]{_buf} .= "\x66\x99"; $_[0] } |
|
1
|
|
|
|
|
2
|
|
706
|
|
|
|
|
|
|
*cwd= *sign_extend_ax_dx; |
707
|
|
|
|
|
|
|
|
708
|
1
|
|
|
1
|
1
|
24
|
sub sign_extend_eax_edx { $_[0]{_buf} .= "\x99"; $_[0] } |
|
1
|
|
|
|
|
1
|
|
709
|
|
|
|
|
|
|
*cdq= *sign_extend_eax_edx; |
710
|
|
|
|
|
|
|
|
711
|
1
|
|
|
1
|
1
|
24
|
sub sign_extend_rax_rdx { $_[0]{_buf} .= "\x48\x99"; $_[0] } |
|
1
|
|
|
|
|
1
|
|
712
|
|
|
|
|
|
|
*cqo= *sign_extend_rax_rdx; |
713
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
|
715
|
|
|
|
|
|
|
my @_carry_flag_op= ( "\xF5", "\xF8", "\xF9" ); |
716
|
3
|
|
|
3
|
1
|
4
|
sub flag_carry { $_[0]{_buf} .= $_carry_flag_op[$_[1] + 1]; $_[0] } |
|
3
|
|
|
|
|
6
|
|
717
|
1
|
|
|
1
|
1
|
26
|
sub clc { $_[0]{_buf} .= "\xF8"; $_[0] } |
|
1
|
|
|
|
|
2
|
|
718
|
1
|
|
|
1
|
1
|
27
|
sub cmc { $_[0]{_buf} .= "\xF5"; $_[0] } |
|
1
|
|
|
|
|
2
|
|
719
|
1
|
|
|
1
|
1
|
27
|
sub stc { $_[0]{_buf} .= "\xF9"; $_[0] } |
|
1
|
|
|
|
|
3
|
|
720
|
|
|
|
|
|
|
|
721
|
|
|
|
|
|
|
my @_direction_flag_op= ( "\xFC", "\xFD" ); |
722
|
2
|
|
|
2
|
1
|
3
|
sub flag_direction { $_[0]{_buf} .= $_direction_flag_op[$_[1]]; $_[0] } |
|
2
|
|
|
|
|
4
|
|
723
|
1
|
|
|
1
|
1
|
653
|
sub cld { $_[0]{_buf} .= "\xFC"; $_[0] } |
|
1
|
|
|
|
|
4
|
|
724
|
1
|
|
|
1
|
1
|
26
|
sub std { $_[0]{_buf} .= "\xFD"; $_[0] } |
|
1
|
|
|
|
|
2
|
|
725
|
|
|
|
|
|
|
|
726
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
sub push_reg { |
728
|
7
|
|
|
7
|
1
|
162
|
my ($self, $reg)= @_; |
729
|
7
|
|
33
|
|
|
14
|
$reg= ($regnum64{$reg} // croak("$reg is not a 64-bit register")); |
730
|
7
|
100
|
|
|
|
23
|
$self->{_buf} .= $reg > 7? pack('CC', 0x41, 0x50+($reg&7)) : pack('C', 0x50+($reg&7)); |
731
|
7
|
|
|
|
|
10
|
$self; |
732
|
|
|
|
|
|
|
} |
733
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
sub push_imm { |
735
|
8
|
|
|
8
|
1
|
177
|
my ($self, $imm)= @_; |
736
|
14
|
|
|
14
|
|
66027
|
use integer; |
|
14
|
|
|
|
|
15
|
|
|
14
|
|
|
|
|
42
|
|
737
|
8
|
50
|
|
|
|
10
|
my $val= ref $imm? 0x7FFFFFFF : $imm; |
738
|
8
|
100
|
|
|
|
23
|
$self->{_buf} .= (($val >> 7) == ($val >> 8))? pack('Cc', 0x6A, $val) : pack('CV', 0x68, $val); |
739
|
8
|
50
|
|
|
|
12
|
$self->_mark_unresolved(-4, encode => '_repack', bits => 32, value => $imm) |
740
|
|
|
|
|
|
|
if ref $imm; |
741
|
8
|
|
|
|
|
13
|
$self; |
742
|
|
|
|
|
|
|
} |
743
|
|
|
|
|
|
|
|
744
|
63
|
|
|
63
|
1
|
1515
|
sub push_mem { shift->_append_op64_reg_mem(0, 0xFF, 6, shift) } |
745
|
|
|
|
|
|
|
|
746
|
|
|
|
|
|
|
|
747
|
|
|
|
|
|
|
sub pop_reg { |
748
|
7
|
|
|
7
|
1
|
168
|
my ($self, $reg)= @_; |
749
|
7
|
|
33
|
|
|
15
|
$reg= ($regnum64{$reg} // croak("$reg is not a 64-bit register")); |
750
|
7
|
100
|
|
|
|
22
|
$self->{_buf} .= $reg > 7? pack('CC', 0x41, 0x58+($reg&7)) : pack('C', 0x58+($reg&7)); |
751
|
7
|
|
|
|
|
14
|
$self; |
752
|
|
|
|
|
|
|
} |
753
|
|
|
|
|
|
|
|
754
|
63
|
|
|
63
|
1
|
1520
|
sub pop_mem { shift->_append_op64_reg_mem(0, 0x8F, 0, shift) } |
755
|
|
|
|
|
|
|
|
756
|
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
sub enter { |
758
|
28
|
|
|
28
|
0
|
617
|
my ($self, $varspace, $nesting)= @_; |
759
|
28
|
|
50
|
|
|
47
|
$nesting //= 0; |
760
|
28
|
50
|
33
|
|
|
76
|
if (!ref $varspace && !ref $nesting) { |
761
|
28
|
|
|
|
|
59
|
$self->{_buf} .= pack('CvC', 0xC8, $varspace, $nesting); |
762
|
|
|
|
|
|
|
} |
763
|
|
|
|
|
|
|
else { |
764
|
0
|
0
|
|
|
|
0
|
$self->{_buf} .= pack('Cv', 0xC8, ref $varspace? 0 : $varspace); |
765
|
0
|
0
|
|
|
|
0
|
$self->_mark_unresolved(-2, encode => '_repack', bits => 16, value => $varspace) |
766
|
|
|
|
|
|
|
if ref $varspace; |
767
|
0
|
0
|
|
|
|
0
|
$self->{_buf} .= pack('C', ref $nesting? 0 : $nesting); |
768
|
0
|
0
|
|
|
|
0
|
$self->_mark_unresolved(-1, encode => '_repack', bits => 8, value => $nesting) |
769
|
|
|
|
|
|
|
if ref $nesting; |
770
|
|
|
|
|
|
|
} |
771
|
28
|
|
|
|
|
49
|
$self |
772
|
|
|
|
|
|
|
} |
773
|
|
|
|
|
|
|
|
774
|
|
|
|
|
|
|
|
775
|
1
|
|
|
1
|
0
|
27
|
sub leave { $_[0]{_buf} .= "\xC9"; $_[0] } |
|
1
|
|
|
|
|
2
|
|
776
|
|
|
|
|
|
|
|
777
|
|
|
|
|
|
|
|
778
|
|
|
|
|
|
|
sub syscall { |
779
|
0
|
|
|
0
|
1
|
0
|
$_[0]{_buf} .= "\x0F\x05"; |
780
|
0
|
|
|
|
|
0
|
$_[0]; |
781
|
|
|
|
|
|
|
} |
782
|
|
|
|
|
|
|
|
783
|
|
|
|
|
|
|
|
784
|
0
|
|
|
0
|
1
|
0
|
sub strcmp64 { $_[0]{_buf}.= "\x48\xA7"; $_[0] } |
|
0
|
|
|
|
|
0
|
|
785
|
|
|
|
|
|
|
*cmpsq= *strcmp64; |
786
|
|
|
|
|
|
|
|
787
|
0
|
|
|
0
|
1
|
0
|
sub strcmp32 { $_[0]{_buf}.= "\xA7"; $_[0] } |
|
0
|
|
|
|
|
0
|
|
788
|
|
|
|
|
|
|
*cmpsd= *strcmp32; |
789
|
|
|
|
|
|
|
|
790
|
0
|
|
|
0
|
1
|
0
|
sub strcmp16 { $_[0]{_buf}.= "\x66\xA7"; $_[0] } |
|
0
|
|
|
|
|
0
|
|
791
|
|
|
|
|
|
|
*cmpsw= *strcmp16; |
792
|
|
|
|
|
|
|
|
793
|
0
|
|
|
0
|
1
|
0
|
sub strcmp8 { $_[0]{_buf}.= "\xA6"; $_[0] } |
|
0
|
|
|
|
|
0
|
|
794
|
|
|
|
|
|
|
*cmpsb= *strcmp8; |
795
|
|
|
|
|
|
|
|
796
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
sub mfence { |
798
|
0
|
|
|
0
|
1
|
0
|
$_[0]{_buf} .= "\x0F\xAE\xF0"; |
799
|
0
|
|
|
|
|
0
|
$_[0]; |
800
|
|
|
|
|
|
|
} |
801
|
|
|
|
|
|
|
sub lfence { |
802
|
0
|
|
|
0
|
1
|
0
|
$_[0]{_buf} .= "\x0F\xAE\xE8"; |
803
|
0
|
|
|
|
|
0
|
$_[0]; |
804
|
|
|
|
|
|
|
} |
805
|
|
|
|
|
|
|
sub sfence { |
806
|
0
|
|
|
0
|
1
|
0
|
$_[0]{_buf} .= "\x0F\xAE\xF8"; |
807
|
0
|
|
|
|
|
0
|
$_[0]; |
808
|
|
|
|
|
|
|
} |
809
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
sub cache_flush { |
811
|
0
|
|
|
0
|
0
|
0
|
...; |
812
|
|
|
|
|
|
|
} |
813
|
|
|
|
|
|
|
*clflush= *cache_flush; |
814
|
|
|
|
|
|
|
|
815
|
|
|
|
|
|
|
|
816
|
|
|
|
|
|
|
sub _encode_op_reg_reg { |
817
|
14
|
|
|
14
|
|
15
|
my ($self, $rex, $opcode, $reg1, $reg2, $immed_pack, $immed)= @_; |
818
|
14
|
|
|
14
|
|
6421
|
use integer; |
|
14
|
|
|
|
|
17
|
|
|
14
|
|
|
|
|
51
|
|
819
|
14
|
|
|
|
|
18
|
$rex |= (($reg1 & 8) >> 1) | (($reg2 & 8) >> 3); |
820
|
14
|
50
|
|
|
|
56
|
return $rex? |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
821
|
|
|
|
|
|
|
(defined $immed? |
822
|
|
|
|
|
|
|
pack('CCC'.$immed_pack, 0x40|$rex, $opcode, 0xC0 | (($reg1 & 7) << 3) | ($reg2 & 7), $immed) |
823
|
|
|
|
|
|
|
: pack('CCC', 0x40|$rex, $opcode, 0xC0 | (($reg1 & 7) << 3) | ($reg2 & 7)) |
824
|
|
|
|
|
|
|
) |
825
|
|
|
|
|
|
|
: (defined $immed? |
826
|
|
|
|
|
|
|
pack('CC'.$immed_pack, $opcode, 0xC0 | (($reg1 & 7) << 3) | ($reg2 & 7), $immed) |
827
|
|
|
|
|
|
|
: pack('CC', $opcode, 0xC0 | (($reg1 & 7) << 3) | ($reg2 & 7)) |
828
|
|
|
|
|
|
|
); |
829
|
|
|
|
|
|
|
} |
830
|
|
|
|
|
|
|
|
831
|
|
|
|
|
|
|
sub _append_op64_reg_reg { |
832
|
686
|
|
|
686
|
|
649
|
my ($self, $opcode, $reg1, $reg2)= @_; |
833
|
686
|
|
33
|
|
|
1145
|
$reg1= ($regnum64{$reg1} // croak("$reg1 is not a 64-bit register")); |
834
|
686
|
|
33
|
|
|
938
|
$reg2= ($regnum64{$reg2} // croak("$reg2 is not a 64-bit register")); |
835
|
14
|
|
|
14
|
|
1950
|
use integer; |
|
14
|
|
|
|
|
13
|
|
|
14
|
|
|
|
|
31
|
|
836
|
686
|
|
|
|
|
1737
|
$self->{_buf} .= pack('CCC', |
837
|
|
|
|
|
|
|
0x48 | (($reg1 & 8) >> 1) | (($reg2 & 8) >> 3), |
838
|
|
|
|
|
|
|
$opcode, 0xC0 | (($reg1 & 7) << 3) | ($reg2 & 7)); |
839
|
686
|
|
|
|
|
905
|
$self; |
840
|
|
|
|
|
|
|
} |
841
|
|
|
|
|
|
|
sub _append_op32_reg_reg { |
842
|
595
|
|
|
595
|
|
551
|
my ($self, $opcode, $reg1, $reg2)= @_; |
843
|
595
|
|
33
|
|
|
1000
|
$reg1= ($regnum32{$reg1} // croak("$reg1 is not a 32-bit register")); |
844
|
595
|
|
33
|
|
|
808
|
$reg2= ($regnum32{$reg2} // croak("$reg2 is not a 32-bit register")); |
845
|
14
|
|
|
14
|
|
1225
|
use integer; |
|
14
|
|
|
|
|
14
|
|
|
14
|
|
|
|
|
35
|
|
846
|
595
|
|
|
|
|
613
|
my $rex= (($reg1 & 8) >> 1) | (($reg2 & 8) >> 3); |
847
|
595
|
100
|
|
|
|
1487
|
$self->{_buf} .= $rex? |
848
|
|
|
|
|
|
|
pack('CCC', 0x40|$rex, $opcode, 0xC0 | (($reg1 & 7) << 3) | ($reg2 & 7)) |
849
|
|
|
|
|
|
|
: pack('CC', $opcode, 0xC0 | (($reg1 & 7) << 3) | ($reg2 & 7)); |
850
|
595
|
|
|
|
|
795
|
$self; |
851
|
|
|
|
|
|
|
} |
852
|
|
|
|
|
|
|
sub _append_op16_reg_reg { |
853
|
553
|
|
|
553
|
|
525
|
my ($self, $opcode, $reg1, $reg2)= @_; |
854
|
553
|
|
33
|
|
|
960
|
$reg1= ($regnum16{$reg1} // croak("$reg1 is not a 16-bit register")); |
855
|
553
|
|
33
|
|
|
761
|
$reg2= ($regnum16{$reg2} // croak("$reg2 is not a 16-bit register")); |
856
|
14
|
|
|
14
|
|
1349
|
use integer; |
|
14
|
|
|
|
|
22
|
|
|
14
|
|
|
|
|
42
|
|
857
|
553
|
|
|
|
|
582
|
my $rex= (($reg1 & 8) >> 1) | (($reg2 & 8) >> 3); |
858
|
553
|
100
|
|
|
|
1445
|
$self->{_buf} .= $rex? |
859
|
|
|
|
|
|
|
pack('CCCC', 0x66, 0x40|$rex, $opcode, 0xC0 | (($reg1 & 7) << 3) | ($reg2 & 7)) |
860
|
|
|
|
|
|
|
: pack('CCC', 0x66, $opcode, 0xC0 | (($reg1 & 7) << 3) | ($reg2 & 7)); |
861
|
553
|
|
|
|
|
776
|
$self; |
862
|
|
|
|
|
|
|
} |
863
|
|
|
|
|
|
|
sub _append_op8_reg_reg { |
864
|
371
|
|
|
371
|
|
376
|
my ($self, $opcode, $reg1, $reg2)= @_; |
865
|
14
|
|
|
14
|
|
1021
|
use integer; |
|
14
|
|
|
|
|
20
|
|
|
14
|
|
|
|
|
37
|
|
866
|
371
|
|
|
|
|
346
|
$reg1= $regnum8{$reg1}; |
867
|
371
|
|
|
|
|
295
|
$reg2= $regnum8{$reg2}; |
868
|
|
|
|
|
|
|
# special case for the "high byte" registers. They can't be used in an |
869
|
|
|
|
|
|
|
# instruction that uses the REX prefix. |
870
|
371
|
50
|
33
|
|
|
1102
|
if (!defined $reg1 || !defined $reg2) { |
871
|
0
|
|
|
|
|
0
|
my $old_reg1= $reg1; |
872
|
0
|
|
|
|
|
0
|
my $old_reg2= $reg2; |
873
|
0
|
|
0
|
|
|
0
|
$reg1= $regnum8_high{$_[2]} // croak "$_[2] is not a valid 8-bit register"; |
874
|
0
|
|
0
|
|
|
0
|
$reg2= $regnum8_high{$_[3]} // croak "$_[3] is not a valid 8-bit register"; |
875
|
0
|
0
|
0
|
|
|
0
|
if (($old_reg1 && $old_reg1 > 3) || ($old_reg2 && $old_reg2 > 3)) { |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
876
|
0
|
|
|
|
|
0
|
croak "Can't combine $_[2] with $_[3] in same instruction"; |
877
|
|
|
|
|
|
|
} |
878
|
0
|
|
|
|
|
0
|
$self->{_buf} .= pack('CC', $opcode, 0xC0 | ($reg1 << 3) | $reg2); |
879
|
|
|
|
|
|
|
} |
880
|
|
|
|
|
|
|
else { |
881
|
371
|
100
|
100
|
|
|
1458
|
$self->{_buf} .= ($reg1 > 3 || $reg2 > 3)? |
882
|
|
|
|
|
|
|
pack('CCC', 0x40|(($reg1 & 8) >> 1) | (($reg2 & 8) >> 3), $opcode, 0xC0 | (($reg1 & 7) << 3) | ($reg2 & 7)) |
883
|
|
|
|
|
|
|
: pack('CC', $opcode, 0xC0 | ($reg1 << 3) | $reg2); |
884
|
|
|
|
|
|
|
} |
885
|
371
|
|
|
|
|
532
|
$self; |
886
|
|
|
|
|
|
|
} |
887
|
|
|
|
|
|
|
|
888
|
|
|
|
|
|
|
# Like above, but the first register argument isn't really a register argument |
889
|
|
|
|
|
|
|
# and therefore doesn't require a 0x40 prefix for values > 3 |
890
|
|
|
|
|
|
|
sub _append_op8_opreg_reg { |
891
|
212
|
|
|
212
|
|
179
|
my ($self, $opcode, $opreg, $reg2)= @_; |
892
|
14
|
|
|
14
|
|
2222
|
use integer; |
|
14
|
|
|
|
|
17
|
|
|
14
|
|
|
|
|
36
|
|
893
|
212
|
|
|
|
|
176
|
$reg2= $regnum8{$reg2}; |
894
|
|
|
|
|
|
|
# special case for the "high byte" registers. They can't be used in an |
895
|
|
|
|
|
|
|
# instruction that uses the REX prefix. |
896
|
212
|
100
|
|
|
|
240
|
if (!defined $reg2) { |
897
|
72
|
|
|
|
|
47
|
my $old_reg2= $reg2; |
898
|
72
|
|
33
|
|
|
129
|
$reg2= $regnum8_high{$_[3]} // croak "$_[3] is not a valid 8-bit register"; |
899
|
72
|
|
|
|
|
151
|
$self->{_buf} .= pack('CC', $opcode, 0xC0 | ($opreg << 3) | $reg2); |
900
|
|
|
|
|
|
|
} |
901
|
|
|
|
|
|
|
else { |
902
|
140
|
100
|
|
|
|
368
|
$self->{_buf} .= ($reg2 > 3)? |
903
|
|
|
|
|
|
|
pack('CCC', 0x40| (($reg2 & 8) >> 3), $opcode, 0xC0 | ($opreg << 3) | ($reg2 & 7)) |
904
|
|
|
|
|
|
|
: pack('CC', $opcode, 0xC0 | ($opreg << 3) | $reg2); |
905
|
|
|
|
|
|
|
} |
906
|
212
|
|
|
|
|
216
|
$self; |
907
|
|
|
|
|
|
|
} |
908
|
|
|
|
|
|
|
|
909
|
|
|
|
|
|
|
|
910
|
|
|
|
|
|
|
sub _append_op64_reg_mem { |
911
|
7938
|
|
|
7938
|
|
7971
|
my ($self, $rex, $opcode, $reg, $mem)= @_; |
912
|
7938
|
|
|
|
|
8028
|
my ($base_reg, $disp, $index_reg, $scale)= @$mem; |
913
|
7938
|
50
|
33
|
|
|
18544
|
$reg= $regnum64{$reg} // croak "$reg is not a valid 64-bit register" |
914
|
|
|
|
|
|
|
if defined $reg; |
915
|
7938
|
100
|
33
|
|
|
13737
|
$base_reg= $regnum64{$base_reg} // croak "$base_reg is not a valid 64-bit register" |
916
|
|
|
|
|
|
|
if defined $base_reg; |
917
|
7938
|
100
|
33
|
|
|
13914
|
$index_reg= $regnum64{$index_reg} // croak "$index_reg is not a valid 64-bit register" |
918
|
|
|
|
|
|
|
if defined $index_reg; |
919
|
7938
|
|
|
|
|
15834
|
$self->_append_possible_unknown('_encode_op_reg_mem', [$rex, $opcode, $reg, $base_reg, $disp, $index_reg, $scale], 4, 7); |
920
|
7938
|
|
|
|
|
13625
|
$self; |
921
|
|
|
|
|
|
|
} |
922
|
|
|
|
|
|
|
|
923
|
|
|
|
|
|
|
sub _append_op32_reg_mem { |
924
|
7686
|
|
|
7686
|
|
7591
|
my ($self, $rex, $opcode, $reg, $mem)= @_; |
925
|
7686
|
|
|
|
|
7571
|
my ($base_reg, $disp, $index_reg, $scale)= @$mem; |
926
|
7686
|
50
|
33
|
|
|
17867
|
$reg= $regnum32{$reg} // croak "$reg is not a valid 32-bit register" |
927
|
|
|
|
|
|
|
if defined $reg; |
928
|
7686
|
100
|
33
|
|
|
13413
|
$base_reg= $regnum64{$base_reg} // croak "$base_reg is not a valid 64-bit register" |
929
|
|
|
|
|
|
|
if defined $base_reg; |
930
|
7686
|
100
|
33
|
|
|
13516
|
$index_reg= $regnum64{$index_reg} // croak "$index_reg is not a valid 64-bit register" |
931
|
|
|
|
|
|
|
if defined $index_reg; |
932
|
7686
|
|
|
|
|
15184
|
$self->_append_possible_unknown('_encode_op_reg_mem', [$rex, $opcode, $reg, $base_reg, $disp, $index_reg, $scale], 4, 7); |
933
|
|
|
|
|
|
|
} |
934
|
|
|
|
|
|
|
|
935
|
|
|
|
|
|
|
sub _append_op16_reg_mem { |
936
|
7686
|
|
|
7686
|
|
7581
|
my ($self, $rex, $opcode, $reg, $mem)= @_; |
937
|
7686
|
|
|
|
|
7664
|
my ($base_reg, $disp, $index_reg, $scale)= @$mem; |
938
|
7686
|
50
|
33
|
|
|
17756
|
$reg= $regnum16{$reg} // croak "$reg is not a valid 16-bit register" |
939
|
|
|
|
|
|
|
if defined $reg; |
940
|
7686
|
100
|
33
|
|
|
13562
|
$base_reg= $regnum64{$base_reg} // croak "$base_reg is not a valid 64-bit register" |
941
|
|
|
|
|
|
|
if defined $base_reg; |
942
|
7686
|
100
|
33
|
|
|
13746
|
$index_reg= $regnum64{$index_reg} // croak "$index_reg is not a valid 64-bit register" |
943
|
|
|
|
|
|
|
if defined $index_reg; |
944
|
7686
|
|
|
|
|
8734
|
$self->{_buf} .= "\x66"; |
945
|
7686
|
|
|
|
|
15589
|
$self->_append_possible_unknown('_encode_op_reg_mem', [$rex, $opcode, $reg, $base_reg, $disp, $index_reg, $scale], 4, 7); |
946
|
|
|
|
|
|
|
} |
947
|
|
|
|
|
|
|
|
948
|
|
|
|
|
|
|
sub _append_op8_reg_mem { |
949
|
6426
|
|
|
6426
|
|
6590
|
my ($self, $rex, $opcode, $reg, $mem)= @_; |
950
|
6426
|
|
|
|
|
6487
|
my ($base_reg, $disp, $index_reg, $scale)= @$mem; |
951
|
6426
|
100
|
33
|
|
|
14284
|
$base_reg= $regnum64{$base_reg} // croak "$base_reg is not a valid 64-bit register" |
952
|
|
|
|
|
|
|
if defined $base_reg; |
953
|
6426
|
100
|
33
|
|
|
11540
|
$index_reg= $regnum64{$index_reg} // croak "$index_reg is not a valid 64-bit register" |
954
|
|
|
|
|
|
|
if defined $index_reg; |
955
|
6426
|
|
|
|
|
5264
|
$reg= $regnum8{$reg}; |
956
|
|
|
|
|
|
|
# special case for the "high byte" registers |
957
|
6426
|
50
|
|
|
|
11586
|
if (!defined $reg) { |
|
|
100
|
|
|
|
|
|
958
|
0
|
|
0
|
|
|
0
|
$reg= $regnum8_high{$_[3]} // croak "$_[3] is not a valid 8-bit register"; |
959
|
0
|
0
|
0
|
|
|
0
|
!$rex && ($base_reg//0) < 8 && ($index_reg//0) < 8 |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
960
|
|
|
|
|
|
|
or croak "Cannot use $_[3] in instruction with REX prefix"; |
961
|
|
|
|
|
|
|
} |
962
|
|
|
|
|
|
|
# special case for needing REX byte for SPL, BPL, DIL, and SIL |
963
|
|
|
|
|
|
|
elsif ($reg > 3) { |
964
|
4410
|
|
|
|
|
3718
|
$rex |= 0x40; |
965
|
|
|
|
|
|
|
} |
966
|
6426
|
|
|
|
|
13386
|
$self->_append_possible_unknown('_encode_op_reg_mem', [$rex, $opcode, $reg, $base_reg, $disp, $index_reg, $scale], 4, 7); |
967
|
|
|
|
|
|
|
} |
968
|
|
|
|
|
|
|
# Like above, but the first register is a constant and don't need to test it for |
969
|
|
|
|
|
|
|
# requiring a REX prefix if >3. |
970
|
|
|
|
|
|
|
sub _append_op8_opreg_mem { |
971
|
1260
|
|
|
1260
|
|
1023
|
my ($self, $rex, $opcode, $opreg, $mem)= @_; |
972
|
1260
|
|
|
|
|
1234
|
my ($base_reg, $disp, $index_reg, $scale)= @$mem; |
973
|
1260
|
100
|
33
|
|
|
2644
|
$base_reg= $regnum64{$base_reg} // croak "$base_reg is not a valid 64-bit register" |
974
|
|
|
|
|
|
|
if defined $base_reg; |
975
|
1260
|
100
|
33
|
|
|
2327
|
$index_reg= $regnum64{$index_reg} // croak "$index_reg is not a valid 64-bit register" |
976
|
|
|
|
|
|
|
if defined $index_reg; |
977
|
1260
|
|
|
|
|
2249
|
$self->_append_possible_unknown('_encode_op_reg_mem', [$rex, $opcode, $opreg, $base_reg, $disp, $index_reg, $scale], 4, 7); |
978
|
|
|
|
|
|
|
} |
979
|
|
|
|
|
|
|
|
980
|
|
|
|
|
|
|
# scale values for the SIB byte |
981
|
|
|
|
|
|
|
my %SIB_scale= ( |
982
|
|
|
|
|
|
|
1 => 0x00, |
983
|
|
|
|
|
|
|
2 => 0x40, |
984
|
|
|
|
|
|
|
4 => 0x80, |
985
|
|
|
|
|
|
|
8 => 0xC0 |
986
|
|
|
|
|
|
|
); |
987
|
|
|
|
|
|
|
|
988
|
|
|
|
|
|
|
sub _encode_op_reg_mem { |
989
|
43344
|
|
|
43344
|
|
46294
|
my ($self, $rex, $opcode, $reg, $base_reg, $disp, $index_reg, $scale, $immed_pack, $immed)= @_; |
990
|
14
|
|
|
14
|
|
7938
|
use integer; |
|
14
|
|
|
|
|
14
|
|
|
14
|
|
|
|
|
60
|
|
991
|
43344
|
|
|
|
|
41051
|
$rex |= ($reg & 8) >> 1; |
992
|
|
|
|
|
|
|
|
993
|
43344
|
|
|
|
|
27461
|
my $tail; |
994
|
43344
|
100
|
|
|
|
45528
|
if (defined $base_reg) { |
995
|
33024
|
|
|
|
|
23121
|
$rex |= ($base_reg & 8) >> 3; |
996
|
|
|
|
|
|
|
|
997
|
|
|
|
|
|
|
# RBP,R13 always gets mod_rm displacement to differentiate from Null base register |
998
|
33024
|
100
|
|
|
|
77039
|
my ($mod_rm, $suffix)= !$disp? ( ($base_reg&7) == 5? (0x40, "\0") : (0x00, '') ) |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
999
|
|
|
|
|
|
|
: (($disp >> 7) == ($disp >> 8))? (0x40, pack('c', $disp)) |
1000
|
|
|
|
|
|
|
: (($disp >> 31) == ($disp >> 32))? (0x80, pack('V', $disp)) |
1001
|
|
|
|
|
|
|
: croak "address displacement out of range: $disp"; |
1002
|
|
|
|
|
|
|
|
1003
|
33024
|
100
|
|
|
|
36528
|
if (defined $index_reg) { |
|
|
100
|
|
|
|
|
|
1004
|
24768
|
|
50
|
|
|
54124
|
my $scale= $SIB_scale{$scale // 1} // croak "invalid index multiplier $scale"; |
|
|
|
33
|
|
|
|
|
1005
|
24768
|
50
|
|
|
|
32349
|
$index_reg != 4 or croak "RSP cannot be used as index register"; |
1006
|
24768
|
|
|
|
|
18884
|
$rex |= ($index_reg & 8) >> 2; |
1007
|
24768
|
|
|
|
|
47744
|
$tail= pack('CC', $mod_rm | (($reg & 7) << 3) | 4, $scale | (($index_reg & 7) << 3) | ($base_reg & 7)) . $suffix; |
1008
|
|
|
|
|
|
|
} |
1009
|
|
|
|
|
|
|
# RSP,R12 always gets a SIB byte |
1010
|
|
|
|
|
|
|
elsif (($base_reg&7) == 4) { |
1011
|
2752
|
|
|
|
|
4720
|
$tail= pack('CC', $mod_rm | (($reg & 7) << 3) | 4, 0x24) . $suffix; |
1012
|
|
|
|
|
|
|
} |
1013
|
|
|
|
|
|
|
else { |
1014
|
|
|
|
|
|
|
# Null index register is encoded as RSP |
1015
|
5504
|
|
|
|
|
9308
|
$tail= pack('C', $mod_rm | (($reg & 7) << 3) | ($base_reg & 7)) . $suffix; |
1016
|
|
|
|
|
|
|
} |
1017
|
|
|
|
|
|
|
} else { |
1018
|
|
|
|
|
|
|
# Null base register is encoded as RBP + 32bit displacement |
1019
|
|
|
|
|
|
|
|
1020
|
10320
|
50
|
|
|
|
14873
|
(($disp >> 31) == ($disp >> 32)) |
1021
|
|
|
|
|
|
|
or croak "address displacement out of range: $disp"; |
1022
|
|
|
|
|
|
|
|
1023
|
10320
|
100
|
|
|
|
11029
|
if (defined $index_reg) { |
1024
|
8256
|
|
50
|
|
|
17063
|
my $scale= $SIB_scale{$scale // 1} // croak "invalid index multiplier $scale"; |
|
|
|
33
|
|
|
|
|
1025
|
8256
|
50
|
|
|
|
10189
|
$index_reg != 4 or croak "RSP cannot be used as index register"; |
1026
|
8256
|
|
|
|
|
6480
|
$rex |= ($index_reg & 8) >> 2; |
1027
|
8256
|
|
|
|
|
17717
|
$tail= pack('CCV', (($reg & 7) << 3) | 4, $scale | (($index_reg & 7) << 3) | 5, $disp); |
1028
|
|
|
|
|
|
|
} |
1029
|
|
|
|
|
|
|
else { |
1030
|
|
|
|
|
|
|
# Null index register is encoded as RSP |
1031
|
2064
|
|
|
|
|
4159
|
$tail= pack('CCV', (($reg & 7) << 3) | 4, 0x25, $disp); |
1032
|
|
|
|
|
|
|
} |
1033
|
|
|
|
|
|
|
} |
1034
|
43344
|
100
|
|
|
|
55053
|
$tail .= pack($immed_pack, $immed) |
1035
|
|
|
|
|
|
|
if defined $immed; |
1036
|
|
|
|
|
|
|
|
1037
|
43344
|
100
|
|
|
|
98743
|
return $rex? |
1038
|
|
|
|
|
|
|
pack('CC', ($rex|0x40), $opcode) . $tail |
1039
|
|
|
|
|
|
|
: pack('C', $opcode) . $tail; |
1040
|
|
|
|
|
|
|
} |
1041
|
|
|
|
|
|
|
|
1042
|
|
|
|
|
|
|
|
1043
|
|
|
|
|
|
|
sub _append_mathop64_const { |
1044
|
392
|
|
|
392
|
|
602
|
my ($self, @args)= @_; # $opcodeAX32, $opcode8, $opcode32, $opcode_reg, $reg, $immed |
1045
|
392
|
|
33
|
|
|
773
|
$args[4]= $regnum64{$args[4]} // croak("$args[4] is not a 64-bit register"); |
1046
|
392
|
|
|
|
|
603
|
$self->_append_possible_unknown('_encode_mathop64_imm', \@args, 5, 7); |
1047
|
|
|
|
|
|
|
} |
1048
|
|
|
|
|
|
|
sub _encode_mathop64_imm { |
1049
|
392
|
|
|
392
|
|
358
|
my ($self, $opcodeAX32, $opcode8, $opcode32, $opcode_reg, $reg, $value)= @_; |
1050
|
14
|
|
|
14
|
|
4550
|
use integer; |
|
14
|
|
|
|
|
16
|
|
|
14
|
|
|
|
|
36
|
|
1051
|
392
|
|
|
|
|
400
|
my $rex= 0x48 | (($reg & 8)>>3); |
1052
|
392
|
100
|
100
|
|
|
2061
|
defined $opcode8 && (($value >> 7) == ($value >> 8))? |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1053
|
|
|
|
|
|
|
pack('CCCc', $rex, $opcode8, 0xC0 | ($opcode_reg << 3) | ($reg & 7), $value) |
1054
|
|
|
|
|
|
|
: (($value >> 31) == ($value >> 32))? ( |
1055
|
|
|
|
|
|
|
# Ops on AX get encoded as a special instruction |
1056
|
|
|
|
|
|
|
$reg? pack('CCCV', $rex, $opcode32, 0xC0 | ($opcode_reg << 3) | ($reg & 7), $value) |
1057
|
|
|
|
|
|
|
: pack('CCV', $rex, $opcodeAX32, $value) |
1058
|
|
|
|
|
|
|
) |
1059
|
|
|
|
|
|
|
# 64-bit only supports 32-bit sign-extend immediate |
1060
|
|
|
|
|
|
|
: croak "$value is wider than 32-bit"; |
1061
|
|
|
|
|
|
|
} |
1062
|
|
|
|
|
|
|
|
1063
|
|
|
|
|
|
|
|
1064
|
|
|
|
|
|
|
sub _append_mathop32_const { |
1065
|
392
|
|
|
392
|
|
589
|
my ($self, @args)= @_; # $opcodeAX32, $opcode8, $opcode32, $opcode_reg, $reg, $immed |
1066
|
392
|
|
33
|
|
|
739
|
$args[4]= $regnum32{$args[4]} // croak("$args[4] is not a 32-bit register"); |
1067
|
392
|
|
|
|
|
607
|
$self->_append_possible_unknown('_encode_mathop32_imm', \@args, 5, 7); |
1068
|
|
|
|
|
|
|
} |
1069
|
|
|
|
|
|
|
sub _encode_mathop32_imm { |
1070
|
392
|
|
|
392
|
|
377
|
my ($self, $opcodeAX32, $opcode8, $opcode32, $opcode_reg, $reg, $value)= @_; |
1071
|
14
|
|
|
14
|
|
2005
|
use integer; |
|
14
|
|
|
|
|
12
|
|
|
14
|
|
|
|
|
37
|
|
1072
|
392
|
|
|
|
|
366
|
my $rex= (($reg & 8)>>3); |
1073
|
392
|
100
|
66
|
|
|
2232
|
defined $opcode8 && (($value >> 7) == ($value >> 8) or ($value >> 8 == 0xFFFFFF))? |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1074
|
|
|
|
|
|
|
( $rex? pack('CCCC', 0x40|$rex, $opcode8, 0xC0 | ($opcode_reg << 3) | ($reg & 7), $value&0xFF) |
1075
|
|
|
|
|
|
|
: pack('CCC', $opcode8, 0xC0 | ($opcode_reg << 3) | ($reg & 7), $value&0xFF) |
1076
|
|
|
|
|
|
|
) |
1077
|
|
|
|
|
|
|
: (($value >> 32) == ($value >> 33))? ( |
1078
|
|
|
|
|
|
|
# Ops on AX get encoded as a special instruction |
1079
|
|
|
|
|
|
|
$rex? pack('CCCV', 0x40|$rex, $opcode32, 0xC0 | ($opcode_reg << 3) | ($reg & 7), $value) |
1080
|
|
|
|
|
|
|
: $reg? pack('CCV', $opcode32, 0xC0 | ($opcode_reg << 3) | ($reg & 7), $value) |
1081
|
|
|
|
|
|
|
: pack('CV', $opcodeAX32, $value) |
1082
|
|
|
|
|
|
|
) |
1083
|
|
|
|
|
|
|
: croak "$value is wider than 32-bit"; |
1084
|
|
|
|
|
|
|
} |
1085
|
|
|
|
|
|
|
|
1086
|
|
|
|
|
|
|
|
1087
|
|
|
|
|
|
|
sub _append_mathop16_const { |
1088
|
343
|
|
|
343
|
|
538
|
my ($self, @args)= @_; # $opcodeAX16, $opcode8, $opcode16, $opcode_reg, $reg, $immed |
1089
|
343
|
|
33
|
|
|
644
|
$args[4]= $regnum16{$args[4]} // croak("$args[4] is not a 16-bit register"); |
1090
|
343
|
|
|
|
|
505
|
$self->_append_possible_unknown('_encode_mathop16_imm', \@args, 5, 8); |
1091
|
|
|
|
|
|
|
} |
1092
|
|
|
|
|
|
|
sub _encode_mathop16_imm { |
1093
|
343
|
|
|
343
|
|
313
|
my ($self, $opcodeAX16, $opcode8, $opcode16, $opcode_reg, $reg, $value)= @_; |
1094
|
14
|
|
|
14
|
|
2353
|
use integer; |
|
14
|
|
|
|
|
13
|
|
|
14
|
|
|
|
|
34
|
|
1095
|
343
|
|
|
|
|
308
|
my $rex= (($reg & 8)>>3); |
1096
|
343
|
100
|
66
|
|
|
1982
|
defined $opcode8 && (($value >> 7) == ($value >> 8) or ($value >> 8 == 0xFF))? |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1097
|
|
|
|
|
|
|
( $rex? pack('CCCCC', 0x66, 0x40|$rex, $opcode8, 0xC0 | ($opcode_reg << 3) | ($reg & 7), $value&0xFF) |
1098
|
|
|
|
|
|
|
: pack('CCCC', 0x66, $opcode8, 0xC0 | ($opcode_reg << 3) | ($reg & 7), $value&0xFF) |
1099
|
|
|
|
|
|
|
) |
1100
|
|
|
|
|
|
|
: (($value >> 16) == ($value >> 17))? ( |
1101
|
|
|
|
|
|
|
# Ops on AX get encoded as a special instruction |
1102
|
|
|
|
|
|
|
$rex? pack('CCCCv', 0x66, 0x40|$rex, $opcode16, 0xC0 | ($opcode_reg << 3) | ($reg & 7), $value&0xFFFF) |
1103
|
|
|
|
|
|
|
: $reg? pack('CCCv', 0x66, $opcode16, 0xC0 | ($opcode_reg << 3) | ($reg & 7), $value&0xFFFF) |
1104
|
|
|
|
|
|
|
: pack('CCv', 0x66, $opcodeAX16, $value) |
1105
|
|
|
|
|
|
|
) |
1106
|
|
|
|
|
|
|
: croak "$value is wider than 16-bit"; |
1107
|
|
|
|
|
|
|
} |
1108
|
|
|
|
|
|
|
|
1109
|
|
|
|
|
|
|
|
1110
|
|
|
|
|
|
|
sub _append_mathop8_const { |
1111
|
245
|
|
|
245
|
|
256
|
my ($self, $opcodeAX8, $opcode8, $opcode_reg, $reg, $immed)= @_; |
1112
|
14
|
|
|
14
|
|
1738
|
use integer; |
|
14
|
|
|
|
|
12
|
|
|
14
|
|
|
|
|
33
|
|
1113
|
245
|
|
|
|
|
223
|
$reg= $regnum8{$reg}; |
1114
|
245
|
50
|
|
|
|
287
|
my $value= ref $immed? 0x00 : $immed; |
1115
|
245
|
50
|
|
|
|
390
|
(($value >> 8) == ($value >> 9)) or croak "$value is wider than 8 bits"; |
1116
|
245
|
50
|
|
|
|
462
|
if (!defined $reg) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1117
|
0
|
|
0
|
|
|
0
|
$reg= $regnum8_high{$_[1]} // croak("$reg is not a 8-bit register"); |
1118
|
0
|
|
|
|
|
0
|
$self->{_buf} .= pack('CCC', $opcode8, 0xC0 | ($opcode_reg<<3) | ($reg & 7), $value&0xFF); |
1119
|
|
|
|
|
|
|
} elsif (!$reg) { |
1120
|
35
|
|
|
|
|
80
|
$self->{_buf} .= pack('CC', $opcodeAX8, $value&0xFF); |
1121
|
|
|
|
|
|
|
} elsif ($reg > 3) { |
1122
|
175
|
|
|
|
|
428
|
$self->{_buf} .= pack('CCCC', 0x40|(($reg & 8)>>3), $opcode8, 0xC0 | ($opcode_reg << 3) | ($reg & 7), $value&0xFF); |
1123
|
|
|
|
|
|
|
} else { |
1124
|
35
|
|
|
|
|
96
|
$self->{_buf} .= pack('CCC', $opcode8, 0xC0 | ($opcode_reg << 3) | ($reg & 7), $value&0xFF); |
1125
|
|
|
|
|
|
|
} |
1126
|
245
|
50
|
|
|
|
302
|
$self->_mark_unresolved(-1, encode => '_repack', bits => 8, value => $immed) |
1127
|
|
|
|
|
|
|
if ref $immed; |
1128
|
245
|
|
|
|
|
348
|
$self; |
1129
|
|
|
|
|
|
|
} |
1130
|
|
|
|
|
|
|
|
1131
|
|
|
|
|
|
|
sub _append_mathop64_const_to_mem { |
1132
|
3528
|
|
|
3528
|
|
3771
|
my ($self, $opcode8, $opcode32, $opcode_reg, $value, $mem)= @_; |
1133
|
3528
|
|
|
|
|
3591
|
my ($base_reg, $disp, $index_reg, $scale)= @$mem; |
1134
|
3528
|
100
|
33
|
|
|
7788
|
$base_reg= ($regnum64{$base_reg} // croak "$base_reg is not a 64-bit register") |
1135
|
|
|
|
|
|
|
if defined $base_reg; |
1136
|
3528
|
100
|
33
|
|
|
6481
|
$index_reg= ($regnum64{$index_reg} // croak "$index_reg is not a 64-bit register") |
1137
|
|
|
|
|
|
|
if defined $index_reg; |
1138
|
3528
|
50
|
|
|
|
9238
|
$self->_append_possible_unknown('_encode_mathop64_mem_immed', [ $opcode8, $opcode32, $opcode_reg, $value, $base_reg, $disp, $index_reg, $scale ], 3, defined $disp? 9:12); |
1139
|
|
|
|
|
|
|
} |
1140
|
|
|
|
|
|
|
sub _encode_mathop64_mem_immed { |
1141
|
3528
|
|
|
3528
|
|
3717
|
my ($self, $opcode8, $opcode32, $opcode_reg, $value, $base_reg, $disp, $index_reg, $scale)= @_; |
1142
|
14
|
|
|
14
|
|
3532
|
use integer; |
|
14
|
|
|
|
|
20
|
|
|
14
|
|
|
|
|
52
|
|
1143
|
3528
|
50
|
100
|
|
|
13728
|
defined $opcode8 && (($value >> 7) == ($value >> 8))? |
|
|
100
|
|
|
|
|
|
1144
|
|
|
|
|
|
|
$self->_encode_op_reg_mem(8, $opcode8, $opcode_reg, $base_reg, $disp, $index_reg, $scale, 'C', $value&0xFF) |
1145
|
|
|
|
|
|
|
: (($value >> 31) == ($value >> 32))? |
1146
|
|
|
|
|
|
|
$self->_encode_op_reg_mem(8, $opcode32, $opcode_reg, $base_reg, $disp, $index_reg, $scale, 'V', $value&0xFFFFFFFF) |
1147
|
|
|
|
|
|
|
: croak "$value is wider than 31-bit"; |
1148
|
|
|
|
|
|
|
} |
1149
|
|
|
|
|
|
|
|
1150
|
|
|
|
|
|
|
sub _append_mathop32_const_to_mem { |
1151
|
3528
|
|
|
3528
|
|
3739
|
my ($self, $opcode8, $opcode32, $opcode_reg, $value, $mem)= @_; |
1152
|
3528
|
|
|
|
|
3480
|
my ($base_reg, $disp, $index_reg, $scale)= @$mem; |
1153
|
3528
|
100
|
33
|
|
|
7581
|
$base_reg= ($regnum64{$base_reg} // croak "$base_reg is not a 64-bit register") |
1154
|
|
|
|
|
|
|
if defined $base_reg; |
1155
|
3528
|
100
|
33
|
|
|
6380
|
$index_reg= ($regnum64{$index_reg} // croak "$index_reg is not a 64-bit register") |
1156
|
|
|
|
|
|
|
if defined $index_reg; |
1157
|
3528
|
50
|
|
|
|
8719
|
$self->_append_possible_unknown('_encode_mathop32_mem_immed', [ $opcode8, $opcode32, $opcode_reg, $value, $base_reg, $disp, $index_reg, $scale ], 3, defined $disp? 12:8); |
1158
|
|
|
|
|
|
|
} |
1159
|
|
|
|
|
|
|
sub _encode_mathop32_mem_immed { |
1160
|
3528
|
|
|
3528
|
|
3623
|
my ($self, $opcode8, $opcode32, $opcode_reg, $value, $base_reg, $disp, $index_reg, $scale)= @_; |
1161
|
14
|
|
|
14
|
|
2262
|
use integer; |
|
14
|
|
|
|
|
15
|
|
|
14
|
|
|
|
|
31
|
|
1162
|
3528
|
50
|
66
|
|
|
13015
|
defined $opcode8 && (($value >> 7) == ($value >> 8) or ($value >> 8 == 0xFFFFFF))? |
|
|
100
|
|
|
|
|
|
1163
|
|
|
|
|
|
|
$self->_encode_op_reg_mem(0, $opcode8, $opcode_reg, $base_reg, $disp, $index_reg, $scale).pack('C',$value&0xFF) |
1164
|
|
|
|
|
|
|
: (($value >> 32) == ($value >> 33))? |
1165
|
|
|
|
|
|
|
$self->_encode_op_reg_mem(0, $opcode32, $opcode_reg, $base_reg, $disp, $index_reg, $scale).pack('V', $value&0xFFFFFFFF) |
1166
|
|
|
|
|
|
|
: croak "$value is wider than 32-bit"; |
1167
|
|
|
|
|
|
|
} |
1168
|
|
|
|
|
|
|
|
1169
|
|
|
|
|
|
|
sub _append_mathop16_const_to_mem { |
1170
|
3087
|
|
|
3087
|
|
3144
|
my ($self, $opcode8, $opcode16, $opcode_reg, $value, $mem)= @_; |
1171
|
3087
|
|
|
|
|
3128
|
my ($base_reg, $disp, $index_reg, $scale)= @$mem; |
1172
|
3087
|
100
|
33
|
|
|
6629
|
$base_reg= ($regnum64{$base_reg} // croak "$base_reg is not a 64-bit register") |
1173
|
|
|
|
|
|
|
if defined $base_reg; |
1174
|
3087
|
100
|
33
|
|
|
5647
|
$index_reg= ($regnum64{$index_reg} // croak "$index_reg is not a 64-bit register") |
1175
|
|
|
|
|
|
|
if defined $index_reg; |
1176
|
3087
|
|
|
|
|
3318
|
$self->{_buf} .= "\x66"; |
1177
|
3087
|
50
|
|
|
|
7692
|
$self->_append_possible_unknown('_encode_mathop16_mem_immed', [ $opcode8, $opcode16, $opcode_reg, $value, $base_reg, $disp, $index_reg, $scale ], 3, defined $disp? 10:6); |
1178
|
|
|
|
|
|
|
} |
1179
|
|
|
|
|
|
|
sub _encode_mathop16_mem_immed { |
1180
|
3087
|
|
|
3087
|
|
3145
|
my ($self, $opcode8, $opcode16, $opcode_reg, $value, $base_reg, $disp, $index_reg, $scale)= @_; |
1181
|
14
|
|
|
14
|
|
2323
|
use integer; |
|
14
|
|
|
|
|
16
|
|
|
14
|
|
|
|
|
31
|
|
1182
|
3087
|
50
|
66
|
|
|
11302
|
defined $opcode8 && (($value >> 7) == ($value >> 8) or ($value >> 8 == 0xFF))? |
|
|
100
|
|
|
|
|
|
1183
|
|
|
|
|
|
|
$self->_encode_op_reg_mem(0, $opcode8, $opcode_reg, $base_reg, $disp, $index_reg, $scale).pack('C',$value&0xFF) |
1184
|
|
|
|
|
|
|
: (($value >> 16) == ($value >> 17))? |
1185
|
|
|
|
|
|
|
$self->_encode_op_reg_mem(0, $opcode16, $opcode_reg, $base_reg, $disp, $index_reg, $scale).pack('v', $value&0xFFFF) |
1186
|
|
|
|
|
|
|
: croak "$value is wider than 16-bit"; |
1187
|
|
|
|
|
|
|
} |
1188
|
|
|
|
|
|
|
|
1189
|
|
|
|
|
|
|
sub _append_mathop8_const_to_mem { |
1190
|
2205
|
|
|
2205
|
|
2269
|
my ($self, $opcode8, $opcode_reg, $value, $mem)= @_; |
1191
|
2205
|
|
|
|
|
2191
|
my ($base_reg, $disp, $index_reg, $scale)= @$mem; |
1192
|
2205
|
100
|
33
|
|
|
4579
|
$base_reg= ($regnum64{$base_reg} // croak "$base_reg is not a 64-bit register") |
1193
|
|
|
|
|
|
|
if defined $base_reg; |
1194
|
2205
|
100
|
33
|
|
|
4058
|
$index_reg= ($regnum64{$index_reg} // croak "$index_reg is not a 64-bit register") |
1195
|
|
|
|
|
|
|
if defined $index_reg; |
1196
|
2205
|
50
|
|
|
|
5400
|
$self->_append_possible_unknown('_encode_mathop8_mem_immed', [ $opcode8, $opcode_reg, $value, $base_reg, $disp, $index_reg, $scale ], 2, defined $disp? 10:6); |
1197
|
|
|
|
|
|
|
} |
1198
|
|
|
|
|
|
|
sub _encode_mathop8_mem_immed { |
1199
|
2205
|
|
|
2205
|
|
2188
|
my ($self, $opcode8, $opcode_reg, $value, $base_reg, $disp, $index_reg, $scale)= @_; |
1200
|
14
|
|
|
14
|
|
2125
|
use integer; |
|
14
|
|
|
|
|
12
|
|
|
14
|
|
|
|
|
166
|
|
1201
|
2205
|
50
|
|
|
|
3345
|
(($value >> 8) == ($value >> 9)) or croak "$value is wider than 8 bit"; |
1202
|
2205
|
|
|
|
|
2719
|
$self->_encode_op_reg_mem(0, $opcode8, $opcode_reg, $base_reg, $disp, $index_reg, $scale).pack('C',$value&0xFF); |
1203
|
|
|
|
|
|
|
} |
1204
|
|
|
|
|
|
|
|
1205
|
|
|
|
|
|
|
|
1206
|
|
|
|
|
|
|
sub _append_shiftop_reg_imm { |
1207
|
732
|
|
|
732
|
|
740
|
my ($self, $bits, $opcode_sh1, $opcode_imm, $opreg, $reg, $immed)= @_; |
1208
|
|
|
|
|
|
|
|
1209
|
|
|
|
|
|
|
# Select appropriate opcode |
1210
|
732
|
100
|
|
|
|
890
|
my $op= $immed eq 1? $opcode_sh1 : $opcode_imm; |
1211
|
|
|
|
|
|
|
|
1212
|
732
|
100
|
|
|
|
1441
|
$bits == 64? $self->_append_op64_reg_reg($op, $opreg, $reg) |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1213
|
|
|
|
|
|
|
: $bits == 32? $self->_append_op32_reg_reg($op, $opreg, $reg) |
1214
|
|
|
|
|
|
|
: $bits == 16? $self->_append_op16_reg_reg($op, $opreg, $reg) |
1215
|
|
|
|
|
|
|
: $self->_append_op8_opreg_reg($op, $opreg, $reg); |
1216
|
|
|
|
|
|
|
|
1217
|
|
|
|
|
|
|
# If not using the shift-one opcode, append an immediate byte. |
1218
|
732
|
100
|
|
|
|
988
|
unless ($immed eq 1) { |
1219
|
636
|
50
|
|
|
|
813
|
$self->{_buf} .= pack('C', ref $immed? 0 : $immed); |
1220
|
636
|
50
|
|
|
|
832
|
$self->_mark_unresolved(-1, encode => '_repack', bits => 8, value => $immed) |
1221
|
|
|
|
|
|
|
if ref $immed; |
1222
|
|
|
|
|
|
|
} |
1223
|
|
|
|
|
|
|
|
1224
|
732
|
|
|
|
|
950
|
$self; |
1225
|
|
|
|
|
|
|
} |
1226
|
|
|
|
|
|
|
|
1227
|
|
|
|
|
|
|
|
1228
|
|
|
|
|
|
|
sub _append_shiftop_mem_imm { |
1229
|
3780
|
|
|
3780
|
|
4145
|
my ($self, $bits, $opcode_sh1, $opcode_imm, $opreg, $mem, $immed)= @_; |
1230
|
|
|
|
|
|
|
|
1231
|
|
|
|
|
|
|
# Select appropriate opcode |
1232
|
3780
|
100
|
|
|
|
4794
|
my $op= $immed eq 1? $opcode_sh1 : $opcode_imm; |
1233
|
|
|
|
|
|
|
|
1234
|
3780
|
100
|
|
|
|
8170
|
$bits == 64? $self->_append_op64_reg_mem(8, $op, $opreg, $mem) |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1235
|
|
|
|
|
|
|
: $bits == 32? $self->_append_op32_reg_mem(0, $op, $opreg, $mem) |
1236
|
|
|
|
|
|
|
: $bits == 16? $self->_append_op16_reg_mem(0, $op, $opreg, $mem) |
1237
|
|
|
|
|
|
|
: $self->_append_op8_opreg_mem(0, $op, $opreg, $mem); |
1238
|
|
|
|
|
|
|
|
1239
|
|
|
|
|
|
|
# If not using the shift-one opcode, append an immediate byte. |
1240
|
3780
|
100
|
|
|
|
5890
|
unless ($immed eq 1) { |
1241
|
3024
|
50
|
|
|
|
4300
|
$self->{_buf} .= pack('C', ref $immed? 0 : $immed); |
1242
|
3024
|
50
|
|
|
|
3727
|
$self->_mark_unresolved(-1, encode => '_repack', bits => 8, value => $immed) |
1243
|
|
|
|
|
|
|
if ref $immed; |
1244
|
|
|
|
|
|
|
} |
1245
|
|
|
|
|
|
|
|
1246
|
3780
|
|
|
|
|
5708
|
$self; |
1247
|
|
|
|
|
|
|
} |
1248
|
|
|
|
|
|
|
|
1249
|
|
|
|
|
|
|
|
1250
|
|
|
|
|
|
|
sub _append_jmp_cond { |
1251
|
64
|
50
|
|
64
|
|
105
|
$_[2]= $_[0]->get_label unless defined $_[2]; |
1252
|
|
|
|
|
|
|
|
1253
|
64
|
|
|
|
|
64
|
my ($self, $cond, $label)= @_; |
1254
|
14
|
|
|
14
|
|
3550
|
use integer; |
|
14
|
|
|
|
|
12
|
|
|
14
|
|
|
|
|
34
|
|
1255
|
64
|
50
|
|
|
|
125
|
$label= $self->get_label($label) |
1256
|
|
|
|
|
|
|
unless ref $label; |
1257
|
|
|
|
|
|
|
$self->_mark_unresolved( |
1258
|
|
|
|
|
|
|
2, # estimated length |
1259
|
|
|
|
|
|
|
encode => sub { |
1260
|
128
|
|
|
128
|
|
91
|
my ($self, $params)= @_; |
1261
|
128
|
50
|
|
|
|
186
|
defined $label->{start} or croak "Label $label is not marked"; |
1262
|
128
|
|
|
|
|
104
|
my $ofs= $label->{start} - ($params->{start}+$params->{len}); |
1263
|
128
|
|
|
|
|
115
|
my $short= (($ofs>>7) == ($ofs>>8)); |
1264
|
128
|
100
|
|
|
|
295
|
return $short? |
1265
|
|
|
|
|
|
|
pack('Cc', 0x70 + $cond, $ofs) |
1266
|
|
|
|
|
|
|
: pack('CCV', 0x0F, 0x80 + $cond, $ofs); |
1267
|
|
|
|
|
|
|
} |
1268
|
64
|
|
|
|
|
178
|
); |
1269
|
64
|
|
|
|
|
90
|
$self; |
1270
|
|
|
|
|
|
|
} |
1271
|
|
|
|
|
|
|
|
1272
|
|
|
|
|
|
|
sub _append_jmp_cx { |
1273
|
8
|
|
|
8
|
|
8
|
my ($self, $op, $label)= @_; |
1274
|
14
|
|
|
14
|
|
1778
|
use integer; |
|
14
|
|
|
|
|
15
|
|
|
14
|
|
|
|
|
30
|
|
1275
|
8
|
50
|
|
|
|
17
|
$label= $self->get_label($label) |
1276
|
|
|
|
|
|
|
unless ref $label; |
1277
|
|
|
|
|
|
|
$self->_mark_unresolved( |
1278
|
|
|
|
|
|
|
2, # estimated length |
1279
|
|
|
|
|
|
|
encode => sub { |
1280
|
8
|
|
|
8
|
|
8
|
my ($self, $params)= @_; |
1281
|
8
|
50
|
|
|
|
11
|
defined $label->{start} or croak "Label $label is not marked"; |
1282
|
8
|
|
|
|
|
9
|
my $ofs= $label->{start} - ($params->{start}+$params->{len}); |
1283
|
8
|
50
|
|
|
|
13
|
(($ofs>>7) == ($ofs>>8)) or croak "Label too far, can only short-jump"; |
1284
|
8
|
|
|
|
|
19
|
return pack('Cc', $op, $ofs); |
1285
|
|
|
|
|
|
|
} |
1286
|
8
|
|
|
|
|
25
|
); |
1287
|
8
|
|
|
|
|
12
|
return $self; |
1288
|
|
|
|
|
|
|
} |
1289
|
|
|
|
|
|
|
|
1290
|
|
|
|
|
|
|
sub _append_possible_unknown { |
1291
|
44694
|
|
|
44694
|
|
41698
|
my ($self, $encoder, $encoder_args, $unknown_pos, $estimated_length)= @_; |
1292
|
44694
|
50
|
|
|
|
53770
|
if (ref $encoder_args->[$unknown_pos]) { |
1293
|
|
|
|
|
|
|
$self->mark_unresolved( |
1294
|
|
|
|
|
|
|
$estimated_length, |
1295
|
|
|
|
|
|
|
encode => sub { |
1296
|
0
|
|
|
0
|
|
0
|
my $self= shift; |
1297
|
0
|
|
|
|
|
0
|
my @args= @$encoder_args; |
1298
|
0
|
|
0
|
|
|
0
|
$args[$unknown_pos]= $args[$unknown_pos]->value |
1299
|
|
|
|
|
|
|
// croak "Value $encoder_args->[$unknown_pos] is still unresolved"; |
1300
|
0
|
|
|
|
|
0
|
$self->$encoder(@args); |
1301
|
|
|
|
|
|
|
}, |
1302
|
0
|
|
|
|
|
0
|
); |
1303
|
|
|
|
|
|
|
} |
1304
|
|
|
|
|
|
|
else { |
1305
|
44694
|
|
|
|
|
79134
|
$self->{_buf} .= $self->$encoder(@$encoder_args); |
1306
|
|
|
|
|
|
|
} |
1307
|
44694
|
|
|
|
|
75248
|
$self; |
1308
|
|
|
|
|
|
|
} |
1309
|
|
|
|
|
|
|
|
1310
|
|
|
|
|
|
|
sub _mark_unresolved { |
1311
|
78
|
|
|
78
|
|
72
|
my ($self, $location)= (shift, shift); |
1312
|
78
|
|
|
|
|
60
|
my $start= length($self->{_buf}); |
1313
|
|
|
|
|
|
|
|
1314
|
|
|
|
|
|
|
# If location is negative, move the 'start' back that many bytes. |
1315
|
|
|
|
|
|
|
# The length is the abs of location. |
1316
|
78
|
50
|
|
|
|
92
|
if ($location < 0) { |
1317
|
0
|
|
|
|
|
0
|
$location= -$location; |
1318
|
0
|
|
|
|
|
0
|
$start -= $location; |
1319
|
|
|
|
|
|
|
} |
1320
|
|
|
|
|
|
|
# If the location is positive, start is the end of the string. |
1321
|
|
|
|
|
|
|
# Add padding bytes for the length of the instruction. |
1322
|
|
|
|
|
|
|
else { |
1323
|
78
|
|
|
|
|
89
|
$self->{_buf} .= "\0" x $location; |
1324
|
|
|
|
|
|
|
} |
1325
|
|
|
|
|
|
|
|
1326
|
|
|
|
|
|
|
#print "Unresolved at $start ($location)\n"; |
1327
|
78
|
|
|
|
|
51
|
push @{ $self->_unresolved }, { start => $start, len => $location, @_ }; |
|
78
|
|
|
|
|
157
|
|
1328
|
|
|
|
|
|
|
} |
1329
|
|
|
|
|
|
|
|
1330
|
|
|
|
|
|
|
sub _repack { |
1331
|
0
|
|
|
0
|
|
0
|
my ($self, $params)= @_; |
1332
|
14
|
|
|
14
|
|
3866
|
use integer; |
|
14
|
|
|
|
|
13
|
|
|
14
|
|
|
|
|
48
|
|
1333
|
0
|
|
|
|
|
0
|
my $v= $params->{value}->value; |
1334
|
0
|
0
|
|
|
|
0
|
defined $v or croak "Placeholder $params->{value} has not been assigned"; |
1335
|
0
|
|
|
|
|
0
|
my $bits= $params->{bits}; |
1336
|
0
|
0
|
|
|
|
0
|
my $pack= $bits == 8? 'C' : $bits == 16? 'v' : $bits == 32? 'V' : $bits == 64? '
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
1337
|
0
|
0
|
|
|
|
0
|
(($v >> $bits) == ($v >> ($bits+1))) or croak "$v is wider than $bits bits"; |
1338
|
0
|
|
|
|
|
0
|
return pack($pack, $v & ~(~0 << $bits)); |
1339
|
|
|
|
|
|
|
} |
1340
|
|
|
|
|
|
|
|
1341
|
|
|
|
|
|
|
sub _resolve { |
1342
|
47496
|
|
|
47496
|
|
31811
|
my $self= shift; |
1343
|
|
|
|
|
|
|
|
1344
|
|
|
|
|
|
|
# Start by making sure every instruction is the length it needs to be |
1345
|
47496
|
|
|
|
|
30809
|
my $changed_len= 1; |
1346
|
47496
|
|
|
|
|
61013
|
while ($changed_len) { |
1347
|
47530
|
|
|
|
|
29642
|
$changed_len= 0; |
1348
|
47530
|
|
|
|
|
29137
|
my $ofs= 0; |
1349
|
47530
|
|
|
|
|
31624
|
for my $p (@{ $self->_unresolved }) { |
|
47530
|
|
|
|
|
114255
|
|
1350
|
|
|
|
|
|
|
#print "Shifting $p by $ofs\n" if $ofs; |
1351
|
258
|
100
|
|
|
|
297
|
$p->{start} += $ofs if $ofs; |
1352
|
|
|
|
|
|
|
my $fn= $p->{encode} |
1353
|
258
|
100
|
|
|
|
347
|
or next; |
1354
|
146
|
|
|
|
|
152
|
my $enc= $p->{encoded}= $self->$fn($p); |
1355
|
146
|
|
|
|
|
170
|
substr($self->{_buf}, $p->{start}, $p->{len})= $enc; |
1356
|
146
|
100
|
|
|
|
229
|
if (length($enc) != $p->{len}) { |
1357
|
|
|
|
|
|
|
#print "New size is $result\n"; |
1358
|
34
|
|
|
|
|
21
|
$changed_len= 1; |
1359
|
34
|
|
|
|
|
35
|
$ofs += (length($enc) - $p->{len}); |
1360
|
34
|
|
|
|
|
64
|
$p->{len}= length($enc); |
1361
|
|
|
|
|
|
|
} |
1362
|
|
|
|
|
|
|
} |
1363
|
|
|
|
|
|
|
} |
1364
|
|
|
|
|
|
|
|
1365
|
|
|
|
|
|
|
# Clear the list |
1366
|
47496
|
|
|
|
|
31871
|
@{ $self->_unresolved }= (); |
|
47496
|
|
|
|
|
59522
|
|
1367
|
|
|
|
|
|
|
} |
1368
|
|
|
|
|
|
|
|
1369
|
|
|
|
|
|
|
1; |
1370
|
|
|
|
|
|
|
|
1371
|
|
|
|
|
|
|
__END__ |