File Coverage

blib/lib/CPU/x86_64/InstructionWriter.pm
Criterion Covered Total %
statement 956 1192 80.2
branch 300 426 70.4
condition 120 273 43.9
subroutine 466 649 71.8
pod 132 555 23.7
total 1974 3095 63.7


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