Preparation for including asm code from pq-code-package.

Subsequent CLs will make use of this.

Bug: 503700354
Change-Id: I28ed40a5517dc4e5133797e47906b8f56a6a6964
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/98028
Commit-Queue: Rudolf Polzer <rpolzer@google.com>
Reviewed-by: Adam Langley <agl@google.com>
Reviewed-by: Xiangfei Ding <xfding@google.com>
diff --git a/crypto/perlasm/PQCodePackage.pm b/crypto/perlasm/PQCodePackage.pm
new file mode 100644
index 0000000..a9a41cc
--- /dev/null
+++ b/crypto/perlasm/PQCodePackage.pm
@@ -0,0 +1,112 @@
+package PQCodePackage;
+
+use strict;
+use warnings;
+
+# Function to adapt assembly code from pq-code-package to BoringSSL usage.
+# Should be kept as simple as possible, and maybe even become an identity
+# function to just mark the origin of an assembly string.
+sub asm {
+    my ($asm) = @_;
+
+    # BoringSSL does not promise alignment for the key data.
+    $asm =~ s/\bvmovdqa\b/vmovdqu/g;
+
+    return $asm;
+}
+
+# TODO(crbug.com/33072965): Replace by a common approach.
+#
+# Adapter to use pq-code-package asm functions (which are red zone less SysV
+# ABI) from BoringSSL.
+#
+# Handles register saving and argument remapping.
+#
+# Function must not call any non-SysV-ABI functions, and if it calls any
+# SysV-ABI functions, $num_xmms must include the xmm registers they clobber
+# too.
+#
+# Arguments:
+#   $win64: Whether compiling for Windows.
+#   $num_xmms: Number of xmm registers starting with xmm6 that get clobbered.
+#   $num_args: Number of arguments the function takes (at most 4).
+sub abi_enter {
+    my ($win64, $num_xmms, $num_args) = @_;
+    my $out = "";
+    if ($win64) {
+        $out .= "        .seh_startproc\n";
+        # Stack layout: xmm6@rsp xmm7 xmm8 ... rdi rsi padding returnaddress.
+        # Padding needed to align the xmm registers to 16 bytes boundaries.
+        my $stack_alloc = 16 + $num_xmms * 16 + 8;
+        $out .= "        subq\t\$$stack_alloc, %rsp\n";
+        $out .= "        .seh_stackalloc\t$stack_alloc\n";
+
+        my $rdi_off = $num_xmms * 16;
+        my $rsi_off = $rdi_off + 8;
+        $out .= "        movq\t%rdi, $rdi_off(%rsp)\n";
+        $out .= "        .seh_savereg\t%rdi, $rdi_off\n";
+        $out .= "        movq\t%rsi, $rsi_off(%rsp)\n";
+        $out .= "        .seh_savereg\t%rsi, $rsi_off\n";
+
+        for (my $i = 0; $i < $num_xmms; $i++) {
+            my $reg = 6 + $i;
+            my $off = $i * 16;
+            $out .= "        vmovdqa\t%xmm$reg, $off(%rsp)\n";
+            $out .= "        .seh_savexmm\t%xmm$reg, $off\n";
+        }
+        $out .= "        .seh_endprologue\n";
+
+        # Map arguments. Funny ordering to spread out data dependencies.
+        $out .= "        movq\t%rdx, %rsi\n"
+            if $num_args >= 2;
+        $out .= "        movq\t%rcx, %rdi\n"
+            if $num_args >= 1;
+        $out .= "        movq\t%r8, %rdx\n"
+            if $num_args >= 3;
+        $out .= "        movq\t%r9, %rcx\n"
+            if $num_args >= 4;
+        die "abi_enter with invalid argument count: got $num_args, want <= 4"
+            if $num_args > 4;
+    }
+    return $out;
+}
+
+# TODO(crbug.com/33072965): Replace by a common approach.
+#
+# Adapter to use pq-code-package asm functions (which are red zone less SysV
+# ABI) from BoringSSL.
+#
+# Handles register restoring and AVX2 zeroing.
+#
+# Arguments:
+#   $win64: Whether compiling for Windows.
+#   $num_xmms: Number of xmm registers starting with xmm6 that get clobbered.
+#     Must match the argument to `abi_enter`.
+sub abi_exit {
+    my ($win64, $num_xmms) = @_;
+    my $out = "";
+    $out .= "        vzeroupper\n";
+    if ($win64) {
+        my $stack_alloc = 16 + $num_xmms * 16 + 8;
+
+        for (my $i = 0; $i < $num_xmms; $i++) {
+            my $reg = 6 + $i;
+            my $off = $i * 16;
+            $out .= "        vmovdqa\t$off(%rsp), %xmm$reg\n";
+        }
+
+        my $rdi_off = $num_xmms * 16;
+        my $rsi_off = $rdi_off + 8;
+        $out .= "        movq\t$rdi_off(%rsp), %rdi\n";
+        $out .= "        movq\t$rsi_off(%rsp), %rsi\n";
+
+        $out .= "        addq\t\$$stack_alloc, %rsp\n";
+    }
+    $out .= "        ret\n";
+    if ($win64) {
+        $out .= "        .seh_endproc\n";
+    }
+    return $out;
+}
+
+1;
diff --git a/crypto/perlasm/x86_64-xlate.pl b/crypto/perlasm/x86_64-xlate.pl
index 508d36f..affebf1 100755
--- a/crypto/perlasm/x86_64-xlate.pl
+++ b/crypto/perlasm/x86_64-xlate.pl
@@ -130,7 +130,7 @@
 		$self->{sz} = $2;
 	    } elsif ($self->{op} =~ /call|jmp|^rdrand$/) {
 		$self->{sz} = "";
-	    } elsif ($self->{op} =~ /^p/ && $' !~ /^(ush|op|insrw)/) { # SSEn
+	    } elsif ($self->{op} =~ /^p/ && $' !~ /^(ush|op|insrw|ext[ql]?$|dep[ql]?$)/) { # SSEn
 		$self->{sz} = "";
 	    } elsif ($self->{op} =~ /^[vk]/) { # VEX or k* such as kmov
 		$self->{sz} = "";
diff --git a/util/pregenerate/build.go b/util/pregenerate/build.go
index e3f732b..4951e04 100644
--- a/util/pregenerate/build.go
+++ b/util/pregenerate/build.go
@@ -57,6 +57,25 @@
 	Args []string `json:"args,omitempty"`
 }
 
