[PATCH 1/3] aarch64-asm: fix macOS build and enable asm implementations

Jussi Kivilinna jussi.kivilinna at iki.fi
Mon Sep 28 18:43:38 CEST 2026


* build-aux/darwin-aarch64-as.sh: New.
* Makefile.am (EXTRA_DIST): Add 'build-aux/darwin-aarch64-as.sh'.
* cipher/Makefile.am (CLEANFILES): Add '*-darwin.s'.
* mpi/Makefile.am (CLEANFILES): New.
* configure.ac [*-apple-darwin*] (CCAS): Use 'darwin-aarch64-as.sh'
wrapper on macOS AArch64.
(GNUPG_SYS_SYMBOL_UNDERSCORE): Move before assembler checks.
(symbol_prefix): New.
(gcry_cv_gcc_aarch64_platform_as_ok)
(gcry_cv_gcc_inline_asm_aarch64_neon)
(gcry_cv_gcc_inline_asm_aarch64_crypto)
(gcry_cv_gcc_inline_asm_aarch64_sve)
(gcry_cv_gcc_inline_asm_aarch64_sve2)
(gcry_cv_gcc_inline_asm_aarch64_sha3_sha512_sm3_sm4): Add symbol
prefix to test function label.
* acinclude.m4 (GNUPG_SYS_SYMBOL_UNDERSCORE): Set underscore prefix
for AArch64 Darwin.
* cipher/asm-common-aarch64.h [__APPLE__] (SECTION_RODATA): New.
[__APPLE__] (GET_DATA_POINTER): Use '@PAGE' and '@PAGEOFF'.
--

Darwin assembler uses ';' as comment character, so statements after
first ';' in macro expansions were silently dropped. Commit 9b684f4a
added ';' separator in 'CFI_ENDPROC' and then caused macOS builds
fail with "Unfinished frame!" error in mpi/aarch64.

Also AArch64 cipher assembly was never built on macOS as configure
checks failed to link test function because of missing '_' symbol
prefix.

Patch adds assembler wrapper for AArch64 Darwin that is used as CCAS.
Wrapper runs C preprocessor on .S source, splits ';' separated
statements to separate lines, converts '.L' local labels to Darwin
'L' prefix and adds '_' prefix to _gcry symbols, and then assembles
the result. Darwin variant of 'GET_DATA_POINTER' used GOT relocation
with 'add' instruction, which assembler rejects, and 'SECTION_RODATA'
did not have Darwin variant.

Benchmark on Apple M1 Mac Mini:

Hash:
                |  nanosecs/byte   mebibytes/sec   cycles/byte  auto Mhz
 SHA1           |     0.408 ns/B      2336 MiB/s      1.30 c/B      3192
 SHA256         |     0.411 ns/B      2321 MiB/s      1.31 c/B      3192
 SHA512         |     0.693 ns/B      1377 MiB/s      2.21 c/B      3192
                =

Cipher:
 AES            |  nanosecs/byte   mebibytes/sec   cycles/byte  auto Mhz
        ECB enc |     0.077 ns/B     12370 MiB/s     0.246 c/B      3192
        ECB dec |     0.077 ns/B     12307 MiB/s     0.247 c/B      3192
        CBC enc |     0.634 ns/B      1505 MiB/s      2.02 c/B      3192
        CBC dec |     0.076 ns/B     12540 MiB/s     0.243 c/B      3192
        CFB enc |     0.637 ns/B      1498 MiB/s      2.03 c/B      3192
        CFB dec |     0.070 ns/B     13594 MiB/s     0.224 c/B      3192
        OFB enc |     0.751 ns/B      1270 MiB/s      2.40 c/B      3192
        OFB dec |     0.751 ns/B      1269 MiB/s      2.40 c/B      3192
        CTR enc |     0.078 ns/B     12192 MiB/s     0.250 c/B      3192
        CTR dec |     0.078 ns/B     12206 MiB/s     0.249 c/B      3192
        XTS enc |     0.124 ns/B      7714 MiB/s     0.395 c/B      3192
        XTS dec |     0.124 ns/B      7715 MiB/s     0.395 c/B      3192
        CCM enc |     0.710 ns/B      1343 MiB/s      2.27 c/B      3192
        CCM dec |     0.712 ns/B      1339 MiB/s      2.27 c/B      3192
       CCM auth |     0.632 ns/B      1509 MiB/s      2.02 c/B      3192
        EAX enc |     0.712 ns/B      1340 MiB/s      2.27 c/B      3192
        EAX dec |     0.715 ns/B      1334 MiB/s      2.28 c/B      3192
       EAX auth |     0.635 ns/B      1501 MiB/s      2.03 c/B      3192
        GCM enc |     0.180 ns/B      5292 MiB/s     0.575 c/B      3192
        GCM dec |     0.181 ns/B      5278 MiB/s     0.577 c/B      3192
       GCM auth |     0.101 ns/B      9420 MiB/s     0.323 c/B      3192
        OCB enc |     0.074 ns/B     12847 MiB/s     0.237 c/B      3192
        OCB dec |     0.072 ns/B     13155 MiB/s     0.231 c/B      3192
       OCB auth |     0.102 ns/B      9372 MiB/s     0.325 c/B      3192
        SIV enc |     0.713 ns/B      1337 MiB/s      2.28 c/B      3192
        SIV dec |     0.725 ns/B      1315 MiB/s      2.31 c/B      3192
       SIV auth |     0.633 ns/B      1506 MiB/s      2.02 c/B      3192
    GCM-SIV enc |     0.184 ns/B      5191 MiB/s     0.586 c/B      3192
    GCM-SIV dec |     0.191 ns/B      4991 MiB/s     0.610 c/B      3192
   GCM-SIV auth |     0.100 ns/B      9490 MiB/s     0.321 c/B      3192
                =
 CHACHA20       |  nanosecs/byte   mebibytes/sec   cycles/byte  auto Mhz
     STREAM enc |     0.709 ns/B      1346 MiB/s      2.26 c/B      3192
     STREAM dec |     0.708 ns/B      1346 MiB/s      2.26 c/B      3192
   POLY1305 enc |     0.721 ns/B      1322 MiB/s      2.30 c/B      3192
   POLY1305 dec |     0.705 ns/B      1353 MiB/s      2.25 c/B      3192
  POLY1305 auth |     0.291 ns/B      3274 MiB/s     0.930 c/B      3192
                =

