diff options
author | David Benjamin <davidben@google.com> | 2016-03-20 14:47:36 -0400 |
---|---|---|
committer | Andy Polyakov <appro@openssl.org> | 2016-06-14 22:50:04 +0200 |
commit | c25278db8e4c21772a0cd81f7873e767cbc6d219 (patch) | |
tree | 02b48ce954764147fd7929e5bf51fdb23a235c64 /crypto/perlasm/x86_64-xlate.pl | |
parent | b867c7077a0ebf2ca17f9d020c112f790074571b (diff) |
Make x86_64-xlate.pl 'use strict' clean.
use strict would have caught a number of historical bugs in the perlasm
code, some in the repository and some found during review. It even found
a fresh masm-only bug (see below).
This required some tweaks. The "single instance is enough" globals got
switched to proper blessed objects rather than relying on symbolic refs.
A few types need $opcode passed in as a result.
The $$line thing is a little bit of a nuisance. There may be a clearer
pattern to use instead.
This even a bug in the masm code.
9b634c9b37afc482a8dc8868e367bdd1b650e507 added logic to make labels
global or function-global based on whether something starts with a $,
seemingly intended to capture the $decor setting of '$L$'. However, it
references $ret which is not defined in label::out. label::out is always
called after label::re, so $ret was always the label itself, so the line
always ran.
I've removed the regular expression so as not to change the behavior of
the script. A number of the assembly files now routinely jump across
functions, so this seems to be the desired behavior now.
GH#1165
Signed-off-by: Andy Polyakov <appro@openssl.org>
Reviewed-by: Rich Salz <rsalz@openssl.org>
Diffstat (limited to 'crypto/perlasm/x86_64-xlate.pl')
-rwxr-xr-x | crypto/perlasm/x86_64-xlate.pl | 233 |
1 files changed, 119 insertions, 114 deletions
diff --git a/crypto/perlasm/x86_64-xlate.pl b/crypto/perlasm/x86_64-xlate.pl index b96873b55c..646f68058c 100755 --- a/crypto/perlasm/x86_64-xlate.pl +++ b/crypto/perlasm/x86_64-xlate.pl @@ -65,6 +65,9 @@ # a. If function accepts more than 4 arguments *and* >4th argument # is declared as non 64-bit value, do clear its upper part. + +use strict; + my $flavour = shift; my $output = shift; if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } @@ -109,14 +112,15 @@ my %globals; { package opcode; # pick up opcodes sub re { - my $self = shift; # single instance in enough... - local *line = shift; - undef $ret; + my ($class, $line) = @_; + my $self = {}; + my $ret; - if ($line =~ /^([a-z][a-z0-9]*)/i) { + if ($$line =~ /^([a-z][a-z0-9]*)/i) { + bless $self,$class; $self->{op} = $1; $ret = $self; - $line = substr($line,@+[0]); $line =~ s/^\s+//; + $$line = substr($$line,@+[0]); $$line =~ s/^\s+//; undef $self->{sz}; if ($self->{op} =~ /^(movz)x?([bw]).*/) { # movz is pain... @@ -128,7 +132,7 @@ my %globals; $self->{sz} = ""; } elsif ($self->{op} =~ /^v/) { # VEX $self->{sz} = ""; - } elsif ($self->{op} =~ /mov[dq]/ && $line =~ /%xmm/) { + } elsif ($self->{op} =~ /mov[dq]/ && $$line =~ /%xmm/) { $self->{sz} = ""; } elsif ($self->{op} =~ /([a-z]{3,})([qlwb])$/) { $self->{op} = $1; @@ -138,8 +142,7 @@ my %globals; $ret; } sub size { - my $self = shift; - my $sz = shift; + my ($self, $sz) = @_; $self->{sz} = $sz if (defined($sz) && !defined($self->{sz})); $self->{sz}; } @@ -180,22 +183,22 @@ my %globals; } } sub mnemonic { - my $self=shift; - my $op=shift; + my ($self, $op) = @_; $self->{op}=$op if (defined($op)); $self->{op}; } } { package const; # pick up constants, which start with $ sub re { - my $self = shift; # single instance in enough... - local *line = shift; - undef $ret; + my ($class, $line) = @_; + my $self = {}; + my $ret; - if ($line =~ /^\$([^,]+)/) { + if ($$line =~ /^\$([^,]+)/) { + bless $self, $class; $self->{value} = $1; $ret = $self; - $line = substr($line,@+[0]); $line =~ s/^\s+//; + $$line = substr($$line,@+[0]); $$line =~ s/^\s+//; } $ret; } @@ -220,32 +223,33 @@ my %globals; } { package ea; # pick up effective addresses: expr(%reg,%reg,scale) sub re { - my $self = shift; # single instance in enough... - local *line = shift; - undef $ret; + my ($class, $line, $opcode) = @_; + my $self = {}; + my $ret; # optional * ---vvv--- appears in indirect jmp/call - if ($line =~ /^(\*?)([^\(,]*)\(([%\w,]+)\)/) { + if ($$line =~ /^(\*?)([^\(,]*)\(([%\w,]+)\)/) { + bless $self, $class; $self->{asterisk} = $1; $self->{label} = $2; ($self->{base},$self->{index},$self->{scale})=split(/,/,$3); $self->{scale} = 1 if (!defined($self->{scale})); $ret = $self; - $line = substr($line,@+[0]); $line =~ s/^\s+//; + $$line = substr($$line,@+[0]); $$line =~ s/^\s+//; if ($win64 && $self->{label} =~ s/\@GOTPCREL//) { - die if (opcode->mnemonic() ne "mov"); - opcode->mnemonic("lea"); + die if ($opcode->mnemonic() ne "mov"); + $opcode->mnemonic("lea"); } $self->{base} =~ s/^%//; $self->{index} =~ s/^%// if (defined($self->{index})); + $self->{opcode} = $opcode; } $ret; } sub size {} sub out { - my $self = shift; - my $sz = shift; + my ($self, $sz) = @_; $self->{label} =~ s/([_a-z][_a-z0-9]*)/$globals{$1} or $1/gei; $self->{label} =~ s/\.L/$decor/g; @@ -280,7 +284,7 @@ my %globals; sprintf "%s%s(%%%s)", $self->{asterisk},$self->{label},$self->{base}; } } else { - %szmap = ( b=>"BYTE$PTR", w=>"WORD$PTR", + my %szmap = ( b=>"BYTE$PTR", w=>"WORD$PTR", l=>"DWORD$PTR", d=>"DWORD$PTR", q=>"QWORD$PTR", o=>"OWORD$PTR", x=>"XMMWORD$PTR", y=>"YMMWORD$PTR", z=>"ZMMWORD$PTR" ); @@ -289,11 +293,12 @@ my %globals; $self->{label} =~ s/(?<![\w\$\.])0x([0-9a-f]+)/0$1h/ig; $self->{label} = "($self->{label})" if ($self->{label} =~ /[\*\+\-\/]/); - ($self->{asterisk}) && ($sz="q") || - (opcode->mnemonic() =~ /^v?mov([qd])$/) && ($sz=$1) || - (opcode->mnemonic() =~ /^v?pinsr([qdwb])$/) && ($sz=$1) || - (opcode->mnemonic() =~ /^vpbroadcast([qdwb])$/) && ($sz=$1) || - (opcode->mnemonic() =~ /^v(?!perm)[a-z]+[fi]128$/) && ($sz="x"); + my $mnemonic = $self->{opcode}->mnemonic(); + ($self->{asterisk}) && ($sz="q") || + ($mnemonic =~ /^v?mov([qd])$/) && ($sz=$1) || + ($mnemonic =~ /^v?pinsr([qdwb])$/) && ($sz=$1) || + ($mnemonic =~ /^vpbroadcast([qdwb])$/) && ($sz=$1) || + ($mnemonic =~ /^v(?!perm)[a-z]+[fi]128$/) && ($sz="x"); if (defined($self->{index})) { sprintf "%s[%s%s*%d%s]",$szmap{$sz}, @@ -312,24 +317,23 @@ my %globals; } { package register; # pick up registers, which start with %. sub re { - my $class = shift; # multiple instances... + my ($class, $line) = @_; my $self = {}; - local *line = shift; - undef $ret; + my $ret; # optional * ---vvv--- appears in indirect jmp/call - if ($line =~ /^(\*?)%(\w+)/) { + if ($$line =~ /^(\*?)%(\w+)/) { bless $self,$class; $self->{asterisk} = $1; $self->{value} = $2; $ret = $self; - $line = substr($line,@+[0]); $line =~ s/^\s+//; + $$line = substr($$line,@+[0]); $$line =~ s/^\s+//; } $ret; } sub size { my $self = shift; - undef $ret; + my $ret; if ($self->{value} =~ /^r[\d]+b$/i) { $ret="b"; } elsif ($self->{value} =~ /^r[\d]+w$/i) { $ret="w"; } @@ -350,14 +354,15 @@ my %globals; } { package label; # pick up labels, which end with : sub re { - my $self = shift; # single instance is enough... - local *line = shift; - undef $ret; + my ($class, $line) = @_; + my $self = {}; + my $ret; - if ($line =~ /(^[\.\w]+)\:/) { + if ($$line =~ /(^[\.\w]+)\:/) { + bless $self,$class; $self->{value} = $1; $ret = $self; - $line = substr($line,@+[0]); $line =~ s/^\s+//; + $$line = substr($$line,@+[0]); $$line =~ s/^\s+//; $self->{value} =~ s/^\.L/$decor/; } @@ -387,7 +392,8 @@ my %globals; } $func; } elsif ($self->{value} ne "$current_function->{name}") { - $self->{value} .= ":" if ($masm && $ret!~m/^\$/); + # Make all labels in masm global. + $self->{value} .= ":" if ($masm); $self->{value} . ":"; } elsif ($win64 && $current_function->{abi} eq "svr4") { my $func = "$current_function->{name}" . @@ -416,24 +422,26 @@ my %globals; } { package expr; # pick up expressioins sub re { - my $self = shift; # single instance is enough... - local *line = shift; - undef $ret; + my ($class, $line, $opcode) = @_; + my $self = {}; + my $ret; - if ($line =~ /(^[^,]+)/) { + if ($$line =~ /(^[^,]+)/) { + bless $self,$class; $self->{value} = $1; $ret = $self; - $line = substr($line,@+[0]); $line =~ s/^\s+//; + $$line = substr($$line,@+[0]); $$line =~ s/^\s+//; $self->{value} =~ s/\@PLT// if (!$elf); $self->{value} =~ s/([_a-z][_a-z0-9]*)/$globals{$1} or $1/gei; $self->{value} =~ s/\.L/$decor/g; + $self->{opcode} = $opcode; } $ret; } sub out { my $self = shift; - if ($nasm && opcode->mnemonic()=~m/^j(?![re]cxz)/) { + if ($nasm && $self->{opcode}->mnemonic()=~m/^j(?![re]cxz)/) { "NEAR ".$self->{value}; } else { $self->{value}; @@ -442,9 +450,9 @@ my %globals; } { package directive; # pick up directives, which start with . sub re { - my $self = shift; # single instance is enough... - local *line = shift; - undef $ret; + my ($class, $line) = @_; + my $self = {}; + my $ret; my $dir; my %opcode = # lea 2f-1f(%rip),%dst; 1: nop; 2: ( "%rax"=>0x01058d48, "%rcx"=>0x010d8d48, @@ -456,25 +464,26 @@ my %globals; "%r12"=>0x01258d4c, "%r13"=>0x012d8d4c, "%r14"=>0x01358d4c, "%r15"=>0x013d8d4c ); - if ($line =~ /^\s*(\.\w+)/) { + if ($$line =~ /^\s*(\.\w+)/) { + bless $self,$class; $dir = $1; $ret = $self; undef $self->{value}; - $line = substr($line,@+[0]); $line =~ s/^\s+//; + $$line = substr($$line,@+[0]); $$line =~ s/^\s+//; SWITCH: for ($dir) { - /\.picmeup/ && do { if ($line =~ /(%r[\w]+)/i) { + /\.picmeup/ && do { if ($$line =~ /(%r[\w]+)/i) { $dir="\t.long"; - $line=sprintf "0x%x,0x90000000",$opcode{$1}; + $$line=sprintf "0x%x,0x90000000",$opcode{$1}; } last; }; /\.global|\.globl|\.extern/ - && do { $globals{$line} = $prefix . $line; - $line = $globals{$line} if ($prefix); + && do { $globals{$$line} = $prefix . $$line; + $$line = $globals{$$line} if ($prefix); last; }; - /\.type/ && do { ($sym,$type,$narg) = split(',',$line); + /\.type/ && do { my ($sym,$type,$narg) = split(',',$$line); if ($type eq "\@function") { undef $current_function; $current_function->{name} = $sym; @@ -486,25 +495,25 @@ my %globals; $current_function->{name} = $sym; $current_function->{scope} = defined($globals{$sym})?"PUBLIC":"PRIVATE"; } - $line =~ s/\@abi\-omnipotent/\@function/; - $line =~ s/\@function.*/\@function/; + $$line =~ s/\@abi\-omnipotent/\@function/; + $$line =~ s/\@function.*/\@function/; last; }; - /\.asciz/ && do { if ($line =~ /^"(.*)"$/) { + /\.asciz/ && do { if ($$line =~ /^"(.*)"$/) { $dir = ".byte"; - $line = join(",",unpack("C*",$1),0); + $$line = join(",",unpack("C*",$1),0); } last; }; /\.rva|\.long|\.quad/ - && do { $line =~ s/([_a-z][_a-z0-9]*)/$globals{$1} or $1/gei; - $line =~ s/\.L/$decor/g; + && do { $$line =~ s/([_a-z][_a-z0-9]*)/$globals{$1} or $1/gei; + $$line =~ s/\.L/$decor/g; last; }; } if ($gas) { - $self->{value} = $dir . "\t" . $line; + $self->{value} = $dir . "\t" . $$line; if ($dir =~ /\.extern/) { $self->{value} = ""; # swallow extern @@ -513,7 +522,7 @@ my %globals; $self->{value} = ".def\t" . ($globals{$1} or $1) . ";\t" . (defined($globals{$1})?".scl 2;":".scl 3;") . "\t.type 32;\t.endef" - if ($win64 && $line =~ /([^,]+),\@function/); + if ($win64 && $$line =~ /([^,]+),\@function/); } elsif (!$elf && $dir =~ /\.size/) { $self->{value} = ""; if (defined($current_function)) { @@ -522,9 +531,9 @@ my %globals; undef $current_function; } } elsif (!$elf && $dir =~ /\.align/) { - $self->{value} = ".p2align\t" . (log($line)/log(2)); + $self->{value} = ".p2align\t" . (log($$line)/log(2)); } elsif ($dir eq ".section") { - $current_segment=$line; + $current_segment=$$line; if (!$elf && $current_segment eq ".init") { if ($flavour eq "macosx") { $self->{value} = ".mod_init_func"; } elsif ($flavour eq "mingw64") { $self->{value} = ".section\t.ctors"; } @@ -532,13 +541,13 @@ my %globals; } elsif ($dir =~ /\.(text|data)/) { $current_segment=".$1"; } elsif ($dir =~ /\.hidden/) { - if ($flavour eq "macosx") { $self->{value} = ".private_extern\t$prefix$line"; } + if ($flavour eq "macosx") { $self->{value} = ".private_extern\t$prefix$$line"; } elsif ($flavour eq "mingw64") { $self->{value} = ""; } } elsif ($dir =~ /\.comm/) { - $self->{value} = "$dir\t$prefix$line"; + $self->{value} = "$dir\t$prefix$$line"; $self->{value} =~ s|,([0-9]+),([0-9]+)$|",$1,".log($2)/log(2)|e if ($flavour eq "macosx"); } - $line = ""; + $$line = ""; return $self; } @@ -569,38 +578,38 @@ my %globals; last; }; /\.section/ && do { my $v=undef; - $line =~ s/([^,]*).*/$1/; - $line = ".CRT\$XCU" if ($line eq ".init"); + $$line =~ s/([^,]*).*/$1/; + $$line = ".CRT\$XCU" if ($$line eq ".init"); if ($nasm) { - $v="section $line"; - if ($line=~/\.([px])data/) { + $v="section $$line"; + if ($$line=~/\.([px])data/) { $v.=" rdata align="; $v.=$1 eq "p"? 4 : 8; - } elsif ($line=~/\.CRT\$/i) { + } elsif ($$line=~/\.CRT\$/i) { $v.=" rdata align=8"; } } else { $v="$current_segment\tENDS\n" if ($current_segment); - $v.="$line\tSEGMENT"; - if ($line=~/\.([px])data/) { + $v.="$$line\tSEGMENT"; + if ($$line=~/\.([px])data/) { $v.=" READONLY"; $v.=" ALIGN(".($1 eq "p" ? 4 : 8).")" if ($masm>=$masmref); - } elsif ($line=~/\.CRT\$/i) { + } elsif ($$line=~/\.CRT\$/i) { $v.=" READONLY "; $v.=$masm>=$masmref ? "ALIGN(8)" : "DWORD"; } } - $current_segment = $line; + $current_segment = $$line; $self->{value} = $v; last; }; - /\.extern/ && do { $self->{value} = "EXTERN\t".$line; + /\.extern/ && do { $self->{value} = "EXTERN\t".$$line; $self->{value} .= ":NEAR" if ($masm); last; }; /\.globl|.global/ && do { $self->{value} = $masm?"PUBLIC":"global"; - $self->{value} .= "\t".$line; + $self->{value} .= "\t".$$line; last; }; /\.size/ && do { if (defined($current_function)) { @@ -615,12 +624,12 @@ my %globals; last; }; /\.align/ && do { my $max = ($masm && $masm>=$masmref) ? 256 : 4096; - $self->{value} = "ALIGN\t".($line>$max?$max:$line); + $self->{value} = "ALIGN\t".($$line>$max?$max:$$line); last; }; /\.(value|long|rva|quad)/ && do { my $sz = substr($1,0,1); - my @arr = split(/,\s*/,$line); + my @arr = split(/,\s*/,$$line); my $last = pop(@arr); my $conv = sub { my $var=shift; $var=~s/^(0b[0-1]+)/oct($1)/eig; @@ -636,7 +645,7 @@ my %globals; $self->{value} .= &$conv($last); last; }; - /\.byte/ && do { my @str=split(/,\s*/,$line); + /\.byte/ && do { my @str=split(/,\s*/,$$line); map(s/(0b[0-1]+)/oct($1)/eig,@str); map(s/0x([0-9a-f]+)/0$1h/ig,@str) if ($masm); while ($#str>15) { @@ -648,7 +657,7 @@ my %globals; .join(",",@str) if (@str); last; }; - /\.comm/ && do { my @str=split(/,\s*/,$line); + /\.comm/ && do { my @str=split(/,\s*/,$$line); my $v=undef; if ($nasm) { $v.="common $prefix@str[0] @str[1]"; @@ -662,7 +671,7 @@ my %globals; last; }; } - $line = ""; + $$line = ""; } $ret; @@ -674,12 +683,12 @@ my %globals; } sub rex { - local *opcode=shift; + my $opcode=shift; my ($dst,$src,$rex)=@_; $rex|=0x04 if($dst>=8); $rex|=0x01 if($src>=8); - push @opcode,($rex|0x40) if ($rex); + push @$opcode,($rex|0x40) if ($rex); } # older gas and ml64 don't handle SSE>2 instructions @@ -711,9 +720,9 @@ my $movq = sub { # elderly gas can't handle inter-register movq my $pextrd = sub { if (shift =~ /\$([0-9]+),\s*%xmm([0-9]+),\s*(%\w+)/) { my @opcode=(0x66); - $imm=$1; - $src=$2; - $dst=$3; + my $imm=$1; + my $src=$2; + my $dst=$3; if ($dst =~ /%r([0-9]+)d/) { $dst = $1; } elsif ($dst =~ /%e/) { $dst = $regrm{$dst}; } rex(\@opcode,$src,$dst); @@ -729,9 +738,9 @@ my $pextrd = sub { my $pinsrd = sub { if (shift =~ /\$([0-9]+),\s*(%\w+),\s*%xmm([0-9]+)/) { my @opcode=(0x66); - $imm=$1; - $src=$2; - $dst=$3; + my $imm=$1; + my $src=$2; + my $dst=$3; if ($src =~ /%r([0-9]+)/) { $src = $1; } elsif ($src =~ /%e/) { $src = $regrm{$src}; } rex(\@opcode,$dst,$src); @@ -810,14 +819,14 @@ my $rdseed = sub { }; sub rxb { - local *opcode=shift; + my $opcode=shift; my ($dst,$src1,$src2,$rxb)=@_; $rxb|=0x7<<5; $rxb&=~(0x04<<5) if($dst>=8); $rxb&=~(0x01<<5) if($src1>=8); $rxb&=~(0x02<<5) if($src2>=8); - push @opcode,$rxb; + push @$opcode,$rxb; } my $vprotd = sub { @@ -860,7 +869,7 @@ ___ OPTION DOTNAME ___ } -while(defined($line=<>)) { +while(defined(my $line=<>)) { $line =~ s|\R$||; # Better chomp @@ -869,31 +878,27 @@ while(defined($line=<>)) { $line =~ s|^\s+||; # ... and skip white spaces in beginning $line =~ s|\s+$||; # ... and at the end - undef $label; - undef $opcode; - undef @args; - - if ($label=label->re(\$line)) { print $label->out(); } + if (my $label=label->re(\$line)) { print $label->out(); } - if (directive->re(\$line)) { - printf "%s",directive->out(); - } elsif ($opcode=opcode->re(\$line)) { + if (my $directive=directive->re(\$line)) { + printf "%s",$directive->out(); + } elsif (my $opcode=opcode->re(\$line)) { my $asm = eval("\$".$opcode->mnemonic()); - undef @bytes; - if ((ref($asm) eq 'CODE') && scalar(@bytes=&$asm($line))) { + if ((ref($asm) eq 'CODE') && scalar(my @bytes=&$asm($line))) { print $gas?".byte\t":"DB\t",join(',',@bytes),"\n"; next; } + my @args; ARGUMENT: while (1) { my $arg; - if ($arg=register->re(\$line)) { opcode->size($arg->size()); } - elsif ($arg=const->re(\$line)) { } - elsif ($arg=ea->re(\$line)) { } - elsif ($arg=expr->re(\$line)) { } - else { last ARGUMENT; } + if ($arg=register->re(\$line)) { $opcode->size($arg->size()); } + elsif ($arg=const->re(\$line)) { } + elsif ($arg=ea->re(\$line, $opcode)) { } + elsif ($arg=expr->re(\$line, $opcode)) { } + else { last ARGUMENT; } push @args,$arg; @@ -904,7 +909,7 @@ while(defined($line=<>)) { if ($#args>=0) { my $insn; - my $sz=opcode->size(); + my $sz=$opcode->size(); if ($gas) { $insn = $opcode->out($#args>=1?$args[$#args]->size():$sz); |