+// findThirdParty locates the deepest package directory `dir` is in - either `dir` itself, or a subdirectory of a `third_party` directory.
+func findThirdParty(dir string) string {
+	for {
+		parent := path.Dir(dir)
+		if path.Base(parent) == "third_party" {
+			return dir
+		}
+		if parent == dir {
+			return dir
+		}
+		dir = parent
+	}
+}
+
+// matchThirdParty returns an edited form of the `dst` path so it has the same `third_party` prefix as `src`.
+func matchThirdParty(src, dst string) string {
+	return path.Join(findThirdParty(src), dst)
+}
+
 // Pregenerate converts an input target to an output target. It returns the
 // result alongside a list of tasks that must be run to build the referenced
 // files.
@@ -110,6 +129,7 @@
 			dst = strings.TrimSuffix(path.Base(p.Src), ".pl")
 		}
 		dst = path.Join("gen", name, dst+fileSuffix)
+		dst = matchThirdParty(p.Src, dst)
 		args = append(slices.Clone(args), p.Args...)
 		addTask(list, NewPerlasmTask(dst, p.Src, args))
 		return dst
diff --git a/util/pregenerate/task.go b/util/pregenerate/task.go
index c6bc71e..bd38a75 100644
--- a/util/pregenerate/task.go
+++ b/util/pregenerate/task.go
@@ -140,6 +140,7 @@
 		defer os.Remove(out.Name())
 
 		args := make([]string, 0, 2+len(perlasmArgs))
+		args = append(args, "-Icrypto/perlasm")
 		args = append(args, filepath.FromSlash(src))
 		args = append(args, perlasmArgs...)
 		args = append(args, out.Name())