GnuPG-bug-id: 8463
Signed-off-by: Jussi Kivilinna <jussi.kivilinna at iki.fi>
---
 Makefile.am                    |   1 +
 acinclude.m4                   |   3 +
 build-aux/darwin-aarch64-as.sh | 114 +++++++++++++++++++++++++++++++++
 cipher/Makefile.am             |   2 +-
 cipher/asm-common-aarch64.h    |   6 +-
 configure.ac                   |  38 +++++++----
 mpi/Makefile.am                |   1 +
 7 files changed, 149 insertions(+), 16 deletions(-)
 create mode 100644 build-aux/darwin-aarch64-as.sh

diff --git a/Makefile.am b/Makefile.am
index f4da0905..14520bc5 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -49,6 +49,7 @@ EXTRA_DIST = autogen.sh autogen.rc README.GIT LICENSES			   \
 	     m4/ChangeLog-2011 cipher/ChangeLog-2011 src/ChangeLog-2011	   \
 	     random/ChangeLog-2011 tests/ChangeLog-2011 mpi/ChangeLog-2011 \
 	     build-aux/libtool-patch.sed 				   \
+	     build-aux/darwin-aarch64-as.sh				   \
 	     build-aux/git-log-footer build-aux/git-log-fix VERSION
 
 DISTCLEANFILES =
diff --git a/acinclude.m4 b/acinclude.m4
index 43e0e906..1054d074 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -73,6 +73,9 @@ case "${host}" in
     i386-emx-os2 | i[3456]86-pc-os2*emx | i386-pc-msdosdjgpp)
         ac_cv_sys_symbol_underscore=yes
         ;;
+    aarch64-apple-darwin*)
+        ac_cv_sys_symbol_underscore=yes
+        ;;
     *)
       if test "$cross_compiling" != yes; then
          tmp_do_check="yes"
