File Coverage

blib/lib/CPU/x86_64/InstructionWriter.pm
Criterion Covered Total %
statement 824 1011 81.5
branch 282 404 69.8
condition 99 261 37.9
subroutine 431 551 78.2
pod 102 464 21.9
total 1738 2691 64.5


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