crypto/perlasm/x86_64-xlate.pl: detect GNU as to deal with quirks
[openssl.git] / crypto / perlasm / x86_64-xlate.pl
index 09d293a446f22347d110bd8e867bb5faf7a7c1f5..197bc48873cabe628e54e208b3421dfbb4434d3d 100755 (executable)
@@ -1,7 +1,7 @@
 #! /usr/bin/env perl
-# Copyright 2005-2016 The OpenSSL Project Authors. All Rights Reserved.
+# Copyright 2005-2018 The OpenSSL Project Authors. All Rights Reserved.
 #
-# Licensed under the OpenSSL license (the "License").  You may not use
+# Licensed under the Apache License 2.0 (the "License").  You may not use
 # this file except in compliance with the License.  You can obtain a copy
 # in the file LICENSE in the source distribution or at
 # https://www.openssl.org/source/license.html
@@ -83,6 +83,10 @@ my $PTR=" PTR";
 my $nasmref=2.03;
 my $nasm=0;
 
+# GNU as indicator, as opposed to $gas, which indicates acceptable
+# syntax
+my $gnuas=0;
+
 if    ($flavour eq "mingw64")  { $gas=1; $elf=0; $win64=1;
                                  $prefix=`echo __USER_LABEL_PREFIX__ | $ENV{CC} -E -P -`;
                                  $prefix =~ s|\R$||; # Better chomp
@@ -100,6 +104,46 @@ elsif (!$gas)
     $elf=0;
     $decor="\$L\$";
 }
+# Find out if we're using GNU as
+elsif (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
+               =~ /GNU assembler version ([2-9]\.[0-9]+)/)
+{
+    $gnuas=1;
+}
+
+my $cet_property;
+if ($flavour =~ /elf/) {
+       # Always generate .note.gnu.property section for ELF outputs to
+       # mark Intel CET support since all input files must be marked
+       # with Intel CET support in order for linker to mark output with
+       # Intel CET support.
+       my $p2align=3; $p2align=2 if ($flavour eq "elf32");
+       my $section='.note.gnu.property, #alloc';
+       $section='".note.gnu.property", "a"' if $gnuas;
+       $cet_property = <<_____;
+       .section $section
+       .p2align $p2align
+       .long 1f - 0f
+       .long 4f - 1f
+       .long 5
+0:
+       # "GNU" encoded with .byte, since .asciz isn't supported
+       # on Solaris.
+       .byte 0x47
+       .byte 0x4e
+       .byte 0x55
+       .byte 0
+1:
+       .p2align $p2align
+       .long 0xc0000002
+       .long 3f - 2f
+2:
+       .long 3
+3:
+       .p2align $p2align
+4:
+_____
+}
 
 my $current_segment;
 my $current_function;
@@ -212,8 +256,9 @@ my %globals;
            }
            sprintf "\$%s",$self->{value};
        } else {
-           $self->{value} =~ s/0x([0-9a-f]+)/0$1h/ig if ($masm);
-           sprintf "%s",$self->{value};
+           my $value = $self->{value};
+           $value =~ s/0x([0-9a-f]+)/0$1h/ig if ($masm);
+           sprintf "%s",$value;
        }
     }
 }
@@ -279,7 +324,7 @@ my %globals;
        }
 
        # if base register is %rbp or %r13, see if it's possible to
-       # flip base and ingex registers [for better performance]
+       # flip base and index registers [for better performance]
        if (!$self->{label} && $self->{index} && $self->{scale}==1 &&
            $self->{base} =~ /(rbp|r13)/) {
                $self->{base} = $self->{index}; $self->{index} = $1;
@@ -437,7 +482,7 @@ my %globals;
        }
     }
 }