diff --git a/build-aux/darwin-aarch64-as.sh b/build-aux/darwin-aarch64-as.sh
new file mode 100644
index 00000000..83f80dcb
--- /dev/null
+++ b/build-aux/darwin-aarch64-as.sh
@@ -0,0 +1,114 @@
+#!/bin/sh
+# Assembler wrapper for AArch64 Darwin.
+# Copyright (C) 2026 Jussi Kivilinna <jussi.kivilinna at iki.fi>
+#
+# This file is part of Libgcrypt.
+#
+# Libgcrypt is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# Libgcrypt is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+# Darwin assembler uses ';' as comment character, treats only 'L' prefixed
+# labels as assembler local and C symbols have '_' prefix.
+#
+# Run C preprocessor on the .S source, then split ';' separated
+# statements to separate lines, convert '.L' labels to 'L' and add
+# prefix to _gcry symbols, and assemble the result.
+#
+# Usage: darwin-aarch64-as.sh CC [CCFLAGS...] ARGS...
+
+# Preprocess only: '-c' becomes '-E' and output goes to "$pp".
+run_cpp ()
+{
+  n=$#
+  skip=
+  for a in "$@"; do
+    if test -n "$skip"; then
+      skip=
+      a="$pp"
+    else
+      case "$a" in
+        -c) a=-E ;;
+        -o) skip=1 ;;
+      esac
+    fi
+    set -- "$@" "$a"
+  done
+  shift $n
+  "$@"
+}
+
+# Assemble "$asm" in place of "$src", without dependency generation.
+run_as ()
+{
+  n=$#
+  skip=
+  for a in "$@"; do
+    if test -n "$skip"; then
+      skip=
+      continue
+    fi
+    case "$a" in
+      -MT|-MF|-MQ) skip=1; continue ;;
+      -MD|-MMD|-MP) continue ;;
+      "$src") a="$asm" ;;
+    esac
+    set -- "$@" "$a"
+  done
+  shift $n
+  "$@"
+}
+
+# Find .S source and output object; pass through non-.S compiles as is.
+src=
+out=
+prev=
+for a in "$@"; do
+  case "$prev" in
+    -o) out="$a" ;;
+  esac
+  case "$a" in
+    *.S) src="$a" ;;
+  esac
+  prev="$a"
+done
+
+if test -z "$src"; then
+  exec "$@"
+fi
+
+# Place converted source next to output object, as libtool compiles
+# PIC and non-PIC objects to separate directories.
+base="${src##*/}"
+if test -n "$out"; then
+  asm="$(dirname "$out")/${base%.S}-darwin.s"
+else
+  asm="${base%.S}-darwin.s"
+fi
+pp="$asm.i"
+
+trap 'rm -f "$pp"' EXIT
+
+run_cpp "$@" || exit 1
+
+# Convert to Darwin syntax
+#  * ; separator to newline
+#  * .L local symbol prefix to L
+#  * _gcry_ global symbol prefix to __gcry_
+tr ';' '\n' < "$pp" | \
+  sed -e 's/^\.L/L/' \
+      -e 's/\([^A-Za-z0-9_.]\)\.L/\1L/g' \
+      -e 's/^_gcry_/__gcry_/' \
+      -e 's/\([^A-Za-z0-9_]\)_gcry_/\1__gcry_/g' \
+  > "$asm" || exit 1
+
+run_as "$@"
diff --git a/cipher/Makefile.am b/cipher/Makefile.am
index 0c00d181..486bd99e 100644
--- a/cipher/Makefile.am
+++ b/cipher/Makefile.am
@@ -29,7 +29,7 @@ AM_CCASFLAGS = $(NOEXECSTACK_FLAGS)
 EXTRA_DIST = gost-s-box.c kyber-common.c kyber-kdep.c \
              dilithium-common.c dilithium-dep.c
 
-CLEANFILES = gost-s-box$(EXEEXT_FOR_BUILD)
+CLEANFILES = gost-s-box$(EXEEXT_FOR_BUILD) *-darwin.s
 DISTCLEANFILES = gost-sb.h
 
 noinst_LTLIBRARIES = libcipher.la
diff --git a/cipher/asm-common-aarch64.h b/cipher/asm-common-aarch64.h
index ec9b9b92..821eeda5 100644
--- a/cipher/asm-common-aarch64.h
+++ b/cipher/asm-common-aarch64.h
@@ -31,14 +31,16 @@
 
 #ifdef _WIN32
 # define SECTION_RODATA .section .rdata
+#elif defined(__APPLE__)
+# define SECTION_RODATA .section __TEXT,__const
 #else
 # define SECTION_RODATA .section .rodata
 #endif
 
 #ifdef __APPLE__
 #define GET_DATA_POINTER(reg, name) \
-	adrp    reg, name at GOTPAGE ; \
-	add     reg, reg, name at GOTPAGEOFF ;
+	adrp    reg, name at PAGE ; \
+	add     reg, reg, name at PAGEOFF ;
 #else
 #define GET_DATA_POINTER(reg, name) \
 	adrp    reg, name ; \
diff --git a/configure.ac b/configure.ac
index ea7ea7ae..d9cbf5d2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -297,6 +297,11 @@ case "${host}" in
         AC_DEFINE(USE_POSIX_SPAWN_FOR_TESTS, 1,
                   [defined if we use posix_spawn in test program])
         AC_CHECK_HEADERS(spawn.h)
+
+        if test "$host_cpu" = aarch64; then
+            CCAS="\$(SHELL) \$(top_srcdir)/build-aux/darwin-aarch64-as.sh $CCAS"
+        fi
+
         ;;
 
     *-openedition*)
@@ -874,6 +879,20 @@ AC_TYPE_PID_T
 
 AC_CHECK_TYPES([byte, ushort, u16, u32, u64])
 
