x86_64-xlate.pl: support for binary constants, such as 0b1010101.
[openssl.git] / crypto / perlasm / x86_64-xlate.pl
index 1f138508249151530cb18e8888fb5e43525df45c..131109d84950ebf74f04de9c46b76e16e62d84e1 100755 (executable)
@@ -71,6 +71,7 @@ my $gas=1;    $gas=0 if ($output =~ /\.asm$/);
 my $elf=1;     $elf=0 if (!$gas);
 my $win64=0;
 my $prefix="";
+my $decor=".L";
 
 my $masmref=8 + 50727*2**-32;  # 8.00.50727 shipped with VS2005
 my $masm=0;
@@ -80,9 +81,9 @@ my $nasmref=2.03;
 my $nasm=0;
 
 if    ($flavour eq "mingw64")  { $gas=1; $elf=0; $win64=1; $prefix="_"; }
-elsif ($flavour eq "macosx")   { $gas=1; $elf=0; $prefix="_"; }
-elsif ($flavour eq "masm")     { $gas=0; $elf=0; $masm=$masmref; $win64=1; }
-elsif ($flavour eq "nasm")     { $gas=0; $elf=0; $nasm=$nasmref; $win64=1; $PTR=""; }
+elsif ($flavour eq "macosx")   { $gas=1; $elf=0; $prefix="_"; $decor="L\$"; }
+elsif ($flavour eq "masm")     { $gas=0; $elf=0; $masm=$masmref; $win64=1; $decor="\$L\$"; }
+elsif ($flavour eq "nasm")     { $gas=0; $elf=0; $nasm=$nasmref; $win64=1; $decor="\$L\$"; $PTR=""; }
 elsif (!$gas)
 {   if ($ENV{ASM} =~ m/nasm/ && `nasm -v` =~ m/version ([0-9]+)\.([0-9]+)/i)
     {  $nasm = $1 + $2*0.01; $PTR="";  }
@@ -91,6 +92,7 @@ elsif (!$gas)
     die "no assembler found on %PATH" if (!($nasm || $masm));
     $win64=1;
     $elf=0;
+    $decor="\$L\$";
 }
 
 my $current_segment;
@@ -193,7 +195,8 @@ my %globals;
            $self->{value} =~ s/([0-9]+\s*[\*\/\%]\s*[0-9]+)/eval($1)/eg;
            sprintf "\$%s",$self->{value};
        } else {
-           $self->{value} =~ s/0x([0-9a-f]+)/0$1h/ig;
+           $self->{value} =~ s/(0b[0-1]+)/oct($1)/eig;
+           $self->{value} =~ s/0x([0-9a-f]+)/0$1h/ig if ($masm);
            sprintf "%s",$self->{value};
        }
     }
@@ -228,6 +231,7 @@ my %globals;
        my $sz = shift;
 
        $self->{label} =~ s/([_a-z][_a-z0-9]*)/$globals{$1} or $1/gei;
+       $self->{label} =~ s/\.L/$decor/g;
 
        # Silently convert all EAs to 64-bit. This is required for
        # elder GNU assembler and results in more compact code,
@@ -240,7 +244,7 @@ my %globals;
            # in $self->{label}
            $self->{label} =~ s/(?<![0-9a-f])(0[x0-9a-f]+)/oct($1)/egi;
            $self->{label} =~ s/([0-9]+\s*[\*\/\%]\s*[0-9]+)/eval($1)/eg;
-           $self->{label} =~ s/\.L/L\$/g       if (!$elf);
+           $self->{label} =~ s/^___imp_/__imp__/   if ($flavour eq "mingw64");
 
            if (defined($self->{index})) {
                sprintf "%s%s(%%%s,%%%s,%d)",$self->{asterisk},
@@ -252,7 +256,6 @@ my %globals;
        } else {
            %szmap = ( b=>"BYTE$PTR", w=>"WORD$PTR", l=>"DWORD$PTR", q=>"QWORD$PTR" );
 
-           $self->{label} =~ s/\.L/\$L\$/g;
            $self->{label} =~ s/\./\$/g;
            $self->{label} =~ s/0x([0-9a-f]+)/0$1h/ig;
            $self->{label} = "($self->{label})" if ($self->{label} =~ /[\*\+\-\/]/);
@@ -322,8 +325,7 @@ my %globals;
            $ret = $self;
            $line = substr($line,@+[0]); $line =~ s/^\s+//;
 
-           $self->{value} =~ s/\.L/\$L\$/ if (!$gas);
-           $self->{value} =~ s/\.L/L\$/   if (!$elf);
+           $self->{value} =~ s/^\.L/$decor/;
        }
        $ret;
     }
@@ -339,7 +341,7 @@ my %globals;
                $func .= "      movq    %rdi,8(%rsp)\n";
                $func .= "      movq    %rsi,16(%rsp)\n";
                $func .= "      movq    %rsp,%rax\n";
-               $func .= ".LSEH_begin_$current_function->{name}:\n";
+               $func .= "${decor}SEH_begin_$current_function->{name}:\n";
                my $narg = $current_function->{narg};
                $narg=6 if (!defined($narg));
                $func .= "      movq    %rcx,%rdi\n" if ($narg>0);
@@ -360,7 +362,7 @@ my %globals;
            $func .= "  mov     QWORD${PTR}[8+rsp],rdi\t;WIN64 prologue\n";
            $func .= "  mov     QWORD${PTR}[16+rsp],rsi\n";
            $func .= "  mov     rax,rsp\n";
