line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# Assembler.pm |
2
|
|
|
|
|
|
|
# |
3
|
|
|
|
|
|
|
# Copyright (c) 1996 Malcolm Beattie |
4
|
|
|
|
|
|
|
# Copyright (c) 2008,2009,2010,2011,2012 Reini Urban |
5
|
|
|
|
|
|
|
# Copyright (c) 2014 cPanel Inc |
6
|
|
|
|
|
|
|
# |
7
|
|
|
|
|
|
|
# You may distribute under the terms of either the GNU General Public |
8
|
|
|
|
|
|
|
# License or the Artistic License, as specified in the README file. |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
package B::Assembler; |
11
|
1
|
|
|
1
|
|
444
|
use Exporter; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
33
|
|
12
|
1
|
|
|
1
|
|
3
|
use B qw(ppname); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
38
|
|
13
|
1
|
|
|
1
|
|
3
|
use B::Asmdata qw(%insn_data @insn_name); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
72
|
|
14
|
1
|
|
|
1
|
|
3
|
use Config qw(%Config); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
34
|
|
15
|
|
|
|
|
|
|
require ByteLoader; # we just need its $VERSION |
16
|
|
|
|
|
|
|
|
17
|
1
|
|
|
1
|
|
3
|
no warnings; # XXX |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
58
|
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
@ISA = qw(Exporter); |
20
|
|
|
|
|
|
|
our @EXPORT_OK = qw(assemble_fh newasm endasm assemble asm maxopix maxsvix); |
21
|
|
|
|
|
|
|
our $VERSION = '1.13'; |
22
|
|
|
|
|
|
|
|
23
|
1
|
|
|
1
|
|
3
|
use strict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
2237
|
|
24
|
|
|
|
|
|
|
my %opnumber; |
25
|
|
|
|
|
|
|
my ( $i, $opname ); |
26
|
|
|
|
|
|
|
for ( $i = 0 ; defined( $opname = ppname($i) ) ; $i++ ) { |
27
|
|
|
|
|
|
|
$opnumber{$opname} = $i; |
28
|
|
|
|
|
|
|
} |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
my ( $linenum, $errors, $out ); # global state, set up by newasm |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
sub error { |
33
|
23
|
|
|
23
|
0
|
16
|
my $str = shift; |
34
|
23
|
|
|
|
|
149
|
warn "$linenum: $str\n"; |
35
|
23
|
|
|
|
|
87
|
$errors++; |
36
|
|
|
|
|
|
|
} |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
my $debug = 0; |
39
|
0
|
|
|
0
|
0
|
0
|
sub debug { $debug = shift } |
40
|
|
|
|
|
|
|
my $quiet = 0; |
41
|
0
|
|
|
0
|
0
|
0
|
sub quiet { $quiet = shift } |
42
|
|
|
|
|
|
|
my ( $maxopix, $maxsvix ) = ( 0xffffffff, 0xffffffff ); |
43
|
0
|
|
|
0
|
0
|
0
|
sub maxopix { $maxopix = shift } |
44
|
0
|
|
|
0
|
0
|
0
|
sub maxsvix { $maxsvix = shift } |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
sub limcheck($$$$) { |
47
|
163
|
|
|
163
|
0
|
135
|
my ( $val, $lo, $hi, $loc ) = @_; |
48
|
163
|
100
|
100
|
|
|
493
|
if ( $val < $lo || $hi < $val ) { |
49
|
16
|
|
|
|
|
40
|
error "argument for $loc outside [$lo, $hi]: $val"; |
50
|
16
|
|
|
|
|
15
|
$val = $hi; |
51
|
|
|
|
|
|
|
} |
52
|
163
|
|
|
|
|
174
|
return $val; |
53
|
|
|
|
|
|
|
} |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
# |
56
|
|
|
|
|
|
|
# First define all the data conversion subs to which Asmdata will refer |
57
|
|
|
|
|
|
|
# |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
sub B::Asmdata::PUT_U8 { |
60
|
30
|
50
|
|
30
|
0
|
46
|
error "Missing argument to PUT_U8" if @_ < 1; |
61
|
30
|
|
|
|
|
18
|
my $arg = shift; |
62
|
30
|
|
|
|
|
29
|
my $c = uncstring($arg); |
63
|
30
|
50
|
|
|
|
31
|
if ( defined($c) ) { |
64
|
0
|
0
|
|
|
|
0
|
if ( length($c) != 1 ) { |
65
|
0
|
|
|
|
|
0
|
error "argument for U8 is too long: $c"; |
66
|
0
|
|
|
|
|
0
|
$c = substr( $c, 0, 1 ); |
67
|
|
|
|
|
|
|
} |
68
|
|
|
|
|
|
|
} |
69
|
|
|
|
|
|
|
else { |
70
|
30
|
|
|
|
|
34
|
$arg = limcheck( $arg, 0, 0xff, 'U8' ); |
71
|
30
|
|
|
|
|
27
|
$c = chr($arg); |
72
|
|
|
|
|
|
|
} |
73
|
30
|
|
|
|
|
27
|
return $c; |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
sub B::Asmdata::PUT_U16 { |
77
|
9
|
50
|
|
9
|
0
|
15
|
error "Missing argument to PUT_U16" if @_ < 1; |
78
|
9
|
|
|
|
|
13
|
my $arg = limcheck( $_[0], 0, 0xffff, 'U16' ); |
79
|
9
|
|
|
|
|
20
|
pack( "S", $arg ); |
80
|
|
|
|
|
|
|
} |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
sub B::Asmdata::PUT_U32 { |
83
|
36
|
50
|
|
36
|
0
|
45
|
error "Missing argument to PUT_U32" if @_ < 1; |
84
|
36
|
|
|
|
|
45
|
my $arg = limcheck( $_[0], 0, 0xffffffff, 'U32' ); |
85
|
36
|
|
|
|
|
61
|
pack( "L", $arg ); |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
sub B::Asmdata::PUT_I32 { |
89
|
7
|
50
|
|
7
|
0
|
11
|
error "Missing argument to PUT_I32" if @_ < 1; |
90
|
7
|
|
|
|
|
9
|
my $arg = limcheck( $_[0], -0x80000000, 0x7fffffff, 'I32' ); |
91
|
7
|
|
|
|
|
15
|
pack( "l", $arg ); |
92
|
|
|
|
|
|
|
} |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
sub B::Asmdata::PUT_NV { |
95
|
2
|
50
|
|
2
|
0
|
4
|
error "Missing argument to PUT_NV" if @_ < 1; |
96
|
2
|
|
|
|
|
9
|
sprintf( "%s\0", $_[0] ); |
97
|
|
|
|
|
|
|
} # "%lf" looses precision and pack('d',...) |
98
|
|
|
|
|
|
|
# may not even be portable between compilers |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
sub B::Asmdata::PUT_objindex { # could allow names here |
101
|
81
|
50
|
|
81
|
0
|
101
|
error "Missing argument to PUT_objindex" if @_ < 1; |
102
|
81
|
|
50
|
|
|
93
|
my $maxidx = $_[1] || 0xffffffff; |
103
|
81
|
|
50
|
|
|
94
|
my $what = $_[2] || 'ix'; |
104
|
81
|
|
|
|
|
89
|
my $arg = limcheck( $_[0], 0, $maxidx, $what ); |
105
|
81
|
|
|
|
|
143
|
pack( "L", $arg ); |
106
|
|
|
|
|
|
|
} |
107
|
50
|
|
|
50
|
0
|
61
|
sub B::Asmdata::PUT_svindex { B::Asmdata::PUT_objindex( @_, $maxsvix, 'svix' ) } |
108
|
19
|
|
|
19
|
0
|
22
|
sub B::Asmdata::PUT_opindex { B::Asmdata::PUT_objindex( @_, $maxopix, 'opix' ) } |
109
|
12
|
|
|
12
|
0
|
17
|
sub B::Asmdata::PUT_pvindex { B::Asmdata::PUT_objindex( @_, $maxsvix, 'pvix' ) } |
110
|
0
|
|
|
0
|
0
|
0
|
sub B::Asmdata::PUT_hekindex { B::Asmdata::PUT_objindex( @_ ) } |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
sub B::Asmdata::PUT_strconst { |
113
|
17
|
50
|
|
17
|
0
|
23
|
error "Missing argument to PUT_strconst" if @_ < 1; |
114
|
17
|
|
|
|
|
17
|
my $arg = shift; |
115
|
17
|
|
|
|
|
18
|
my $str = uncstring($arg); |
116
|
17
|
100
|
|
|
|
21
|
if ( !defined($str) ) { |
117
|
1
|
|
|
|
|
7
|
my @callstack = caller(3); |
118
|
1
|
50
|
|
|
|
62
|
error "bad string constant: '$arg', called from ".$callstack[3] |
119
|
|
|
|
|
|
|
." line:".$callstack[2] unless $callstack[3] eq 'B::PADNAME::ix'; # empty newpadnx |
120
|
1
|
|
|
|
|
2
|
$str = ''; |
121
|
|
|
|
|
|
|
} |
122
|
17
|
100
|
|
|
|
23
|
if ( $str =~ s/\0//g ) { |
123
|
1
|
|
|
|
|
3
|
error "string constant argument contains NUL: $arg"; |
124
|
1
|
|
|
|
|
1
|
$str = ''; |
125
|
|
|
|
|
|
|
} |
126
|
17
|
|
|
|
|
26
|
return $str . "\0"; |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
# expects the string argument already on the "stack" (with depth 1, one sv) |
130
|
|
|
|
|
|
|
sub B::Asmdata::PUT_pvcontents { |
131
|
5
|
|
|
5
|
0
|
3
|
my $arg = shift; |
132
|
5
|
100
|
|
|
|
9
|
error "extraneous argument to pvcontents: $arg" if defined $arg; |
133
|
5
|
|
|
|
|
7
|
return ""; |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
sub B::Asmdata::PUT_PV { |
137
|
4
|
50
|
|
4
|
0
|
8
|
error "Missing argument to PUT_PV" if @_ < 1; |
138
|
4
|
|
|
|
|
2
|
my $arg = shift; |
139
|
4
|
|
|
|
|
6
|
my $str = uncstring($arg); |
140
|
4
|
100
|
|
|
|
6
|
if ( !defined($str) ) { |
141
|
1
|
|
|
|
|
4
|
error "bad string argument: $arg"; |
142
|
1
|
|
|
|
|
2
|
$str = ''; |
143
|
|
|
|
|
|
|
} |
144
|
4
|
|
|
|
|
10
|
return pack( "L", length($str) ) . $str; |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
sub B::Asmdata::PUT_comment_t { |
148
|
3
|
|
|
3
|
0
|
4
|
my $arg = shift; |
149
|
3
|
|
|
|
|
5
|
$arg = uncstring($arg); |
150
|
3
|
50
|
|
|
|
11
|
error "bad string argument: $arg" unless defined($arg); |
151
|
3
|
100
|
|
|
|
6
|
if ( $arg =~ s/\n//g ) { |
152
|
1
|
|
|
|
|
4
|
error "comment argument contains linefeed: $arg"; |
153
|
|
|
|
|
|
|
} |
154
|
3
|
|
|
|
|
4
|
return $arg . "\n"; |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
sub B::Asmdata::PUT_double { |
157
|
0
|
0
|
|
0
|
0
|
0
|
error "Missing argument to PUT_double" if @_ < 1; |
158
|
0
|
|
|
|
|
0
|
sprintf( "%s\0", $_[0] ) |
159
|
|
|
|
|
|
|
} # see PUT_NV above |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
sub B::Asmdata::PUT_none { |
162
|
7
|
|
|
7
|
0
|
5
|
my $arg = shift; |
163
|
7
|
100
|
|
|
|
13
|
error "extraneous argument: $arg" if defined $arg; |
164
|
7
|
|
|
|
|
8
|
return ""; |
165
|
|
|
|
|
|
|
} |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
sub B::Asmdata::PUT_op_tr_array { |
168
|
2
|
50
|
|
2
|
0
|
11
|
error "Missing argument to PUT_tr_array" if @_ < 1; |
169
|
2
|
|
|
|
|
302
|
my @ary = split /\s*,\s*/, shift; |
170
|
2
|
|
|
|
|
60
|
return pack "S*", @ary; |
171
|
|
|
|
|
|
|
} |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
sub B::Asmdata::PUT_IV64 { |
174
|
9
|
50
|
|
9
|
0
|
14
|
error "Missing argument to PUT_IV64" if @_ < 1; |
175
|
9
|
|
|
|
|
17
|
return pack "Q", shift; |
176
|
|
|
|
|
|
|
} |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
sub B::Asmdata::PUT_IV { |
179
|
9
|
50
|
|
9
|
0
|
44
|
$Config{ivsize} == 4 ? &B::Asmdata::PUT_I32 : &B::Asmdata::PUT_IV64; |
180
|
|
|
|
|
|
|
} |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
sub B::Asmdata::PUT_PADOFFSET { |
183
|
0
|
0
|
|
0
|
0
|
0
|
$Config{ptrsize} == 8 ? &B::Asmdata::PUT_IV64 : &B::Asmdata::PUT_U32; |
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
sub B::Asmdata::PUT_long { |
187
|
0
|
0
|
|
0
|
0
|
0
|
$Config{longsize} == 8 ? &B::Asmdata::PUT_IV64 : &B::Asmdata::PUT_U32; |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
sub B::Asmdata::PUT_svtype { |
191
|
0
|
0
|
|
0
|
0
|
0
|
$Config{longsize} == 8 ? &B::Asmdata::PUT_IV64 : &B::Asmdata::PUT_U32; |
192
|
|
|
|
|
|
|
} |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
sub B::Asmdata::PUT_pmflags { |
195
|
5
|
50
|
|
5
|
0
|
13
|
return ($] < 5.013) ? B::Asmdata::PUT_U16(@_) : B::Asmdata::PUT_U32(@_); |
196
|
|
|
|
|
|
|
} |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
my %unesc = ( |
199
|
|
|
|
|
|
|
n => "\n", |
200
|
|
|
|
|
|
|
r => "\r", |
201
|
|
|
|
|
|
|
t => "\t", |
202
|
|
|
|
|
|
|
a => "\a", |
203
|
|
|
|
|
|
|
b => "\b", |
204
|
|
|
|
|
|
|
f => "\f", |
205
|
|
|
|
|
|
|
v => "\013" |
206
|
|
|
|
|
|
|
); |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
sub uncstring { |
209
|
54
|
|
|
54
|
0
|
44
|
my $s = shift; |
210
|
54
|
100
|
66
|
|
|
177
|
$s =~ s/^"// and $s =~ s/"$// or return undef; |
211
|
22
|
50
|
33
|
|
|
21
|
$s =~ s/\\(\d\d\d|.)/length($1) == 3 ? chr(oct($1)) : ($unesc{$1}||$1)/eg; |
|
1
|
|
|
|
|
9
|
|
212
|
22
|
|
|
|
|
28
|
return $s; |
213
|
|
|
|
|
|
|
} |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
sub strip_comments { |
216
|
204
|
|
|
204
|
0
|
126
|
my $stmt = shift; |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
# Comments only allowed in instructions which don't take string arguments |
219
|
|
|
|
|
|
|
# Treat string as a single line so .* eats \n characters. |
220
|
204
|
|
|
|
|
131
|
my $line = $stmt; |
221
|
204
|
|
|
|
|
150
|
$stmt =~ s{ |
222
|
|
|
|
|
|
|
^\s* # Ignore leading whitespace |
223
|
|
|
|
|
|
|
( |
224
|
|
|
|
|
|
|
[^"]* # A double quote '"' indicates a string argument. If we |
225
|
|
|
|
|
|
|
# find a double quote, the match fails and we strip nothing. |
226
|
|
|
|
|
|
|
) |
227
|
|
|
|
|
|
|
\s*\# # Any amount of whitespace plus the comment marker... |
228
|
|
|
|
|
|
|
\s*(.*)$ # ...which carries on to end-of-string. |
229
|
|
|
|
|
|
|
}{$1}sx; # Keep only the instruction and optional argument. |
230
|
204
|
50
|
|
|
|
352
|
return ($stmt) if $line eq $stmt; |
231
|
|
|
|
|
|
|
|
232
|
0
|
|
|
|
|
0
|
$stmt =~ m{ |
233
|
|
|
|
|
|
|
^\s* |
234
|
|
|
|
|
|
|
( |
235
|
|
|
|
|
|
|
[^"]* |
236
|
|
|
|
|
|
|
) |
237
|
|
|
|
|
|
|
\s*\# |
238
|
|
|
|
|
|
|
\s*(.*)$ |
239
|
|
|
|
|
|
|
}sx; # Keep only the instruction and optional argument. |
240
|
0
|
|
|
|
|
0
|
my ( $line, $comment ) = ( $1, $2 ); |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
# $line =~ s/\t$// if $comment; |
243
|
0
|
|
|
|
|
0
|
return ( $line, $comment ); |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
# create the ByteCode header: |
247
|
|
|
|
|
|
|
# magic, archname, ByteLoader $VERSION, ivsize, ptrsize, longsize, byteorder, |
248
|
|
|
|
|
|
|
# archflag, perlversion |
249
|
|
|
|
|
|
|
# byteorder is strconst, not U32 because of varying size issues (?) |
250
|
|
|
|
|
|
|
# archflag: bit 1: useithreads, bit 2: multiplicity |
251
|
|
|
|
|
|
|
# perlversion for the bytecode translation. |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
sub gen_header { |
254
|
1
|
|
|
1
|
0
|
3
|
my $header = gen_header_hash(); |
255
|
1
|
|
|
|
|
2
|
my $string = ""; |
256
|
1
|
|
|
|
|
3
|
$string .= B::Asmdata::PUT_U32( $header->{magic} ); |
257
|
1
|
|
|
|
|
5
|
$string .= B::Asmdata::PUT_strconst( '"' . $header->{archname} . '"' ); |
258
|
1
|
|
|
|
|
4
|
$string .= B::Asmdata::PUT_strconst( '"' . $header->{blversion} . '"' ); |
259
|
1
|
|
|
|
|
2
|
$string .= B::Asmdata::PUT_U32( $header->{ivsize} ); |
260
|
1
|
|
|
|
|
3
|
$string .= B::Asmdata::PUT_U32( $header->{ptrsize} ); |
261
|
1
|
50
|
|
|
|
3
|
if ( exists $header->{longsize} ) { |
262
|
1
|
|
|
|
|
3
|
$string .= B::Asmdata::PUT_U32( $header->{longsize} ); |
263
|
|
|
|
|
|
|
} |
264
|
1
|
|
|
|
|
5
|
$string .= B::Asmdata::PUT_strconst( sprintf(qq["0x%s"], $header->{byteorder} )); |
265
|
1
|
50
|
|
|
|
3
|
if ( exists $header->{archflag} ) { |
266
|
1
|
|
|
|
|
3
|
$string .= B::Asmdata::PUT_U16( $header->{archflag} ); |
267
|
|
|
|
|
|
|
} |
268
|
1
|
50
|
|
|
|
3
|
if ( exists $header->{perlversion} ) { |
269
|
1
|
|
|
|
|
4
|
$string .= B::Asmdata::PUT_strconst( '"' . $header->{perlversion} . '"'); |
270
|
|
|
|
|
|
|
} |
271
|
1
|
|
|
|
|
5
|
$string; |
272
|
|
|
|
|
|
|
} |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
# Calculate the ByteCode header values: |
275
|
|
|
|
|
|
|
# magic, archname, ByteLoader $VERSION, ivsize, ptrsize, longsize, byteorder |
276
|
|
|
|
|
|
|
# archflag, perlversion |
277
|
|
|
|
|
|
|
# nvtype is irrelevant (floats are stored as strings) |
278
|
|
|
|
|
|
|
# byteorder is strconst, not U32 because of varying size issues (?) |
279
|
|
|
|
|
|
|
# archflag: bit 1: useithreads, bit 2: multiplicity |
280
|
|
|
|
|
|
|
# perlversion for the bytecode translation. |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
sub gen_header_hash { |
283
|
1
|
|
|
1
|
0
|
1
|
my $header = {}; |
284
|
1
|
|
|
|
|
2
|
my $blversion = "$ByteLoader::VERSION"; |
285
|
|
|
|
|
|
|
#if ($] < 5.009 and $blversion eq '0.06_01') { |
286
|
|
|
|
|
|
|
# $blversion = '0.06';# fake the old backwards compatible version |
287
|
|
|
|
|
|
|
#} |
288
|
1
|
|
|
|
|
2
|
$header->{magic} = 0x43424c50; |
289
|
1
|
|
|
|
|
6
|
$header->{archname} = $Config{archname}; |
290
|
1
|
|
|
|
|
3
|
$header->{blversion} = $blversion; |
291
|
1
|
|
|
|
|
3
|
$header->{ivsize} = $Config{ivsize}; |
292
|
1
|
|
|
|
|
50
|
$header->{ptrsize} = $Config{ptrsize}; |
293
|
1
|
50
|
|
|
|
4
|
if ( $blversion ge "0.06_03" ) { |
294
|
1
|
|
|
|
|
36
|
$header->{longsize} = $Config{longsize}; |
295
|
|
|
|
|
|
|
} |
296
|
1
|
|
|
|
|
15
|
my $byteorder = $Config{byteorder}; |
297
|
1
|
50
|
|
|
|
5
|
if ($] < 5.007) { |
298
|
|
|
|
|
|
|
# until 5.6 the $Config{byteorder} was dependent on ivsize, which was wrong. we need longsize. |
299
|
0
|
|
|
|
|
0
|
my $t = $Config{ivtype}; |
300
|
0
|
|
|
|
|
0
|
my $s = $Config{longsize}; |
301
|
0
|
0
|
|
|
|
0
|
my $f = $t eq 'long' ? 'L!' : $s == 8 ? 'Q': 'I'; |
|
|
0
|
|
|
|
|
|
302
|
0
|
0
|
0
|
|
|
0
|
if ($s == 4 || $s == 8) { |
303
|
0
|
|
|
|
|
0
|
my $i = 0; |
304
|
0
|
|
|
|
|
0
|
foreach my $c (reverse(2..$s)) { $i |= ord($c); $i <<= 8 } |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
305
|
0
|
|
|
|
|
0
|
$i |= ord(1); |
306
|
0
|
|
|
|
|
0
|
$byteorder = join('', unpack('a'x$s, pack($f, $i))); |
307
|
|
|
|
|
|
|
} else { |
308
|
0
|
|
|
|
|
0
|
$byteorder = '?'x$s; |
309
|
|
|
|
|
|
|
} |
310
|
|
|
|
|
|
|
} |
311
|
1
|
|
|
|
|
2
|
$header->{byteorder} = $byteorder; |
312
|
1
|
50
|
|
|
|
3
|
if ( $blversion ge "0.06_05" ) { |
313
|
1
|
|
|
|
|
1
|
my $archflag = 0; |
314
|
1
|
50
|
|
|
|
6
|
$archflag += 1 if $Config{useithreads}; |
315
|
1
|
50
|
|
|
|
33
|
$archflag += 2 if $Config{usemultiplicity}; |
316
|
1
|
|
|
|
|
3
|
$header->{archflag} = $archflag; |
317
|
|
|
|
|
|
|
} |
318
|
1
|
50
|
|
|
|
12
|
if ( $blversion ge "0.06_06" ) { |
319
|
1
|
|
|
|
|
3
|
$header->{perlversion} = $]; |
320
|
|
|
|
|
|
|
} |
321
|
1
|
|
|
|
|
1
|
$header; |
322
|
|
|
|
|
|
|
} |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
sub parse_statement { |
325
|
204
|
|
|
204
|
0
|
129
|
my $stmt = shift; |
326
|
204
|
|
|
|
|
764
|
my ( $insn, $arg ) = $stmt =~ m{ |
327
|
|
|
|
|
|
|
^\s* # allow (but ignore) leading whitespace |
328
|
|
|
|
|
|
|
(.*?) # Ignore -S op groups. Instruction continues up until... |
329
|
|
|
|
|
|
|
(?: # ...an optional whitespace+argument group |
330
|
|
|
|
|
|
|
\s+ # first whitespace. |
331
|
|
|
|
|
|
|
(.*) # The argument is all the rest (newlines included). |
332
|
|
|
|
|
|
|
)?$ # anchor at end-of-line |
333
|
|
|
|
|
|
|
}sx; |
334
|
204
|
100
|
|
|
|
262
|
if ( defined($arg) ) { |
335
|
193
|
100
|
|
|
|
417
|
if ( $arg =~ s/^0x(?=[0-9a-fA-F]+$)// ) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
336
|
9
|
|
|
|
|
9
|
$arg = hex($arg); |
337
|
|
|
|
|
|
|
} |
338
|
|
|
|
|
|
|
elsif ( $arg =~ s/^0(?=[0-7]+$)// ) { |
339
|
0
|
|
|
|
|
0
|
$arg = oct($arg); |
340
|
|
|
|
|
|
|
} |
341
|
|
|
|
|
|
|
elsif ( $arg =~ /^pp_/ ) { |
342
|
0
|
|
|
|
|
0
|
$arg =~ s/\s*$//; # strip trailing whitespace |
343
|
0
|
|
|
|
|
0
|
my $opnum = $opnumber{$arg}; |
344
|
0
|
0
|
|
|
|
0
|
if ( defined($opnum) ) { |
345
|
0
|
|
|
|
|
0
|
$arg = $opnum; |
346
|
|
|
|
|
|
|
} |
347
|
|
|
|
|
|
|
else { |
348
|
|
|
|
|
|
|
# TODO: ignore [op] from O=Bytecode,-S |
349
|
0
|
|
|
|
|
0
|
error qq(No such op type "$arg"); |
350
|
0
|
|
|
|
|
0
|
$arg = 0; |
351
|
|
|
|
|
|
|
} |
352
|
|
|
|
|
|
|
} |
353
|
|
|
|
|
|
|
} |
354
|
204
|
|
|
|
|
284
|
return ( $insn, $arg ); |
355
|
|
|
|
|
|
|
} |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
sub assemble_insn { |
358
|
204
|
|
|
204
|
0
|
152
|
my ( $insn, $arg ) = @_; |
359
|
204
|
|
|
|
|
190
|
my $data = $insn_data{$insn}; |
360
|
204
|
100
|
|
|
|
190
|
if ( defined($data) ) { |
361
|
203
|
|
|
|
|
118
|
my ( $bytecode, $putsub ) = @{$data}[ 0, 1 ]; |
|
203
|
|
|
|
|
217
|
|
362
|
203
|
50
|
|
|
|
254
|
error qq(unsupported instruction "$insn") unless $putsub; |
363
|
203
|
50
|
|
|
|
198
|
return "" unless $putsub; |
364
|
203
|
|
|
|
|
195
|
my $argcode = &$putsub($arg); |
365
|
203
|
|
|
|
|
404
|
return chr($bytecode) . $argcode; |
366
|
|
|
|
|
|
|
} |
367
|
|
|
|
|
|
|
else { |
368
|
1
|
|
|
|
|
3
|
error qq(no such instruction "$insn"); |
369
|
1
|
|
|
|
|
8
|
return ""; |
370
|
|
|
|
|
|
|
} |
371
|
|
|
|
|
|
|
} |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
sub assemble_fh { |
374
|
1
|
|
|
1
|
0
|
2965
|
my ( $fh, $out ) = @_; |
375
|
1
|
|
|
|
|
2
|
my $line; |
376
|
1
|
|
|
|
|
3
|
my $asm = newasm($out); |
377
|
1
|
|
|
|
|
24
|
while ( $line = <$fh> ) { |
378
|
204
|
|
|
|
|
1244
|
assemble($line); |
379
|
|
|
|
|
|
|
} |
380
|
1
|
|
|
|
|
7
|
endasm(); |
381
|
|
|
|
|
|
|
} |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
sub newasm { |
384
|
1
|
|
|
1
|
0
|
1
|
my ($outsub) = @_; |
385
|
|
|
|
|
|
|
|
386
|
1
|
50
|
|
|
|
9
|
die "Invalid printing routine for B::Assembler\n" |
387
|
|
|
|
|
|
|
unless ref $outsub eq 'CODE'; |
388
|
1
|
50
|
|
|
|
2
|
die <
|
389
|
|
|
|
|
|
|
Can't have multiple byteassembly sessions at once! |
390
|
|
|
|
|
|
|
(perhaps you forgot an endasm()?) |
391
|
|
|
|
|
|
|
EOD |
392
|
|
|
|
|
|
|
|
393
|
1
|
|
|
|
|
2
|
$linenum = $errors = 0; |
394
|
1
|
|
|
|
|
1
|
$out = $outsub; |
395
|
|
|
|
|
|
|
|
396
|
1
|
|
|
|
|
3
|
$out->( gen_header() ); |
397
|
|
|
|
|
|
|
} |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
sub endasm { |
400
|
1
|
50
|
|
1
|
0
|
3
|
if ($errors) { |
401
|
1
|
|
|
|
|
7
|
die "There were $errors assembly errors\n"; |
402
|
|
|
|
|
|
|
} |
403
|
0
|
|
|
|
|
0
|
$linenum = $errors = $out = 0; |
404
|
|
|
|
|
|
|
} |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
### interface via whole line, and optional comments |
407
|
|
|
|
|
|
|
sub assemble { |
408
|
204
|
|
|
204
|
0
|
166
|
my ($line) = @_; |
409
|
204
|
|
|
|
|
126
|
my ( $insn, $arg, $comment ); |
410
|
204
|
|
|
|
|
115
|
$linenum++; |
411
|
204
|
|
|
|
|
151
|
chomp $line; |
412
|
204
|
|
|
|
|
462
|
$line =~ s/\cM$//; |
413
|
204
|
50
|
|
|
|
222
|
if ($debug) { |
414
|
0
|
|
|
|
|
0
|
my $quotedline = $line; |
415
|
0
|
|
|
|
|
0
|
$quotedline =~ s/\\/\\\\/g; |
416
|
0
|
|
|
|
|
0
|
$quotedline =~ s/"/\\"/g; |
417
|
0
|
|
|
|
|
0
|
$out->( assemble_insn( "comment", qq("$quotedline") ) ); |
418
|
|
|
|
|
|
|
} |
419
|
204
|
|
|
|
|
190
|
( $line, $comment ) = strip_comments($line); |
420
|
204
|
50
|
0
|
|
|
222
|
if ($line) { |
|
|
0
|
|
|
|
|
|
421
|
204
|
|
|
|
|
194
|
( $insn, $arg ) = parse_statement($line); |
422
|
204
|
0
|
33
|
|
|
308
|
if ($debug and !$comment and $insn =~ /_flags/) { |
|
|
|
33
|
|
|
|
|
423
|
0
|
|
|
|
|
0
|
$comment = sprintf("0x%x", $arg); |
424
|
|
|
|
|
|
|
} |
425
|
204
|
|
|
|
|
189
|
$out->( assemble_insn( $insn, $arg, $comment ) ); |
426
|
204
|
50
|
|
|
|
5541
|
if ($debug) { |
427
|
0
|
|
|
|
|
|
$out->( assemble_insn( "nop", undef ) ); |
428
|
|
|
|
|
|
|
} |
429
|
|
|
|
|
|
|
} |
430
|
|
|
|
|
|
|
elsif ( $debug and $comment ) { |
431
|
0
|
|
|
|
|
|
$out->( assemble_insn( "nop", undef, $comment ) ); |
432
|
|
|
|
|
|
|
} |
433
|
|
|
|
|
|
|
} |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
### temporary workaround |
436
|
|
|
|
|
|
|
### interface via 2-3 args |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
sub asm ($;$$) { |
439
|
0
|
0
|
|
0
|
0
|
|
return if $_[0] =~ /\s*\W/; |
440
|
0
|
0
|
|
|
|
|
if ( defined $_[1] ) { |
441
|
|
|
|
|
|
|
return |
442
|
0
|
0
|
0
|
|
|
|
if $_[1] eq "0" |
443
|
|
|
|
|
|
|
and $_[0] !~ /^(?:ldsv|stsv|newsvx?|newpad.*|av_pushx?|av_extend|xav_flags)$/; |
444
|
0
|
0
|
0
|
|
|
|
return if $_[1] eq "1" and $]>5.007 and $_[0] =~ /^(?:sv_refcnt)$/; |
|
|
|
0
|
|
|
|
|
445
|
|
|
|
|
|
|
} |
446
|
0
|
|
|
|
|
|
my ( $insn, $arg, $comment ) = @_; |
447
|
0
|
0
|
|
|
|
|
if ($] < 5.007) { |
448
|
0
|
0
|
|
|
|
|
if ($insn eq "newsvx") { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
449
|
0
|
|
|
|
|
|
$arg = $arg & 0xff; # sv not SVt_NULL |
450
|
0
|
|
|
|
|
|
$insn = "newsv"; |
451
|
|
|
|
|
|
|
# XXX but this needs stsv tix-1 also |
452
|
|
|
|
|
|
|
} elsif ($insn eq "newopx") { |
453
|
0
|
|
|
|
|
|
$insn = "newop"; |
454
|
|
|
|
|
|
|
} elsif ($insn eq "av_pushx") { |
455
|
0
|
|
|
|
|
|
$insn = "av_push"; |
456
|
|
|
|
|
|
|
} elsif ($insn eq "ldspecsvx") { |
457
|
0
|
|
|
|
|
|
$insn = "ldspecsv"; |
458
|
|
|
|
|
|
|
} elsif ($insn eq "gv_stashpvx") { |
459
|
0
|
|
|
|
|
|
$insn = "gv_stashpv"; |
460
|
|
|
|
|
|
|
} elsif ($insn eq "gv_fetchpvx") { |
461
|
0
|
|
|
|
|
|
$insn = "gv_fetchpv"; |
462
|
|
|
|
|
|
|
} elsif ($insn eq "main_cv") { |
463
|
0
|
|
|
|
|
|
return; |
464
|
|
|
|
|
|
|
} |
465
|
|
|
|
|
|
|
} |
466
|
0
|
|
|
|
|
|
$out->( assemble_insn( $insn, $arg, $comment ) ); |
467
|
0
|
|
|
|
|
|
$linenum++; |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
# assemble "@_"; |
470
|
|
|
|
|
|
|
} |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
1; |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
__END__ |