+
+#
+# Check whether underscores in symbols are required.  This needs to be
+# done before setting up the assembler stuff.
+#
+GNUPG_SYS_SYMBOL_UNDERSCORE()
+
+if test "$ac_cv_sys_symbol_underscore" = "yes" ; then
+  symbol_prefix=_
+else
+  symbol_prefix=
+fi
+
+
 #
 # Check for __builtin_bswap32 intrinsic.
 #
@@ -1247,7 +1266,7 @@ AC_CACHE_CHECK([whether GCC assembler is compatible for ARMv8/Aarch64 assembly i
           AC_LINK_IFELSE([AC_LANG_PROGRAM(
             [[__asm__(
                 ".text\n\t"
-                "asmfunc:\n\t"
+                "$symbol_prefix" "asmfunc:\n\t"
                 "eor x0, x0, x30, ror #12;\n\t"
                 "add x0, x0, x30, asr #12;\n\t"
                 "eor v0.16b, v0.16b, v31.16b;\n\t"
@@ -1310,13 +1329,6 @@ if test "$gcry_cv_gcc_asm_elf_directives" = "yes" ; then
 fi
 
 
-#
-# Check whether underscores in symbols are required.  This needs to be
-# done before setting up the assembler stuff.
-#
-GNUPG_SYS_SYMBOL_UNDERSCORE()
-
-
 #################################
 ####                         ####
 #### Setup assembler stuff.  ####
@@ -2200,7 +2212,7 @@ AC_CACHE_CHECK([whether GCC inline assembler supports AArch64 NEON instructions]
           [[__asm__(
                 ".cpu generic+simd\n\t"
                 ".text\n\t"
-                "testfn:\n\t"
+                "$symbol_prefix" "testfn:\n\t"
                 "mov w0, \#42;\n\t"
                 "dup v0.8b, w0;\n\t"
                 "ld4 {v0.8b,v1.8b,v2.8b,v3.8b},[x0],\#32;\n\t"
@@ -2229,7 +2241,7 @@ AC_CACHE_CHECK([whether GCC inline assembler supports AArch64 Crypto Extension i
           [[__asm__(
                 ".cpu generic+simd+crypto\n\t"
                 ".text\n\t"
-                "testfn:\n\t"
+                "$symbol_prefix" "testfn:\n\t"
                 "mov w0, \#42;\n\t"
                 "dup v0.8b, w0;\n\t"
                 "ld4 {v0.8b,v1.8b,v2.8b,v3.8b},[x0],\#32;\n\t"
@@ -2278,7 +2290,7 @@ AC_CACHE_CHECK([whether GCC inline assembler supports AArch64 SVE instructions],
           [[__asm__(
                 ".cpu generic+simd+sve\n\t"
                 ".text\n\t"
-                "testfn:\n\t"
+                "$symbol_prefix" "testfn:\n\t"
                 "mov x0, \#60;\n\t"
                 "whilelo p0.s, xzr, x0;\n\t"
                 "mov z0.s, p0/z, \#55;\n\t"
@@ -2308,7 +2320,7 @@ AC_CACHE_CHECK([whether GCC inline assembler supports AArch64 SVE2 instructions]
           [[__asm__(
                 ".cpu generic+simd+sve2\n\t"
                 ".text\n\t"
-                "testfn:\n\t"
+                "$symbol_prefix" "testfn:\n\t"
                 ";\n\t"
                 "eor3 z0.d, z0.d, z1.d, z2.d;\n\t"
                 "ext z8.b, {z20.b, z21.b}, \#3;\n\t"
@@ -2342,7 +2354,7 @@ AC_CACHE_CHECK([whether GCC inline assembler supports AArch64 SHA3/SHA512/SM3/SM
           [[__asm__(
                 ".arch armv8.2-a+sha3+sm4\n\t"
                 ".text\n\t"
-                "testfn:\n\t"
+                "$symbol_prefix" "testfn:\n\t"
 
                 /* Test for SHA512 instructions */
                 "sha512h q0, q0, v0.2d;\n\t"
diff --git a/mpi/Makefile.am b/mpi/Makefile.am
index a7268e2b..960a73ad 100644
--- a/mpi/Makefile.am
+++ b/mpi/Makefile.am
@@ -30,6 +30,7 @@ AM_ASFLAGS = $(MPI_SFLAGS)
 AM_CCASFLAGS = $(NOEXECSTACK_FLAGS)
 
 EXTRA_DIST = config.links
+CLEANFILES = *-darwin.s
 DISTCLEANFILES = mpi-asm-defs.h \
                  mpih-add1-asm.S mpih-mul1-asm.S mpih-mul2-asm.S mpih-mul3-asm.S  \
 		 mpih-lshift-asm.S mpih-rshift-asm.S mpih-sub1-asm.S asm-syntax.h \
-- 
2.53.0



More information about the Gcrypt-devel mailing list