Add ABI tests for HRSS assembly.

The last instruction did not unwind correctly. Also add .type and .size
annotations so that errors show up properly.

Change-Id: Id18e12b4ed51bdabb90bd5ac66631fd989649eec
Reviewed-on: https://boringssl-review.googlesource.com/c/34190
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
diff --git a/crypto/hrss/asm/poly_rq_mul.S b/crypto/hrss/asm/poly_rq_mul.S
index 0ad0fb5..ebaabd3 100644
--- a/crypto/hrss/asm/poly_rq_mul.S
+++ b/crypto/hrss/asm/poly_rq_mul.S
@@ -312,6 +312,7 @@
 .text
 .global poly_Rq_mul
 .hidden poly_Rq_mul
+.type poly_Rq_mul, @function
 .att_syntax prefix
 poly_Rq_mul:
 .cfi_startproc
@@ -8450,8 +8451,13 @@
 vmovdqu %ymm11, 1320(%rdi)
 mov %r8, %rsp
 pop %r12
+.cfi_restore r12
 pop %rbp
+.cfi_restore rbp
+.cfi_def_cfa_register rsp
+.cfi_adjust_cfa_offset -8
 ret
 .cfi_endproc
+.size poly_Rq_mul,.-poly_Rq_mul
 
 #endif
diff --git a/crypto/hrss/hrss.c b/crypto/hrss/hrss.c
index 13bfa08..71fa5e3 100644
--- a/crypto/hrss/hrss.c
+++ b/crypto/hrss/hrss.c
@@ -1387,23 +1387,12 @@
   OPENSSL_memset(&out->v[N], 0, 3 * sizeof(uint16_t));
 }
 
-// On x86-64, we can use the AVX2 code from [HRSS]. (The authors have given
-// explicit permission for this and signed a CLA.) However it's 57KB of object
-// code, so it's not used if |OPENSSL_SMALL| is defined.
-#if !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_SMALL) && \
-    defined(OPENSSL_X86_64) && defined(OPENSSL_LINUX)
-// poly_Rq_mul is defined in assembly.
-extern void poly_Rq_mul(struct poly *r, const struct poly *a,
-                        const struct poly *b);
-#endif
-
 static void poly_mul(struct poly *r, const struct poly *a,
                      const struct poly *b) {
-#if !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_SMALL) && \
-    defined(OPENSSL_X86_64) && defined(OPENSSL_LINUX)
+#if defined(POLY_RQ_MUL_ASM)
   const int has_avx2 = (OPENSSL_ia32cap_P[2] & (1 << 5)) != 0;
   if (has_avx2) {
-    poly_Rq_mul(r, a, b);
+    poly_Rq_mul(r->v, a->v, b->v);
     return;
   }
 #endif
diff --git a/crypto/hrss/hrss_test.cc b/crypto/hrss/hrss_test.cc
index ee0400e..596db07 100644
--- a/crypto/hrss/hrss_test.cc
+++ b/crypto/hrss/hrss_test.cc
@@ -14,9 +14,11 @@
 
 #include <gtest/gtest.h>
 
+#include <openssl/cpu.h>
 #include <openssl/hrss.h>
 #include <openssl/rand.h>
 
+#include "../test/abi_test.h"
 #include "../test/test_util.h"
 #include "internal.h"
 
@@ -477,3 +479,18 @@
   };
   EXPECT_EQ(Bytes(shared_key), Bytes(kExpectedFailureKey));
 }
+
+#if defined(POLY_RQ_MUL_ASM) && defined(SUPPORTS_ABI_TEST)
+TEST(HRSS, ABI) {
+  const bool has_avx2 = (OPENSSL_ia32cap_P[2] & (1 << 5)) != 0;
+  if (!has_avx2) {
+    fprintf(stderr, "Skipping ABI test due to lack of AVX2 support.\n");
+    return;
+  }
+
+  alignas(16) uint16_t r[N + 3];
+  alignas(16) uint16_t a[N + 3] = {0};
+  alignas(16) uint16_t b[N + 3] = {0};
+  CHECK_ABI(poly_Rq_mul, r, a, b);
+}
+#endif  // POLY_RQ_MUL_ASM && SUPPORTS_ABI_TEST
diff --git a/crypto/hrss/internal.h b/crypto/hrss/internal.h
index 70218b8..7cfe010 100644
--- a/crypto/hrss/internal.h
+++ b/crypto/hrss/internal.h
@@ -42,6 +42,18 @@
 OPENSSL_EXPORT void HRSS_poly3_invert(struct poly3 *out,
                                       const struct poly3 *in);
 
+// On x86-64, we can use the AVX2 code from [HRSS]. (The authors have given
+// explicit permission for this and signed a CLA.) However it's 57KB of object
+// code, so it's not used if |OPENSSL_SMALL| is defined.
+#if !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_SMALL) && \
+    defined(OPENSSL_X86_64) && defined(OPENSSL_LINUX)
+#define POLY_RQ_MUL_ASM
+// poly_Rq_mul is defined in assembly. Inputs and outputs must be 16-byte-
+// aligned.
+extern void poly_Rq_mul(uint16_t r[N + 3], const uint16_t a[N + 3],
+                        const uint16_t b[N + 3]);
+#endif
+
 
 #if defined(__cplusplus)
 }  // extern "C"