-{ package expr;                # pick up expressioins
+{ package expr;                # pick up expressions
     sub re {
        my      ($class, $line, $opcode) = @_;
        my      $self = {};
@@ -530,7 +575,7 @@ my %globals;
        );
 
     # Following constants are defined in x86_64 ABI supplement, for
-    # example avaiable at https://www.uclibc.org/docs/psABI-x86_64.pdf,
+    # example available at https://www.uclibc.org/docs/psABI-x86_64.pdf,
     # see section 3.7 "Stack Unwind Algorithm".
     my %DW_reg_idx = (
        "%rax"=>0,  "%rdx"=>1,  "%rcx"=>2,  "%rbx"=>3,
@@ -540,10 +585,11 @@ my %globals;
        );
 
     my ($cfa_reg, $cfa_rsp);
+    my @cfa_stack;
 
     # [us]leb128 format is variable-length integer representation base
     # 2^128, with most significant bit of each byte being 0 denoting
-    # *last* most significat digit. See "Variable Length Data" in the
+    # *last* most significant digit. See "Variable Length Data" in the
     # DWARF specification, numbered 7.6 at least in versions 3 and 4.
     sub sleb128 {
        use integer;    # get right shift extend sign
@@ -610,6 +656,8 @@ my %globals;
        foreach my $token (split(/,\s*/,$line)) {
            if ($token =~ /^%r/) {
                push @ret,reg($token);
+           } elsif ($token =~ /((?:0x)?[0-9a-f]+)\((%r\w+)\)/) {
+               push @ret,reg("$2+$1");
            } elsif ($token =~ /(\w+):(\-?(?:0x)?[0-9a-f]+)(U?)/i) {
                my $i = 1*eval($2);
                push @ret,$DW_OP_complex{$1}, ($3 ? uleb128($i) : sleb128($i));
@@ -633,7 +681,7 @@ my %globals;
        my      $self = {};
        my      $ret;
 
-       if ($$line =~ s/^\s*\.cfi_(\w+)\s+//) {
+       if ($$line =~ s/^\s*\.cfi_(\w+)\s*//) {
            bless $self,$class;
            $ret = $self;
            undef $self->{value};
@@ -645,7 +693,13 @@ my %globals;
            # why it starts with -8. Recall that CFA is top of caller's
            # stack...
            /startproc/ && do { ($cfa_reg, $cfa_rsp) = ("%rsp", -8); last; };
-           /endproc/   && do { ($cfa_reg, $cfa_rsp) = ("%rsp",  0); last; };
+           /endproc/   && do { ($cfa_reg, $cfa_rsp) = ("%rsp",  0);
+                               # .cfi_remember_state directives that are not
+                               # matched with .cfi_restore_state are
+                               # unnecessary.
+                               die "unpaired .cfi_remember_state" if (@cfa_stack);
+                               last;
+                             };
            /def_cfa_register/
                        && do { $cfa_reg = $$line; last; };
            /def_cfa_offset/
@@ -656,7 +710,7 @@ my %globals;
                        && do { $cfa_rsp -= 1*eval($$line) if ($cfa_reg eq "%rsp");
                                last;
                              };
-           /def_cfa/   && do { if ($$line =~ /(%r\w+)\s*,\s*(\.+)/) {
+           /def_cfa/   && do { if ($$line =~ /(%r\w+)\s*,\s*(.+)/) {
                                    $cfa_reg = $1;
                                    $cfa_rsp = -1*eval($2) if ($cfa_reg eq "%rsp");
                                }
@@ -685,6 +739,14 @@ my %globals;
                                                      cfa_expression($$line)));
                                last;
                              };
+           /remember_state/
+                       && do { push @cfa_stack, [$cfa_reg, $cfa_rsp];
+                               last;
+                             };
+           /restore_state/
+                       && do { ($cfa_reg, $cfa_rsp) = @{pop @cfa_stack};
+                               last;
+                             };
            }
 
            $self->{value} = ".cfi_$dir\t$$line" if ($dir);
@@ -874,7 +936,7 @@ my %globals;
                                                        $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=~s/^([_a-z\$\@][_a-z0-9\$\@]*)/$nasm?"$1 wrt ..imagebase":"imagerel $1"/egi; }
                                                        $var;
                                                    };
 
@@ -1195,10 +1257,11 @@ while(defined(my $line=<>)) {
     print $line,"\n";
 }
 
+print "$cet_property"                  if ($cet_property);
 print "\n$current_segment\tENDS\n"     if ($current_segment && $masm);
 print "END\n"                          if ($masm);
 
-close STDOUT;
+close STDOUT or die "error closing STDOUT: $!;"
 
 \f#################################################
 # Cross-reference x86_64 ABI "card"
@@ -1243,7 +1306,7 @@ close STDOUT;
 # the area above user stack pointer in true asynchronous manner...
 #
 # All the above means that if assembler programmer adheres to Unix
-# register and stack layout, but disregards the "red zone" existense,
+# register and stack layout, but disregards the "red zone" existence,
 # it's possible to use following prologue and epilogue to "gear" from
 # Unix to Win64 ABI in leaf functions with not more than 6 arguments.
 #
@@ -1424,6 +1487,6 @@ close STDOUT;
 #
 # (*)  Note that we're talking about run-time, not debug-time. Lack of
 #      unwind information makes debugging hard on both Windows and
-#      Unix. "Unlike" referes to the fact that on Unix signal handler
+#      Unix. "Unlike" refers to the fact that on Unix signal handler
 #      will always be invoked, core dumped and appropriate exit code
 #      returned to parent (for user notification).