File Coverage

blib/lib/CPU/x86_64/InstructionWriter.pm
Criterion Covered Total %
statement 687 829 82.8
branch 211 298 70.8
condition 65 193 33.6
subroutine 364 467 77.9
pod 64 394 16.2
total 1391 2181 63.7


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