-           $func .= "\$L\$SEH_begin_$current_function->{name}:";
+           $func .= "${decor}SEH_begin_$current_function->{name}:";
            $func .= ":" if ($masm);
            $func .= "\n";
            my $narg = $current_function->{narg};
@@ -391,8 +393,7 @@ my %globals;
 
            $self->{value} =~ s/\@PLT// if (!$elf);
            $self->{value} =~ s/([_a-z][_a-z0-9]*)/$globals{$1} or $1/gei;
-           $self->{value} =~ s/\.L/\$L\$/g if (!$gas);
-           $self->{value} =~ s/\.L/L\$/g   if (!$elf);
+           $self->{value} =~ s/\.L/$decor/g;
        }
        $ret;
     }
@@ -461,6 +462,11 @@ my %globals;
                                    }
                                    last;
                                  };
+               /\.rva|\.long|\.quad/
+                           && do { $line =~ s/([_a-z][_a-z0-9]*)/$globals{$1} or $1/gei;
+                                   $line =~ s/\.L/$decor/g;
+                                   last;
+                                 };
            }
 
            if ($gas) {
@@ -477,7 +483,7 @@ my %globals;
                } elsif (!$elf && $dir =~ /\.size/) {
                    $self->{value} = "";
                    if (defined($current_function)) {
-                       $self->{value} .= ".LSEH_end_$current_function->{name}:"
+                       $self->{value} .= "${decor}SEH_end_$current_function->{name}:"
                                if ($win64 && $current_function->{abi} eq "svr4");
                        undef $current_function;
                    }
@@ -555,7 +561,7 @@ my %globals;
                /\.size/    && do { if (defined($current_function)) {
                                        undef $self->{value};
                                        if ($current_function->{abi} eq "svr4") {
-                                           $self->{value}="\$L\$SEH_end_$current_function->{name}:";
+                                           $self->{value}="${decor}SEH_end_$current_function->{name}:";
                                            $self->{value}.=":\n" if($masm);
                                        }
                                        $self->{value}.="$current_function->{name}\tENDP" if($masm);
@@ -569,8 +575,8 @@ my %globals;
                                    my @arr = split(',',$line);
                                    my $last = pop(@arr);
                                    my $conv = sub  {   my $var=shift;
-                                                       $var=~s/0x([0-9a-f]+)/0$1h/ig;
-                                                       $var=~s/\.L/\$L\$/g;
+                                                       $var=~s/(0b[0-1]+)/oct($1)/eig;
+                                                       $var=~s/0x([0-9a-f]+)/0$1h/ig if ($masm);
                                                        if ($sz eq "D" && ($current_segment=~/.[px]data/ || $dir eq ".rva"))
                                                        { $var=~s/([_a-z\$\@][_a-z0-9\$\@]*)/$nasm?"$1 wrt ..imagebase":"imagerel $1"/egi; }
                                                        $var;
@@ -583,6 +589,8 @@ my %globals;
                                    last;
                                  };
                /\.byte/    && do { my @str=split(",",$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) {
                                        $self->{value}.="DB\t"
                                                .join(",",@str[0..15])."\n";
@@ -623,44 +631,41 @@ while($line=<>) {
 
     undef $label;
     undef $opcode;
-    undef $dst;
-    undef $src;
     undef $sz;
+    undef @args;
 
     if ($label=label->re(\$line))      { print $label->out(); }
 
     if (directive->re(\$line)) {
        printf "%s",directive->out();
-    } elsif ($opcode=opcode->re(\$line)) { ARGUMENT: {
+    } elsif ($opcode=opcode->re(\$line)) { ARGUMENT: while (1) {
+       my $arg;
 
-       if ($src=register->re(\$line))  { opcode->size($src->size()); }
-       elsif ($src=const->re(\$line))  { }
-       elsif ($src=ea->re(\$line))     { }
-       elsif ($src=expr->re(\$line))   { }
+       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; }
 
-       last ARGUMENT if ($line !~ /^,/);
+       push @args,$arg;
 
-       $line = substr($line,1); $line =~ s/^\s+//;
-
-       if ($dst=register->re(\$line))  { opcode->size($dst->size()); }
-       elsif ($dst=const->re(\$line))  { }
-       elsif ($dst=ea->re(\$line))     { }
+       last ARGUMENT if ($line !~ /^,/);
 
+       $line =~ s/^,\s*//;
        } # ARGUMENT:
 
        $sz=opcode->size();
 
-       if (defined($dst)) {
+       if ($#args>=0) {
+           my $insn;
            if ($gas) {
-               printf "\t%s\t%s,%s",   $opcode->out($dst->size()),
-                                       $src->out($sz),$dst->out($sz);
+               $insn = $opcode->out($#args>=1?$args[$#args]->size():$sz);
            } else {
+               $insn = $opcode->out();
+               @args = reverse(@args);
                undef $sz if ($nasm && $opcode->mnemonic() eq "lea");
-               printf "\t%s\t%s,%s",   $opcode->out(),
-                                       $dst->out($sz),$src->out($sz);
            }
-       } elsif (defined($src)) {
-           printf "\t%s\t%s",$opcode->out(),$src->out($sz);
+           printf "\t%s\t%s",$insn,join(",",map($_->out($sz),@args));
        } else {
            printf "\t%s",$opcode->out();
        }