| 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
|
|
957
|
use Exporter; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
54
|
|
|
12
|
1
|
|
|
1
|
|
8
|
use B qw(ppname); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
64
|
|
|
13
|
1
|
|
|
1
|
|
8
|
use B::Asmdata qw(%insn_data @insn_name); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
102
|
|
|
14
|
1
|
|
|
1
|
|
7
|
use Config qw(%Config); |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
63
|
|
|
15
|
|
|
|
|
|
|
require ByteLoader; # we just need its $VERSION |
|
16
|
|
|
|
|
|
|
|
|
17
|
1
|
|
|
1
|
|
8
|
no warnings; # XXX |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
110
|
|
|
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
|
|
9
|
use strict; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
4949
|
|
|
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
|
30
|
my $str = shift; |
|
34
|
23
|
|
|
|
|
183
|
warn "$linenum: $str\n"; |
|
35
|
23
|
|
|
|
|
123
|
$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
|
161
|
|
|
161
|
0
|
373
|
my ( $val, $lo, $hi, $loc ) = @_; |
|
48
|
161
|
100
|
100
|
|
|
667
|
if ( $val < $lo || $hi < $val ) { |
|
49
|
16
|
|
|
|
|
63
|
error "argument for $loc outside [$lo, $hi]: $val"; |
|
50
|
16
|
|
|
|
|
22
|
$val = $hi; |
|
51
|
|
|
|
|
|
|
} |
|
52
|
161
|
|
|
|
|
396
|
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
|
69
|
error "Missing argument to PUT_U8" if @_ < 1; |
|
61
|
30
|
|
|
|
|
51
|
my $arg = shift; |
|
62
|
30
|
|
|
|
|
64
|
my $c = uncstring($arg); |
|
63
|
30
|
50
|
|
|
|
77
|
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
|
|
|
|
|
64
|
$arg = limcheck( $arg, 0, 0xff, 'U8' ); |
|
71
|
30
|
|
|
|
|
62
|
$c = chr($arg); |
|
72
|
|
|
|
|
|
|
} |
|
73
|
30
|
|
|
|
|
64
|
return $c; |
|
74
|
|
|
|
|
|
|
} |
|
75
|
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
sub B::Asmdata::PUT_U16 { |
|
77
|
9
|
50
|
|
9
|
0
|
24
|
error "Missing argument to PUT_U16" if @_ < 1; |
|
78
|
9
|
|
|
|
|
20
|
my $arg = limcheck( $_[0], 0, 0xffff, 'U16' ); |
|
79
|
9
|
|
|
|
|
35
|
pack( "S", $arg ); |
|
80
|
|
|
|
|
|
|
} |
|
81
|
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
sub B::Asmdata::PUT_U32 { |
|
83
|
34
|
50
|
|
34
|
0
|
83
|
error "Missing argument to PUT_U32" if @_ < 1; |
|
84
|
34
|
|
|
|
|
77
|
my $arg = limcheck( $_[0], 0, 0xffffffff, 'U32' ); |
|
85
|
34
|
|
|
|
|
125
|
pack( "L", $arg ); |
|
86
|
|
|
|
|
|
|
} |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
sub B::Asmdata::PUT_I32 { |
|
89
|
7
|
50
|
|
7
|
0
|
25
|
error "Missing argument to PUT_I32" if @_ < 1; |
|
90
|
7
|
|
|
|
|
21
|
my $arg = limcheck( $_[0], -0x80000000, 0x7fffffff, 'I32' ); |
|
91
|
7
|
|
|
|
|
24
|
pack( "l", $arg ); |
|
92
|
|
|
|
|
|
|
} |
|
93
|
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
sub B::Asmdata::PUT_NV { |
|
95
|
2
|
50
|
|
2
|
0
|
9
|
error "Missing argument to PUT_NV" if @_ < 1; |
|
96
|
2
|
|
|
|
|
10
|
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
|
191
|
error "Missing argument to PUT_objindex" if @_ < 1; |
|
102
|
81
|
|
50
|
|
|
449
|
my $maxidx = $_[1] || 0xffffffff; |
|
103
|
81
|
|
50
|
|
|
197
|
my $what = $_[2] || 'ix'; |
|
104
|
81
|
|
|
|
|
175
|
my $arg = limcheck( $_[0], 0, $maxidx, $what ); |
|
105
|
81
|
|
|
|
|
287
|
pack( "L", $arg ); |
|
106
|
|
|
|
|
|
|
} |
|
107
|
50
|
|
|
50
|
0
|
111
|
sub B::Asmdata::PUT_svindex { B::Asmdata::PUT_objindex( @_, $maxsvix, 'svix' ) } |
|
108
|
19
|
|
|
19
|
0
|
44
|
sub B::Asmdata::PUT_opindex { B::Asmdata::PUT_objindex( @_, $maxopix, 'opix' ) } |
|
109
|
12
|
|
|
12
|
0
|
27
|
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
|
45
|
error "Missing argument to PUT_strconst" if @_ < 1; |
|
114
|
17
|
|
|
|
|
33
|
my $arg = shift; |
|
115
|
17
|
|
|
|
|
46
|
my $str = uncstring($arg); |
|
116
|
17
|
100
|
|
|
|
42
|
if ( !defined($str) ) { |
|
117
|
1
|
|
|
|
|
8
|
my @callstack = caller(3); |
|
118
|
1
|
50
|
|
|
|
9
|
error "bad string constant: '$arg', called from ".$callstack[3] |
|
119
|
|
|
|
|
|
|
." line:".$callstack[2] unless $callstack[3] eq 'B::PADNAME::ix'; # empty newpadnx |
|
120
|
1
|
|
|
|
|
4
|
$str = ''; |
|
121
|
|
|
|
|
|
|
} |
|
122
|
17
|
100
|
|
|
|
49
|
if ( $str =~ s/\0//g ) { |
|
123
|
1
|
|
|
|
|
6
|
error "string constant argument contains NUL: $arg"; |
|
124
|
1
|
|
|
|
|
3
|
$str = ''; |
|
125
|
|
|
|
|
|
|
} |
|
126
|
17
|
|
|
|
|
45
|
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
|
9
|
my $arg = shift; |
|
132
|
5
|
100
|
|
|
|
18
|
error "extraneous argument to pvcontents: $arg" if defined $arg; |
|
133
|
5
|
|
|
|
|
13
|
return ""; |
|
134
|
|
|
|
|
|
|
} |
|
135
|
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
sub B::Asmdata::PUT_PV { |
|
137
|
4
|
50
|
|
4
|
0
|
13
|
error "Missing argument to PUT_PV" if @_ < 1; |
|
138
|
4
|
|
|
|
|
9
|
my $arg = shift; |
|
139
|
4
|
|
|
|
|
11
|
my $str = uncstring($arg); |
|
140
|
4
|
100
|
|
|
|
14
|
if ( !defined($str) ) { |
|
141
|
1
|
|
|
|
|
4
|
error "bad string argument: $arg"; |
|
142
|
1
|
|
|
|
|
2
|
$str = ''; |
|
143
|
|
|
|
|
|
|
} |
|
144
|
4
|
|
|
|
|
18
|
return pack( "L", length($str) ) . $str; |
|
145
|
|
|
|
|
|
|
} |
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
sub B::Asmdata::PUT_comment_t { |
|
148
|
3
|
|
|
3
|
0
|
7
|
my $arg = shift; |
|
149
|
3
|
|
|
|
|
8
|
$arg = uncstring($arg); |
|
150
|
3
|
50
|
|
|
|
12
|
error "bad string argument: $arg" unless defined($arg); |
|
151
|
3
|
100
|
|
|
|
12
|
if ( $arg =~ s/\n//g ) { |
|
152
|
1
|
|
|
|
|
4
|
error "comment argument contains linefeed: $arg"; |
|
153
|
|
|
|
|
|
|
} |
|
154
|
3
|
|
|
|
|
12
|
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
|
14
|
my $arg = shift; |
|
163
|
7
|
100
|
|
|
|
22
|
error "extraneous argument: $arg" if defined $arg; |
|
164
|
7
|
|
|
|
|
14
|
return ""; |
|
165
|
|
|
|
|
|
|
} |
|
166
|
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
sub B::Asmdata::PUT_op_tr_array { |
|
168
|
2
|
50
|
|
2
|
0
|
158
|
error "Missing argument to PUT_tr_array" if @_ < 1; |
|
169
|
2
|
|
|
|
|
396
|
my @ary = split /\s*,\s*/, shift; |
|
170
|
2
|
|
|
|
|
134
|
return pack "S*", @ary; |
|
171
|
|
|
|
|
|
|
} |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
sub B::Asmdata::PUT_IV64 { |
|
174
|
9
|
50
|
|
9
|
0
|
25
|
error "Missing argument to PUT_IV64" if @_ < 1; |
|
175
|
9
|
|
|
|
|
31
|
return pack "Q", shift; |
|
176
|
|
|
|
|
|
|
} |
|
177
|
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
sub B::Asmdata::PUT_IV { |
|
179
|
9
|
50
|
|
9
|
0
|
74
|
$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
|
22
|
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
|
94
|
my $s = shift; |
|
210
|
54
|
100
|
66
|
|
|
310
|
$s =~ s/^"// and $s =~ s/"$// or return undef; |
|
211
|
22
|
50
|
33
|
|
|
69
|
$s =~ s/\\(\d\d\d|.)/length($1) == 3 ? chr(oct($1)) : ($unesc{$1}||$1)/eg; |
|
|
1
|
|
|
|
|
11
|
|
|
212
|
22
|
|
|
|
|
53
|
return $s; |
|
213
|
|
|
|
|
|
|
} |
|
214
|
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
sub strip_comments { |
|
216
|
202
|
|
|
202
|
0
|
333
|
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
|
202
|
|
|
|
|
323
|
my $line = $stmt; |
|
221
|
202
|
|
|
|
|
349
|
$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
|
202
|
50
|
|
|
|
612
|
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
|
6
|
my $header = gen_header_hash(); |
|
255
|
1
|
|
|
|
|
5
|
my $string = ""; |
|
256
|
1
|
|
|
|
|
6
|
$string .= B::Asmdata::PUT_U32( $header->{magic} ); |
|
257
|
1
|
|
|
|
|
10
|
$string .= B::Asmdata::PUT_strconst( '"' . $header->{archname} . '"' ); |
|
258
|
1
|
|
|
|
|
7
|
$string .= B::Asmdata::PUT_strconst( '"' . $header->{blversion} . '"' ); |
|
259
|
1
|
|
|
|
|
5
|
$string .= B::Asmdata::PUT_U32( $header->{ivsize} ); |
|
260
|
1
|
|
|
|
|
5
|
$string .= B::Asmdata::PUT_U32( $header->{ptrsize} ); |
|
261
|
1
|
50
|
|
|
|
10
|
if ( exists $header->{longsize} ) { |
|
262
|
1
|
|
|
|
|
6
|
$string .= B::Asmdata::PUT_U32( $header->{longsize} ); |
|
263
|
|
|
|
|
|
|
} |
|
264
|
1
|
|
|
|
|
7
|
$string .= B::Asmdata::PUT_strconst( sprintf(qq["0x%s"], $header->{byteorder} )); |
|
265
|
1
|
50
|
|
|
|
5
|
if ( exists $header->{archflag} ) { |
|
266
|
1
|
|
|
|
|
6
|
$string .= B::Asmdata::PUT_U16( $header->{archflag} ); |
|
267
|
|
|
|
|
|
|
} |
|
268
|
1
|
50
|
|
|
|
6
|
if ( exists $header->{perlversion} ) { |
|
269
|
1
|
|
|
|
|
5
|
$string .= B::Asmdata::PUT_strconst( '"' . $header->{perlversion} . '"'); |
|
270
|
|
|
|
|
|
|
} |
|
271
|
1
|
|
|
|
|
14
|
$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
|
3
|
my $header = {}; |
|
284
|
1
|
|
|
|
|
5
|
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
|
|
|
|
|
5
|
$header->{magic} = 0x43424c50; |
|
289
|
1
|
|
|
|
|
20
|
$header->{archname} = $Config{archname}; |
|
290
|
1
|
|
|
|
|
7
|
$header->{blversion} = $blversion; |
|
291
|
1
|
|
|
|
|
10
|
$header->{ivsize} = $Config{ivsize}; |
|
292
|
1
|
|
|
|
|
89
|
$header->{ptrsize} = $Config{ptrsize}; |
|
293
|
1
|
50
|
|
|
|
10
|
if ( $blversion ge "0.06_03" ) { |
|
294
|
1
|
|
|
|
|
67
|
$header->{longsize} = $Config{longsize}; |
|
295
|
|
|
|
|
|
|
} |
|
296
|
1
|
|
|
|
|
34
|
my $byteorder = $Config{byteorder}; |
|
297
|
1
|
50
|
|
|
|
10
|
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
|
|
|
|
|
4
|
$header->{byteorder} = $byteorder; |
|
312
|
1
|
50
|
|
|
|
5
|
if ( $blversion ge "0.06_05" ) { |
|
313
|
1
|
|
|
|
|
4
|
my $archflag = 0; |
|
314
|
1
|
50
|
|
|
|
14
|
$archflag += 1 if $Config{useithreads}; |
|
315
|
1
|
50
|
|
|
|
57
|
$archflag += 2 if $Config{usemultiplicity}; |
|
316
|
1
|
|
|
|
|
7
|
$header->{archflag} = $archflag; |
|
317
|
|
|
|
|
|
|
} |
|
318
|
1
|
50
|
|
|
|
6
|
if ( $blversion ge "0.06_06" ) { |
|
319
|
1
|
|
|
|
|
4
|
$header->{perlversion} = $]; |
|
320
|
|
|
|
|
|
|
} |
|
321
|
1
|
|
|
|
|
4
|
$header; |
|
322
|
|
|
|
|
|
|
} |
|
323
|
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
sub parse_statement { |
|
325
|
202
|
|
|
202
|
0
|
356
|
my $stmt = shift; |
|
326
|
202
|
|
|
|
|
1430
|
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
|
202
|
100
|
|
|
|
596
|
if ( defined($arg) ) { |
|
335
|
191
|
100
|
|
|
|
692
|
if ( $arg =~ s/^0x(?=[0-9a-fA-F]+$)// ) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
336
|
9
|
|
|
|
|
26
|
$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
|
202
|
|
|
|
|
565
|
return ( $insn, $arg ); |
|
355
|
|
|
|
|
|
|
} |
|
356
|
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
sub assemble_insn { |
|
358
|
202
|
|
|
202
|
0
|
406
|
my ( $insn, $arg ) = @_; |
|
359
|
202
|
|
|
|
|
486
|
my $data = $insn_data{$insn}; |
|
360
|
202
|
100
|
|
|
|
395
|
if ( defined($data) ) { |
|
361
|
201
|
|
|
|
|
308
|
my ( $bytecode, $putsub ) = @{$data}[ 0, 1 ]; |
|
|
201
|
|
|
|
|
502
|
|
|
362
|
201
|
50
|
|
|
|
448
|
error qq(unsupported instruction "$insn") unless $putsub; |
|
363
|
201
|
50
|
|
|
|
429
|
return "" unless $putsub; |
|
364
|
201
|
|
|
|
|
422
|
my $argcode = &$putsub($arg); |
|
365
|
201
|
|
|
|
|
957
|
return chr($bytecode) . $argcode; |
|
366
|
|
|
|
|
|
|
} |
|
367
|
|
|
|
|
|
|
else { |
|
368
|
1
|
|
|
|
|
55
|
error qq(no such instruction "$insn"); |
|
369
|
1
|
|
|
|
|
3
|
return ""; |
|
370
|
|
|
|
|
|
|
} |
|
371
|
|
|
|
|
|
|
} |
|
372
|
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
sub assemble_fh { |
|
374
|
1
|
|
|
1
|
0
|
7134
|
my ( $fh, $out ) = @_; |
|
375
|
1
|
|
|
|
|
3
|
my $line; |
|
376
|
1
|
|
|
|
|
7
|
my $asm = newasm($out); |
|
377
|
1
|
|
|
|
|
40
|
while ( $line = <$fh> ) { |
|
378
|
202
|
|
|
|
|
2833
|
assemble($line); |
|
379
|
|
|
|
|
|
|
} |
|
380
|
1
|
|
|
|
|
42
|
endasm(); |
|
381
|
|
|
|
|
|
|
} |
|
382
|
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
sub newasm { |
|
384
|
1
|
|
|
1
|
0
|
4
|
my ($outsub) = @_; |
|
385
|
|
|
|
|
|
|
|
|
386
|
1
|
50
|
|
|
|
8
|
die "Invalid printing routine for B::Assembler\n" |
|
387
|
|
|
|
|
|
|
unless ref $outsub eq 'CODE'; |
|
388
|
1
|
50
|
|
|
|
7
|
die <
|
|
389
|
|
|
|
|
|
|
Can't have multiple byteassembly sessions at once! |
|
390
|
|
|
|
|
|
|
(perhaps you forgot an endasm()?) |
|
391
|
|
|
|
|
|
|
EOD |
|
392
|
|
|
|
|
|
|
|
|
393
|
1
|
|
|
|
|
3
|
$linenum = $errors = 0; |
|
394
|
1
|
|
|
|
|
3
|
$out = $outsub; |
|
395
|
|
|
|
|
|
|
|
|
396
|
1
|
|
|
|
|
5
|
$out->( gen_header() ); |
|
397
|
|
|
|
|
|
|
} |
|
398
|
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
sub endasm { |
|
400
|
1
|
50
|
|
1
|
0
|
6
|
if ($errors) { |
|
401
|
1
|
|
|
|
|
9
|
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
|
202
|
|
|
202
|
0
|
463
|
my ($line) = @_; |
|
409
|
202
|
|
|
|
|
598
|
my ( $insn, $arg, $comment ); |
|
410
|
202
|
|
|
|
|
337
|
$linenum++; |
|
411
|
202
|
|
|
|
|
371
|
chomp $line; |
|
412
|
202
|
|
|
|
|
424
|
$line =~ s/\cM$//; |
|
413
|
202
|
50
|
|
|
|
476
|
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
|
202
|
|
|
|
|
394
|
( $line, $comment ) = strip_comments($line); |
|
420
|
202
|
50
|
0
|
|
|
471
|
if ($line) { |
|
|
|
0
|
|
|
|
|
|
|
421
|
202
|
|
|
|
|
405
|
( $insn, $arg ) = parse_statement($line); |
|
422
|
202
|
0
|
33
|
|
|
486
|
if ($debug and !$comment and $insn =~ /_flags/) { |
|
|
|
|
33
|
|
|
|
|
|
423
|
0
|
|
|
|
|
0
|
$comment = sprintf("0x%x", $arg); |
|
424
|
|
|
|
|
|
|
} |
|
425
|
202
|
|
|
|
|
421
|
$out->( assemble_insn( $insn, $arg, $comment ) ); |
|
426
|
202
|
50
|
|
|
|
11544
|
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__ |