diff --git a/CHANGES.md b/CHANGES.md
index b0ecdbe795..aa7e1f2572 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -7,6 +7,7 @@ Next Release (5.7.0)
 
 Features
 --------
+* [#1238](https://github.com/java-native-access/jna/pull/1238): Add macOS `aarch64` architecture to universal `darwin` target. Cherry pick [libffi/libffi#577](https://github.com/libffi/libffi/pull/577). - [@fkistner](https://github.com/fkistner), [@Vzor-](https://github.com/Vzor-), [@tresf](https://github.com/tresf).
 * [#1264](https://github.com/java-native-access/jna/pull/1264): Update libffi to v3.3; Add Windows `aarch64` target. - [@tresf](https://github.com/tresf).
 * [#1293](https://github.com/java-native-access/jna/issues/1293): Bind part of Windows Application Recovery and Restart API: `RegisterApplicationRestart`, `UnregisterApplicationRestart` and `GetApplicationRestartSettings` in `c.s.j.p.w.Kernel32` - [@matthiasblaesing](https://github.com/matthiasblaesing).
 * [#1217](https://github.com/java-native-access/jna/pull/1217): Add mappings for AIX `Perfstat` library to `c.s.j.p.unix.aix` - [@dbwiddis](https://github.com/dbwiddis).
diff --git a/build.xml b/build.xml
index 41bf1be99f..31b9fc9d81 100644
--- a/build.xml
+++ b/build.xml
@@ -276,8 +276,7 @@
     <condition property="os.prefix" value="win32-${jre.arch}">
       <equals arg1="${build.os.family}" arg2="windows"/>
     </condition>
-    <!-- Darwin builds are universal, no arch required -->
-    <condition property="os.prefix" value="darwin">
+    <condition property="os.prefix" value="darwin-${jre.arch}">
       <equals arg1="${build.os.family}" arg2="mac"/>
     </condition>
     <condition property="os.prefix" value="sunos-${jre.arch}">
@@ -295,6 +294,14 @@
     <condition property="os.prefix" value="kfreebsd-${jre.arch}">
       <equals arg1="${build.os.name}" arg2="GNU/kFreeBSD"/>
     </condition>
+    <!-- Darwin's resource prefix lacks arch info, use "darwin" instead -->
+    <condition property="resource.prefix" value="darwin">
+        <matches string="${os.prefix}" pattern="^darwin-"/>
+    </condition>
+    <condition property="darwin.build" value="true">
+        <matches string="${os.prefix}" pattern="^darwin-"/>
+    </condition>
+    <property name="resource.prefix" value="${os.prefix}" description="fallback"/>
     <fail unless="os.prefix" message="OS/arch not supported (${os.name}/${jre.arch}), edit build.xml and native/Makefile to add it."/>
     <!-- Keep all natives separate -->
     <property name="native.subdir" value="native-${os.prefix}"/>
@@ -316,6 +323,9 @@
     <condition property="ld.preload.name" value="LD_PRELOAD" else="IGNORE">
       <not><equals arg1="${libjsig}" arg2=""/></not>
     </condition>
+    <condition property="native.jar" value="darwin.jar">
+      <matches string="${os.prefix}" pattern="^darwin-"/>
+    </condition>
     <property name="native.jar" value="${os.prefix}.jar"/>
     <property name="build.native" location="${build}/${native.subdir}"/>
     <property name="build.headers" location="${build}/headers"/>
@@ -521,7 +531,7 @@ com/sun/jna/openbsd-x86-64/libjnidispatch.so;
 processor=x86-64;osname=openbsd,
 
 com/sun/jna/darwin/libjnidispatch.jnilib;
-osname=macosx;processor=x86;processor=x86-64;processor=ppc
+osname=macosx;processor=x86;processor=x86-64;processor=aarch64;processor=ppc
 "/>
           </manifest>
           <manifest file="@{target}" mode="update" if:true="@{module-info}">
@@ -873,6 +883,21 @@ osname=macosx;processor=x86;processor=x86-64;processor=ppc
     </condition>
     <property name="make.OS" value="IGNORE="/>
     <!-- Ensure Makefile ARCH property properly set -->
+    <condition property="ARCH" value="aarch64">
+      <matches string="${os.prefix}" pattern="-aarch64$"/>
+    </condition>
+    <condition property="ARCH" value="x86-64">
+      <matches string="${os.prefix}" pattern="-x86-64$"/>
+    </condition>
+    <condition property="ARCH" value="ppc">
+      <matches string="${os.prefix}" pattern="-ppc$"/>
+    </condition>
+    <condition property="ARCH" value="ppc64">
+      <matches string="${os.prefix}" pattern="-ppc64$"/>
+    </condition>
+    <condition property="ARCH" value="x86">
+      <matches string="${os.prefix}" pattern="-x86$"/>
+    </condition>
     <condition property="ARCH" value="arm">
       <equals arg1="${os.prefix}" arg2="w32ce-arm"/>
     </condition>
@@ -882,27 +907,12 @@ osname=macosx;processor=x86;processor=x86-64;processor=ppc
     <condition property="ARCH" value="armv7">
       <equals arg1="${os.prefix}" arg2="android-armv7"/>
     </condition>
-    <condition property="ARCH" value="aarch64">
-      <matches string="${os.prefix}" pattern="-aarch64$"/>
-    </condition>
-    <condition property="ARCH" value="x86">
-      <equals arg1="${os.prefix}" arg2="android-x86"/>
-    </condition>
-    <condition property="ARCH" value="x86-64">
-      <equals arg1="${os.prefix}" arg2="android-x86-64"/>
-    </condition>
     <condition property="ARCH" value="mips">
       <equals arg1="${os.prefix}" arg2="android-mips"/>
     </condition>
     <condition property="ARCH" value="mips64">
       <equals arg1="${os.prefix}" arg2="android-mips64"/>
     </condition>
-    <condition property="ARCH" value="ppc">
-      <equals arg1="${os.prefix}" arg2="aix-ppc"/>
-    </condition>
-    <condition property="ARCH" value="ppc64">
-      <equals arg1="${os.prefix}" arg2="aix-ppc64"/>
-    </condition>
     <!-- ensure ARCH is set properly for 64-bit capable platforms -->
     <!-- use ANT_OPTS=-d64/-d32 to build 64-bit/32-bit if not the platform default -->
     <property name="ARCH" value="${build.os.arch}"/>
@@ -918,49 +928,43 @@ osname=macosx;processor=x86;processor=x86-64;processor=ppc
     <condition property="make.SDKROOT" value="SDKROOT=${SDKROOT}">
       <isset property="SDKROOT"/>
     </condition>
-    <property name="xcode" value="/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform"/>
-    <condition property="make.SDKROOT"
-	       value="SDKROOT=${xcode}/Developer/SDKs/MacOSX10.11.sdk">
-      <and>
-        <equals arg1="${os.prefix}" arg2="darwin" trim="true"/>
-        <available file="${xcode}/Developer/SDKs/MacOSX10.11.sdk"/>
-      </and>
-    </condition>
-    <condition property="make.SDKROOT"
-	       value="SDKROOT=${xcode}/Developer/SDKs/MacOSX10.9.sdk">
-      <and>
-        <equals arg1="${os.prefix}" arg2="darwin" trim="true"/>
-        <available file="${xcode}/Developer/SDKs/MacOSX10.9.sdk"/>
-      </and>
-    </condition>
-    <condition property="make.SDKROOT"
-	       value="SDKROOT=${xcode}/Developer/SDKs/MacOSX10.8.sdk">
+    <!-- If not manually provided, detect the SDKROOT in various locations:
+         - Modern build environments ("MacOSX.sdk", no version):
+           /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk
+
+         - macOS 10.8 and older:
+           /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX(version).sdk
+
+         - Prior versions:
+           /Developer/SDKs/MacOSX(version).sdk
+    -->
+    <condition property="make.SDKROOT" value="SDKROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk">
       <and>
-        <equals arg1="${os.prefix}" arg2="darwin" trim="true"/>
-        <available file="${xcode}/Developer/SDKs/MacOSX10.8.sdk"/>
+        <matches string="${os.prefix}" pattern="^darwin-"/>
+        <available file="/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk"/>
       </and>
     </condition>
-    <condition property="make.SDKROOT"
-	       value="SDKROOT=/Developer/SDKs/MacOSX10.6.sdk">
+    <condition property="sdk-parent" value="/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs">
       <and>
-        <equals arg1="${os.prefix}" arg2="darwin" trim="true"/>
-        <available file="/Developer/SDKs/MacOSX10.6.sdk"/>
+        <matches string="${os.prefix}" pattern="^darwin-"/>
+        <available file="/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs"/>
       </and>
     </condition>
-    <condition property="make.SDKROOT"
-	       value="SDKROOT=/Developer/SDKs/MacOSX10.5.sdk">
+    <condition property="sdk-parent" value="/Developer/SDKs">
       <and>
-        <equals arg1="${os.prefix}" arg2="darwin" trim="true"/>
-        <available file="/Developer/SDKs/MacOSX10.5.sdk"/>
+        <matches string="${os.prefix}" pattern="^darwin-"/>
+        <available file="/Developer/SDKs"/>
       </and>
     </condition>
-    <condition property="make.SDKROOT"
-	       value="SDKROOT=/Developer/SDKs/MacOSX10.4u.sdk" else="IGNORE=">
-      <and>
-        <equals arg1="${os.prefix}" arg2="darwin" trim="true"/>
-        <available file="/Developer/SDKs/MacOSX10.4u.sdk"/>
-      </and>
+    <!-- Multiple SDKs is common; find the most recent (sort -V requires 10.12+) -->
+    <exec executable="sh" dir="${sdk-parent}" outputproperty="sdk-latest" if:set="darwin.build" unless:set="make.SDKROOT">
+      <arg value="-c"/>
+      <arg line="&quot;ls -d MacOSX10.*.sdk | sort -t &quot;.&quot; -k2 -n | tail -1&quot;"/>
+    </exec>
+    <condition property="make.SDKROOT" value="SDKROOT=${sdk-parent}/${sdk-latest}" else="IGNORE=">
+      <isset property="sdk-latest"/>
     </condition>
+
     <!-- Windows' drive letters and spaces in absolute paths wreak havoc on
          make -->
     <condition property="make.BUILD" value="BUILD=../${build}/${native.subdir}" else="BUILD=${build.native}">
@@ -989,7 +993,7 @@ osname=macosx;processor=x86;processor=x86-64;processor=ppc
       <isset property="EXTRA_MAKE_OPTS"/>
     </condition>
     <!-- Native resource path within jna.jar -->
-    <property name="native.path" value="com/sun/jna/${os.prefix}"/>
+    <property name="native.path" value="com/sun/jna/${resource.prefix}"/>
 
     <!-- Default make program -->
     <property name="make" value="make"/>
@@ -1055,6 +1059,68 @@ cd ..
     </zip>
   </target>
 
+  <!-- 
+    Darwin prefers fat libraries. native/Makefile outputs a binary file for
+    one architecture. The binary is joined into a preexisting library pulled
+    from lib/native/darwin.jar using lipo.
+
+    If the preexisting library does not exist, or the library is thin and
+    only supports the target arch, the output binary will be renamed and
+    used in lieu of joining a fat lib.
+  -->
+  <macrodef name="darwin-lipo">
+    <sequential>
+      <available file="${lib.native}/${native.jar}" property="lib-available"/>
+      <unzip src="${lib.native}/${native.jar}" dest="${build.native}" if:true="${lib-available}">
+        <patternset>
+          <include name="libjnidispatch.jnilib"/>
+        </patternset>
+      </unzip>
+      <!--
+        Detect the arch that was just built.
+        Note, lipo -info will not exactly match that provided by ${ARCH}, this is OK
+      -->
+      <exec executable="lipo" dir="${build.native}" failonerror="true" outputproperty="lipo-info" if:true="${lib-available}">
+        <arg value="-info"/>
+        <arg value="libjnidispatch-${ARCH}.jnilib"/>
+      </exec>
+      <regexp id="lipo-regex" pattern="\b(\w+)$"/>
+      <loadresource property="lipo-arch" if:true="${lib-available}">
+          <propertyresource name="lipo-info"/>
+          <filterchain>
+              <tokenfilter>
+                  <filetokenizer/>
+                  <replaceregex pattern=".*\s" replace=""/>
+              </tokenfilter>
+          </filterchain>
+      </loadresource>
+      <!-- Use the detected arch to remove the old binary, and add the new binary to the fat library -->
+      <exec executable="lipo" dir="${build.native}" failonerror="false" if:true="${lib-available}">
+        <arg value="-remove"/>
+        <arg value="${lipo-arch}"/>
+        <arg value="libjnidispatch.jnilib"/>
+        <arg value="-output"/>
+        <arg value="libjnidispatch.jnilib"/>
+      </exec>
+      <exec executable="lipo" dir="${build.native}" failonerror="false" if:true="${lib-available}" resultproperty="lipo-result">
+        <arg value="-create"/>
+        <arg value="libjnidispatch.jnilib"/>
+        <arg value="libjnidispatch-${ARCH}.jnilib"/>
+        <arg value="-output"/>
+        <arg value="libjnidispatch.jnilib"/>
+      </exec>
+      <condition property="replace-lib" value="true">
+        <or>
+          <not>
+            <equals arg1="0" arg2="${lipo-result}"/>
+          </not>
+          <isfalse value="${lib-available}"/>
+        </or>
+      </condition>
+      <move file="${build.native}/libjnidispatch-${ARCH}.jnilib" tofile="${build.native}/libjnidispatch.jnilib" if:true="${replace-lib}" overwrite="true"/>
+    </sequential>
+  </macrodef>
+
   <target name="native" depends="-enable-native,javah,-native-api-check,-prepare-native" unless="-native"
           description="Build native libraries.  Use 'ant -DCC=xxx' to build using a compiler other than gcc">
     <exec executable="${make}" dir="${native}" failonerror="true">
@@ -1074,6 +1140,7 @@ cd ..
       <arg value="JNA_JNI_VERSION=${jni.version}"/>
       <arg value="CHECKSUM=${jni.md5}"/>
     </exec>
+    <darwin-lipo if:set="darwin.build"/>
     <mkdir dir="${classes}/${native.path}"/>
     <copy todir="${classes}/${native.path}">
       <fileset dir="${build.native}"
@@ -1132,13 +1199,13 @@ cd ..
       <exclude name="${tests.exclude}"/>
     </javac>
     <!-- Embed testlib-jar at root and at default resource path -->
-    <mkdir dir="${test.classes}/${os.prefix}"/>
+    <mkdir dir="${test.classes}/${resource.prefix}"/>
     <copy todir="${test.classes}">
       <fileset dir="${build.native}">
         <include name="*testlib-jar*"/>
       </fileset>
     </copy>
-    <copy todir="${test.classes}/${os.prefix}">
+    <copy todir="${test.classes}/${resource.prefix}">
       <fileset dir="${build.native}">
         <include name="*testlib-jar*"/>
       </fileset>
diff --git a/lib/native/darwin.jar b/lib/native/darwin.jar
index b67789b883..31e6a36e55 100644
Binary files a/lib/native/darwin.jar and b/lib/native/darwin.jar differ
diff --git a/native/Makefile b/native/Makefile
index 48dbd6d594..05e5d26c1f 100644
--- a/native/Makefile
+++ b/native/Makefile
@@ -11,7 +11,7 @@
 #
 #   Windows (x86/amd64/aarch64)
 #   Windows CE/Mobile (arm)
-#   Darwin/OS X (i386/x86_64/ppc)
+#   Darwin/OS X (i386/x86-64/ppc/aarch64)
 #   Linux (i386/amd64/ppc/arm)
 #   Solaris (i386/amd64/sparc/sparcv9)
 #   AIX (ppc/ppc64)
@@ -392,47 +392,61 @@ endif
 
 
 ifeq ($(OS),darwin)
-XCODE_VERSION=$(shell xcodebuild -version | grep Xcode | sed 's/^Xcode \([1-9]\).*/\1/g')
-JAVA_INCLUDES+=-I/System/Library/Frameworks/JavaVM.framework/Headers
-DEFAULT_ARCH=$(shell arch)
-ARCH=$(shell arch)
-HOST_CONFIG=--host $(ARCH)-apple-darwin
-FFI_ENV += CC="$(CC)" CFLAGS="-arch $(ARCH) $(ISYSROOT) $(COPT) $(CDEBUG)" CPPFLAGS="$(CDEFINES)" LD="$(LD) -arch $(ARCH)"
-ALT_ARCHS=
-ifneq ($(ARCH),i386)
-ALT_ARCHS+=i386
+
+DARWIN_ARCH=$(ARCH)
+ifeq ($(ARCH),aarch64)
+  DARWIN_ARCH=arm64
+else 
+ifeq ($(ARCH),x86-64)
+  DARWIN_ARCH=x86_64
+else
+ifeq ($(ARCH),x86)
+  DARWIN_ARCH=x86
+else 
 endif
-ifneq ($(ARCH),x86_64)
-ALT_ARCHS+=x86_64
 endif
+endif
+
+XCODE_VERSION=$(shell xcodebuild -version | grep Xcode | sed 's/^Xcode \([1-9][0-9]*\).*/\1/g')
+MACOS_VERSION_MAJOR=$(shell sw_vers -productVersion | cut -d. -f 1)
+MACOS_VERSION_MINOR=$(shell sw_vers -productVersion | cut -d. -f 2)
+JAVA_INCLUDES+=-I/System/Library/Frameworks/JavaVM.framework/Headers
+# Actual deployment target depends on SDK support
+MACOSX_DEPLOYMENT_TARGET=10.3
+DEFAULT_ARCH=$(shell arch)
+HOST_CONFIG=--host $(DARWIN_ARCH)-apple-darwin
+FFI_ENV += CC="$(CC)" CFLAGS="-mmacosx-version-min=$(MACOSX_DEPLOYMENT_TARGET) -arch $(DARWIN_ARCH) $(ISYSROOT) $(COPT) $(CDEBUG)" CPPFLAGS="$(CDEFINES)" LD="$(LD) -arch $(DARWIN_ARCH)"
+LIBSFX=.dylib
+JNISFX=-$(ARCH).jnilib
+# JAWT no longer supported on OSX
+CDEFINES+=-DTARGET_RT_MAC_CFM=0 -DFFI_MMAP_EXEC_WRIT -DNO_JAWT
+
 ifneq ($(ARCH),ppc)
-ifeq ($(XCODE_VERSION),3)
-# Xcode 3 options
-# not supported on XCode 4+
-ALT_ARCHS+=ppc
-else
+ifneq ($(XCODE_VERSION),3)
 # Xcode 4+ options
 NO_COMPACT_UNWIND=-Wl,-no_compact_unwind
 endif
 endif
-LIBSFX=.dylib
-JNISFX=.jnilib
 ifneq ($(SDKROOT),)
 SYSLIBROOT=-Wl,-syslibroot,$(SDKROOT)
 ISYSROOT=-isysroot $(SDKROOT)
-ARCHFLAGS=-arch i386 -arch x86_64
-ifeq ($(XCODE_VERSION),3)
-ARCHFLAGS+=-arch ppc
-endif
+ARCHFLAGS+=-arch $(DARWIN_ARCH)
 endif
 
 PCFLAGS+=$(ISYSROOT) -x objective-c
-# JAWT no longer supported on OSX
-CDEFINES+=-DTARGET_RT_MAC_CFM=0 -DFFI_MMAP_EXEC_WRIT -DNO_JAWT
-LDFLAGS=$(ARCHFLAGS) -dynamiclib -o $@ -framework JavaVM \
+
+# MAJOR < 10 || (MAJOR = 10 && MINOR < 7)
+MACOS_LT_10_7 = $(shell [ ${MACOS_VERSION_MAJOR} -lt 10 -o ${MACOS_VERSION_MAJOR} -eq 10 -a ${MACOS_VERSION_MINOR} -lt 7 ] && echo true)
+
+# JavaVM.framwork is "Deprecated in OS X v10.7."
+ifeq ($(MACOS_LT_10_7),true)
+FRAMEWORK=-framework JavaVM
+endif
+
+LDFLAGS=$(ARCHFLAGS) -dynamiclib -o $@ $(FRAMEWORK) \
   -compatibility_version $(shell echo ${JNA_JNI_VERSION}|sed 's/^\([0-9][0-9]*\).*/\1/g') \
   -current_version $(JNA_JNI_VERSION) \
-  -mmacosx-version-min=10.3 \
+  -mmacosx-version-min=$(MACOSX_DEPLOYMENT_TARGET) \
   -framework Foundation \
   $(NO_COMPACT_UNWIND) \
   -install_name ${@F} \
@@ -447,11 +461,7 @@ endif
 $(BUILD)/%.o : %.c dispatch.h protect.h $(FFI_LIB)
 	@mkdir -p $(BUILD)
 ifneq ($(SDKROOT),)
-	$(CC) $(LOC_CC_OPTS) -arch $(ARCH) $(CFLAGS) -c $< -o $@.$(ARCH)
-	for arch in $(ALT_ARCHS); do \
-	  $(CC) $(LOC_CC_OPTS) -arch $$arch -I$(BUILD)/libffi.$$arch/include $(CFLAGS) -c $< -o $@.$$arch; \
-	done
-	lipo -create -output $@ $@.*
+	$(CC) $(LOC_CC_OPTS) -mmacosx-version-min=$(MACOSX_DEPLOYMENT_TARGET) -arch $(DARWIN_ARCH) $(CFLAGS) -c $< -o $@
 else
 	$(CC) $(CFLAGS) $(LOC_CC_OPTS) -c $< $(COUT)
 endif
@@ -507,25 +517,6 @@ $(FFI_LIB):
 	    && $(FFI_ENV) $(FFI_SRC)/configure $(FFI_CONFIG) $(HOST_CONFIG)); \
 	fi
 	$(MAKE) -C $(FFI_BUILD)
-ifneq ($(SDKROOT),)
-	@for arch in $(ALT_ARCHS); do \
-	  mkdir -p $(BUILD)/libffi.$$arch; \
-	  if [ ! -f $(BUILD)/libffi.$$arch/Makefile ]; then \
-	    echo "Configuring libffi ($$arch)"; \
-	    (cd $(BUILD)/libffi.$$arch \
-	     && CC="$(CC)" CFLAGS="-arch $$arch $(ISYSROOT) $(COPT) $(CDEBUG)" CPPFLAGS="$(CDEFINES)" \
-                LDFLAGS="-arch $$arch" \
-               $(FFI_SRC)/configure $(FFI_CONFIG) --host=$$arch-apple-darwin --disable-dependency-tracking); \
-	  fi; \
-	  $(MAKE) -C $(BUILD)/libffi.$$arch; \
-	done
-ifneq ($(ALT_ARCHS),)
-	/usr/bin/libtool -static -o $@.tmp $(FFI_BUILD)/.libs/${@F} $(BUILD)/libffi.*/.libs/${@F}
-else
-	/usr/bin/libtool -static -o $@.tmp $(FFI_BUILD)/.libs/${@F}
-endif
-	mv $@.tmp $@
-endif
 endif
 
 clean:
diff --git a/native/build.xml b/native/build.xml
index 1d17b6d84e..27250a9d8e 100644
--- a/native/build.xml
+++ b/native/build.xml
@@ -15,8 +15,7 @@
     <condition property="os.prefix" value="win32-${jre.arch}">
         <os family="windows"/>
     </condition>
-    <!-- Darwin builds are universal, no arch required -->
-    <condition property="os.prefix" value="darwin">
+    <condition property="os.prefix" value="darwin-${jre.arch}">
         <os family="mac"/>
     </condition>
     <condition property="os.prefix" value="sunos-${jre.arch}">
@@ -38,6 +37,9 @@
           message="OS/arch not supported (${os.name}/${jre.arch}), edit build.xml and native/Makefile to add it."/>
     <!-- Keep all natives separate -->
     <property name="native.subdir" value="native-${os.prefix}"/>
+    <condition property="darwin.build" value="true">
+        <matches string="${os.prefix}" pattern="^darwin-"/>
+    </condition>
 
     <!-- ################# figure out the compatibility version ################## -->
     <!-- Set up restrictions for w32ce, based on JavaME/CDC -->
@@ -238,11 +240,17 @@
         <condition property="ARCH" value="aarch64">
             <matches string="${os.prefix}" pattern="-aarch64$"/>
         </condition>
-        <condition property="ARCH" value="x86">
-            <equals arg1="${os.prefix}" arg2="android-x86"/>
-        </condition>
         <condition property="ARCH" value="x86-64">
-            <equals arg1="${os.prefix}" arg2="android-x86-64"/>
+            <matches string="${os.prefix}" pattern="-x86-64$"/>
+        </condition>
+        <condition property="ARCH" value="ppc">
+            <matches string="${os.prefix}" pattern="-ppc$"/>
+        </condition>
+        <condition property="ARCH" value="ppc64">
+            <matches string="${os.prefix}" pattern="-ppc64$"/>
+        </condition>
+        <condition property="ARCH" value="x86">
+            <matches string="${os.prefix}" pattern="-x86$"/>
         </condition>
         <condition property="ARCH" value="mips">
             <equals arg1="${os.prefix}" arg2="android-mips"/>
@@ -250,12 +258,6 @@
         <condition property="ARCH" value="mips64">
             <equals arg1="${os.prefix}" arg2="android-mips64"/>
         </condition>
-        <condition property="ARCH" value="ppc">
-            <equals arg1="${os.prefix}" arg2="aix-ppc"/>
-        </condition>
-        <condition property="ARCH" value="ppc64">
-            <equals arg1="${os.prefix}" arg2="aix-ppc64"/>
-        </condition>
         <!-- ensure ARCH is set properly for 64-bit capable platforms -->
         <!-- use ANT_OPTS=-d64/-d32 to build 64-bit/32-bit if not the platform default -->
         <property name="ARCH" value="${os.arch}"/>
@@ -279,44 +281,42 @@
         <condition property="make.SDKROOT" value="SDKROOT=${SDKROOT}">
             <isset property="SDKROOT"/>
         </condition>
-        <property name="xcode" value="/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform"/>
-        <condition property="make.SDKROOT" value="SDKROOT=${xcode}/Developer/SDKs/MacOSX10.11.sdk">
-            <and>
-                <equals arg1="${os.prefix}" arg2="darwin" trim="true"/>
-                <available file="${xcode}/Developer/SDKs/MacOSX10.11.sdk"/>
-            </and>
-        </condition>
-        <condition property="make.SDKROOT" value="SDKROOT=${xcode}/Developer/SDKs/MacOSX10.9.sdk">
-            <and>
-                <equals arg1="${os.prefix}" arg2="darwin" trim="true"/>
-                <available file="${xcode}/Developer/SDKs/MacOSX10.9.sdk"/>
-            </and>
-        </condition>
-        <condition property="make.SDKROOT" value="SDKROOT=${xcode}/Developer/SDKs/MacOSX10.8.sdk">
+        <!-- If not manually provided, detect the SDKROOT in various locations:
+            - Modern build environments ("MacOSX.sdk", no version):
+            /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk
+
+            - macOS 10.8 and older:
+            /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX(version).sdk
+
+            - Prior versions:
+            /Developer/SDKs/MacOSX(version).sdk
+        -->
+        <condition property="make.SDKROOT" value="SDKROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk">
             <and>
-                <equals arg1="${os.prefix}" arg2="darwin" trim="true"/>
-                <available file="${xcode}/Developer/SDKs/MacOSX10.8.sdk"/>
+                <matches string="${os.prefix}" pattern="^darwin-"/>
+                <available file="/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk"/>
             </and>
         </condition>
-        <condition property="make.SDKROOT" value="SDKROOT=/Developer/SDKs/MacOSX10.6.sdk">
+        <condition property="sdk-parent" value="/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs">
             <and>
-                <equals arg1="${os.prefix}" arg2="darwin" trim="true"/>
-                <available file="/Developer/SDKs/MacOSX10.6.sdk"/>
+                <matches string="${os.prefix}" pattern="^darwin-"/>
+                <available file="/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs"/>
             </and>
         </condition>
-        <condition property="make.SDKROOT" value="SDKROOT=/Developer/SDKs/MacOSX10.5.sdk">
+        <condition property="sdk-parent" value="/Developer/SDKs">
             <and>
-                <equals arg1="${os.prefix}" arg2="darwin" trim="true"/>
-                <available file="/Developer/SDKs/MacOSX10.5.sdk"/>
+                <matches string="${os.prefix}" pattern="^darwin-"/>
+                <available file="/Developer/SDKs"/>
             </and>
         </condition>
-        <condition property="make.SDKROOT" value="SDKROOT=/Developer/SDKs/MacOSX10.4u.sdk" else="IGNORE=">
-            <and>
-                <equals arg1="${os.prefix}" arg2="darwin" trim="true"/>
-                <available file="/Developer/SDKs/MacOSX10.4u.sdk"/>
-            </and>
+        <!-- Multiple SDKs is common; find the most recent (sort -V requires 10.12+) -->
+        <exec executable="sh" dir="${sdk-parent}" outputproperty="sdk-latest" if:set="darwin.build" unless:set="make.SDKROOT">
+            <arg value="-c"/>
+            <arg line="&quot;ls -d MacOSX10.*.sdk | sort -t &quot;.&quot; -k2 -n | tail -1&quot;"/>
+        </exec>
+        <condition property="make.SDKROOT" value="SDKROOT=${sdk-parent}/${sdk-latest}" else="IGNORE=">
+            <isset property="sdk-latest"/>
         </condition>
-        <echo level="info" message="make.SDKROOT: ${make.SDKROOT}"/>
 
         <!-- Windows drive letters, separator and spaces in absolute paths wreak havoc on make -->
         <condition property="make.BUILD"
diff --git a/native/libffi/src/aarch64/ffi.c b/native/libffi/src/aarch64/ffi.c
index 99da36cde3..44b1ecdd97 100644
--- a/native/libffi/src/aarch64/ffi.c
+++ b/native/libffi/src/aarch64/ffi.c
@@ -660,12 +660,13 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *orig_rvalue,
 		state.ngrn = N_X_ARG_REG;
 		/* Note that the default abi extends each argument
 		   to a full 64-bit slot, while the iOS abi allocates
-		   only enough space. */
+		   only enough space, except for variadic arguments. */
 #ifdef __APPLE__
-		memcpy(d, a, s);
-#else
-		*(ffi_arg *)d = ext;
+		if (!state.allocating_variadic)
+		  memcpy(d, a, s);
+		else
 #endif
+		  *(ffi_arg *)d = ext;
 	      }
 	  }
 	  break;
diff --git a/test/com/sun/jna/LibraryLoadTest.java b/test/com/sun/jna/LibraryLoadTest.java
index d29007f91a..aa07a673a4 100644
--- a/test/com/sun/jna/LibraryLoadTest.java
+++ b/test/com/sun/jna/LibraryLoadTest.java
@@ -203,13 +203,12 @@ public void testLoadLibraryWithLongName() throws Exception {
     public void testLoadFrameworkLibrary() {
         if (Platform.isMac()) {
             final String PATH = "/System/Library/Frameworks/CoreServices.framework";
-            assertTrue("CoreServices not present on this setup, expected at " + PATH, new File(PATH).exists());
             try {
                 NativeLibrary lib = NativeLibrary.getInstance("CoreServices");
                 assertNotNull("CoreServices not found", lib);
             }
             catch(UnsatisfiedLinkError e) {
-                fail("Should search /System/Library/Frameworks");
+                failCoreServices("Should search /System/Library/Frameworks: ", e, PATH);
             }
         }
     }
@@ -218,13 +217,12 @@ public void testLoadFrameworkLibraryAbsolute() {
         if (Platform.isMac()) {
             final String PATH = "/System/Library/Frameworks/CoreServices";
             final String FRAMEWORK = PATH + ".framework";
-            assertTrue("CoreServices not present on this setup, expected at " + FRAMEWORK, new File(FRAMEWORK).exists());
             try {
                 NativeLibrary lib = NativeLibrary.getInstance(PATH);
                 assertNotNull("CoreServices not found", lib);
             }
             catch(UnsatisfiedLinkError e) {
-                fail("Should try FRAMEWORK.framework/FRAMEWORK if the absolute framework (truncated) path given exists: " + e);
+                failCoreServices("Should try FRAMEWORK.framework/FRAMEWORK if the absolute framework (truncated) path given exists: ", e, FRAMEWORK);
             }
         }
     }
@@ -232,17 +230,23 @@ public void testLoadFrameworkLibraryAbsolute() {
     public void testLoadFrameworkLibraryAbsoluteFull() {
         if (Platform.isMac()) {
             final String PATH = "/System/Library/Frameworks/CoreServices.framework/CoreServices";
-            assertTrue("CoreServices not present on this setup, expected at " + PATH, new File(PATH).exists());
             try {
                 NativeLibrary lib = NativeLibrary.getInstance(PATH);
                 assertNotNull("CoreServices not found", lib);
             }
             catch(UnsatisfiedLinkError e) {
-                fail("Should try FRAMEWORK verbatim if the absolute path given exists: " + e);
+                failCoreServices("Should try FRAMEWORK verbatim if the absolute path given exists: ", e, PATH);
             }
         }
     }
 
+    private void failCoreServices(String message, UnsatisfiedLinkError e, String expectedPath) {
+        if (!new File(expectedPath).exists()) {
+            message = "CoreServices not present on this setup, expected at " + expectedPath + "\n" + message;
+        }
+        fail(message + e);
+    }
+
     public void testHandleObjectMethods() {
         CLibrary lib = (CLibrary)load();
         String method = "toString";
diff --git a/test/com/sun/jna/PlatformTest.java b/test/com/sun/jna/PlatformTest.java
index 21eea41c8d..b82679aa38 100644
--- a/test/com/sun/jna/PlatformTest.java
+++ b/test/com/sun/jna/PlatformTest.java
@@ -47,6 +47,9 @@ public void testOSPrefix() {
         assertEquals("Wrong resource path Mac/x86_64", "darwin",
                      Platform.getNativeLibraryResourcePrefix(Platform.MAC,
                                                              "x86_64", "Mac"));
+        assertEquals("Wrong resource path Mac/aarch64", "darwin",
+                    Platform.getNativeLibraryResourcePrefix(Platform.MAC,
+                                                             "aarch64", "Mac"));
         assertEquals("Wrong resource path Solaris/sparc", "sunos-sparc",
                      Platform.getNativeLibraryResourcePrefix(Platform.SOLARIS,
                                                              "sparc", "Solaris"));
diff --git a/test/com/sun/jna/VarArgsTest.java b/test/com/sun/jna/VarArgsTest.java
index 9710f43795..f93b8030d7 100644
--- a/test/com/sun/jna/VarArgsTest.java
+++ b/test/com/sun/jna/VarArgsTest.java
@@ -42,8 +42,8 @@ protected List<String> getFieldOrder() {
         }
         public int addVarArgs(String fmt, Number... args);
         public String returnStringVarArgs(String fmt, Object... args);
-        public void modifyStructureVarArgs(String fmt, Object arg1, Object... args);
-        public String returnStringVarArgs2(String... args);
+        public void modifyStructureVarArgs(String fmt, Object... args);
+        public String returnStringVarArgs2(String fmt, String... args);
     }
     TestLibrary lib;
     @Override
diff --git a/www/MacDevelopmentEnvironment.md b/www/MacDevelopmentEnvironment.md
index 715ba61207..4ca8d37996 100644
--- a/www/MacDevelopmentEnvironment.md
+++ b/www/MacDevelopmentEnvironment.md
@@ -1,6 +1,54 @@
 Mac Development Environment
 ===========================
 
+### Prequisites
+* [Xcode](https://developer.apple.com/download/) with Command Line tools
+* The following tools: `ant autoconf automake libtool gettext`
+   * These are available via [Homebrew](https://brew.sh)
+      ```bash
+      brew install ant autoconf automake libtool gettext
+      ```
+
+   * ... or alternately via [MacPorts](https://www.macports.org/)
+
+### Compiling
+
+1. To compile and run unit tests for the current archecture:
+   ```bash
+   ant
+   ```
+
+2. To compile native components only and skip unit tests:
+   ```bash
+   ant native
+   ```
+
+3. To provide an alternate (older) macOS SDK:
+   ```bash
+   ant -DSDKROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk
+   ```
+
+4. To cross-compile for an alternate architecture:
+   ```bash
+   # ARM64 (>= 11.0)
+   ant -Dos.prefix=darwin-aarch64
+
+   # x86 (<= 10.13)
+   ant -Dos.prefix=darwin-x86
+
+   # x86_64
+   ant -Dos.prefix=darwin-x86-64
+
+   # PPC (<= 10.5)
+   ant -Dos.prefix=darwin-ppc
+
+   # PPC64
+   ant -Dos.prefix=darwin-ppc64
+   ```
+
+### Troubleshooting
+
+
 * Xcode - If you only have the Xcode command line tools installed, and not the full Xcode UI, you may see build errors like this:
 
         native:
