  def find_file(filename, std_dirs, paths):
      """Searches for the directory where a given file is located,
      and returns a possibly-empty list of additional directories, or None
-@@ -2118,7 +2125,7 @@ class PyBuildExt(build_ext):
+@@ -2101,43 +2108,17 @@ class PyBuildExt(build_ext):
+                            library_dirs=added_lib_dirs))
+         return True
+ 
+-    def configure_ctypes_darwin(self, ext):
+-        # Darwin (OS X) uses preconfigured files, in
+-        # the Modules/_ctypes/libffi_osx directory.
+-        ffi_srcdir = os.path.abspath(os.path.join(self.srcdir, 'Modules',
+-                                                  '_ctypes', 'libffi_osx'))
+-        sources = [os.path.join(ffi_srcdir, p)
+-                   for p in ['ffi.c',
+-                             'x86/darwin64.S',
+-                             'x86/x86-darwin.S',
+-                             'x86/x86-ffi_darwin.c',
+-                             'x86/x86-ffi64.c',
+-                             'powerpc/ppc-darwin.S',
+-                             'powerpc/ppc-darwin_closure.S',
+-                             'powerpc/ppc-ffi_darwin.c',
+-                             'powerpc/ppc64-darwin_closure.S',
+-                             ]]
+-
+-        # Add .S (preprocessed assembly) to C compiler source extensions.
+-        self.compiler.src_extensions.append('.S')
+-
+-        include_dirs = [os.path.join(ffi_srcdir, 'include'),
+-                        os.path.join(ffi_srcdir, 'powerpc')]
+-        ext.include_dirs.extend(include_dirs)
+-        ext.sources.extend(sources)
+-        return True
+-
+     def configure_ctypes(self, ext):
+-        if not self.use_system_libffi:
+-            if MACOS:
+-                return self.configure_ctypes_darwin(ext)
+-            print('INFO: Could not locate ffi libs and/or headers')
+-            return False
+         return True
+ 
+     def detect_ctypes(self):
+         # Thomas Heller's _ctypes module
+-        self.use_system_libffi = False
++
++        if (not sysconfig.get_config_var("LIBFFI_INCLUDEDIR") and MACOS):
++            self.use_system_libffi = True
++        else:
++            self.use_system_libffi = '--with-system-ffi' in sysconfig.get_config_var("CONFIG_ARGS")
++
+         include_dirs = []
+         extra_compile_args = ['-DPy_BUILD_CORE_MODULE']
+         extra_link_args = []
+@@ -2150,11 +2131,9 @@ class PyBuildExt(build_ext):
+ 
+         if MACOS:
+             sources.append('_ctypes/malloc_closure.c')
+-            sources.append('_ctypes/darwin/dlfcn_simple.c')
++            extra_compile_args.append('-DUSING_MALLOC_CLOSURE_DOT_C=1')
+             extra_compile_args.append('-DMACOSX')
+             include_dirs.append('_ctypes/darwin')
+-            # XXX Is this still needed?
+-            # extra_link_args.extend(['-read_only_relocs', 'warning'])
+ 
+         elif HOST_PLATFORM == 'sunos5':
+             # XXX This shouldn't be necessary; it appears that some
+@@ -2184,31 +2163,48 @@ class PyBuildExt(build_ext):
                                 sources=['_ctypes/_ctypes_test.c'],
                                 libraries=['m']))
  
++        ffi_inc = sysconfig.get_config_var("LIBFFI_INCLUDEDIR")
++        ffi_lib = None
++
+         ffi_inc_dirs = self.inc_dirs.copy()
+         if MACOS:
+-            if '--with-system-ffi' not in sysconfig.get_config_var("CONFIG_ARGS"):
+-                return
+-            # OS X 10.5 comes with libffi.dylib; the include files are
+-            # in /usr/include/ffi
+-            ffi_inc_dirs.append('/usr/include/ffi')
+-
 -        ffi_inc = [sysconfig.get_config_var("LIBFFI_INCLUDEDIR")]
-+        ffi_inc = sysconfig.get_config_var("LIBFFI_INCLUDEDIR")
-         ffi_lib = None
- 
-         ffi_inc_dirs = self.inc_dirs.copy()
-@@ -2127,29 +2134,38 @@ class PyBuildExt(build_ext):
-                 return
-             ffi_in_sdk = os.path.join(macosx_sdk_root(), "usr/include/ffi")
-             if os.path.exists(ffi_in_sdk):
--                ffi_inc = [ffi_in_sdk]
-+                ffi_inc = ffi_in_sdk
-                 ffi_lib = 'ffi'
--                sources.remove('_ctypes/malloc_closure.c')
-             else:
-                 # OS X 10.5 comes with libffi.dylib; the include files are
-                 # in /usr/include/ffi
-                 ffi_inc_dirs.append('/usr/include/ffi')
- 
 -        if not ffi_inc or ffi_inc[0] == '':
 -            ffi_inc = find_file('ffi.h', [], ffi_inc_dirs)
 -        if ffi_inc is not None:
 -            ffi_h = ffi_inc[0] + '/ffi.h'
++            ffi_in_sdk = os.path.join(macosx_sdk_root(), "usr/include/ffi")
++
++            if not ffi_inc:
++                if os.path.exists(ffi_in_sdk):
++                    ext.extra_compile_args.append("-DUSING_APPLE_OS_LIBFFI=1")
++                    ffi_inc = ffi_in_sdk
++                    ffi_lib = 'ffi'
++                else:
++                    # OS X 10.5 comes with libffi.dylib; the include files are
++                    # in /usr/include/ffi
++                    ffi_inc_dirs.append('/usr/include/ffi')
++
 +        if not ffi_inc:
 +            found = find_file('ffi.h', [], ffi_inc_dirs)
 +            if found:

         if ffi_inc and ffi_lib:
-            ext.include_dirs.extend(ffi_inc)
+            ffi_headers = glob(os.path.join(ffi_inc, '*.h'))
+            if grep_headers_for('ffi_closure_alloc', ffi_headers):
+                try:
+                    sources.remove('_ctypes/malloc_closure.c')
+                except ValueError:
+                    pass
+            if grep_headers_for('ffi_prep_cif_var', ffi_headers):
+                ext.extra_compile_args.append("-DHAVE_FFI_PREP_CIF_VAR=1")
+            ext.include_dirs.append(ffi_inc)
             ext.libraries.append(ffi_lib)
             self.use_system_libffi = True
 
-- 
2.21.1 (Apple Git-122.3)


From 6717b8cb761ad60d243247c22d2136d1bb6cf6ed Mon Sep 17 00:00:00 2001
From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com>
Date: Wed, 1 Jul 2020 01:30:05 +0000
Subject: [PATCH 6/9] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?=
 =?UTF-8?q?rb=5Fit.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Comment: Patches 1/9 and 3/9 have been slightly modified in order to
Comment: backport this patchset to Python 3.8.3.

---
 .../Core and Builtins/2020-07-01-01-30-04.bpo-41100.hCrjJJ.rst   | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-07-01-01-30-04.bpo-41100.hCrjJJ.rst

diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-07-01-01-30-04.bpo-41100.hCrjJJ.rst b/Misc/NEWS.d/next/Core and Builtins/2020-07-01-01-30-04.bpo-41100.hCrjJJ.rst
new file mode 100644
index 0000000..769eb89
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2020-07-01-01-30-04.bpo-41100.hCrjJJ.rst	
@@ -0,0 +1 @@
+setup.py: probe libffi for ffi_closure_alloc and ffi_prep_cif_var
\ No newline at end of file
-- 
2.21.1 (Apple Git-122.3)


From 25b80eaea24be19a201e02629844b486b20d4acb Mon Sep 17 00:00:00 2001
From: Lawrence D'Anna <64555057+lawrence-danna-apple@users.noreply.github.com>
Date: Mon, 13 Jul 2020 16:21:28 -0700
Subject: [PATCH 7/9] fix spelling in Doc/library/ctypes.rst
Comment: Patches 1/9 and 3/9 have been slightly modified in order to
Comment: backport this patchset to Python 3.8.3.

Co-authored-by: Arch Oversight <archoversight@gmail.com>
---
 Doc/library/ctypes.rst | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst
index caed17a..8a82dd5 100644
--- a/Doc/library/ctypes.rst
+++ b/Doc/library/ctypes.rst
@@ -1581,7 +1581,7 @@ They are instances of a private class:
 
    .. attribute:: variadic
 
-      Assign a boolean to specify that the function takes a variable nubmer of
+      Assign a boolean to specify that the function takes a variable number of
       arguments.   This does not matter on most platforms, but for Apple arm64
       platforms variadic functions have a different calling convention than
       normal functions.
@@ -2552,4 +2552,3 @@ Arrays and pointers
 
         Returns the object to which to pointer points.  Assigning to this
         attribute changes the pointer to point to the assigned object.
-
-- 
2.21.1 (Apple Git-122.3)


From 31a6fc56a69b85423971247c95f003387924e3d9 Mon Sep 17 00:00:00 2001
From: Lawrence D'Anna <lawrence_danna@apple.com>
Date: Mon, 29 Jun 2020 14:03:15 -0700
Subject: [PATCH 8/9] allow python to build for macosx-11.0-arm64
Comment: Patches 1/9 and 3/9 have been slightly modified in order to
Comment: backport this patchset to Python 3.8.3.

---
 configure    | 3 +++
 configure.ac | 3 +++
 2 files changed, 6 insertions(+)

diff --git a/configure b/configure
index 96dcd0d..b009927 100755
--- a/configure
+++ b/configure
@@ -9264,6 +9264,9 @@ fi
     	ppc)
     		MACOSX_DEFAULT_ARCH="ppc64"
     		;;
+      arm64)
+    		MACOSX_DEFAULT_ARCH="arm64"
+    		;;
     	*)
     		as_fn_error $? "Unexpected output of 'arch' on OSX" "$LINENO" 5
     		;;
diff --git a/configure.ac b/configure.ac
index 18a0446..3083e1e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2442,6 +2442,9 @@ case $ac_sys_system/$ac_sys_release in
     	ppc)
     		MACOSX_DEFAULT_ARCH="ppc64"
     		;;
+      arm64)
+    		MACOSX_DEFAULT_ARCH="arm64"
+    		;;
     	*)
     		AC_MSG_ERROR([Unexpected output of 'arch' on OSX])
     		;;
-- 
2.21.1 (Apple Git-122.3)


From 0f4840d3003c82a8a67b6f0c4f71ccbdbfa6d1c6 Mon Sep 17 00:00:00 2001
From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com>
Date: Tue, 30 Jun 2020 00:02:43 +0000
Subject: [PATCH 9/9] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?=
 =?UTF-8?q?rb=5Fit.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Comment: Patches 1/9 and 3/9 have been slightly modified in order to
Comment: backport this patchset to Python 3.8.3.

---
 .../Core and Builtins/2020-06-30-00-02-42.bpo-41164.zbzWsP.rst   | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-06-30-00-02-42.bpo-41164.zbzWsP.rst

diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-06-30-00-02-42.bpo-41164.zbzWsP.rst b/Misc/NEWS.d/next/Core and Builtins/2020-06-30-00-02-42.bpo-41164.zbzWsP.rst
new file mode 100644
index 0000000..c431766
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2020-06-30-00-02-42.bpo-41164.zbzWsP.rst	
@@ -0,0 +1 @@
+Allow python to build for macosx-11.0-arm64
\ No newline at end of file
-- 
2.21.1 (Apple Git-122.3)


diff -pur a/Lib/_osx_support.py b/Lib/_osx_support.py
--- a/Lib/_osx_support.py	2020-10-05 17:07:58.000000000 +0200
+++ b/Lib/_osx_support.py	2020-11-05 14:28:53.000000000 +0100
@@ -110,6 +110,26 @@ def _get_system_version():
 
     return _SYSTEM_VERSION
 
+_SYSTEM_VERSION_TUPLE = None
+def _get_system_version_tuple():
+    """
+    Return the macOS system version as a tuple
+
+    The return value is safe to use to compare
+    two version numbers.
+    """
+    global _SYSTEM_VERSION_TUPLE
+    if _SYSTEM_VERSION_TUPLE is None:
+        osx_version = _get_system_version()
+        if osx_version:
+            try:
+                _SYSTEM_VERSION_TUPLE = tuple(int(i) for i in osx_version.split('.'))
+            except ValueError:
+                _SYSTEM_VERSION_TUPLE = ()
+
+    return _SYSTEM_VERSION_TUPLE
+   
+
 def _remove_original_values(_config_vars):
     """Remove original unmodified values for testing"""
     # This is needed for higher-level cross-platform tests of get_platform.
@@ -132,14 +152,18 @@ def _supports_universal_builds():
     # builds, in particular -isysroot and -arch arguments to the compiler. This
     # is in support of allowing 10.4 universal builds to run on 10.3.x systems.
 
-    osx_version = _get_system_version()
-    if osx_version:
-        try:
-            osx_version = tuple(int(i) for i in osx_version.split('.'))
-        except ValueError:
-            osx_version = ''
+    osx_version = _get_system_version_tuple()
     return bool(osx_version >= (10, 4)) if osx_version else False
 
+def _supports_arm64_builds():
+    """Returns True if arm64 builds are supported on this system"""
+    # There are two sets of systems supporting macOS/arm64 builds:
+    # 1. macOS 11 and later, unconditionally
+    # 2. macOS 10.15 with Xcode 12.2 or later
+    # For now the second category is ignored.
+    osx_version = _get_system_version_tuple()
+    return osx_version >= (11, 0) if osx_version else False
+
 
 def _find_appropriate_compiler(_config_vars):
     """Find appropriate C compiler for extension module builds"""
@@ -331,6 +355,12 @@ def compiler_fixup(compiler_so, cc_args)
             except ValueError:
                 break
 
+    elif not _supports_arm64_builds():
+        # Look for "-arch arm64" and drop that
+        for idx in range(len(compiler_so)):
+            if compiler_so[idx] == '-arch' and compiler_so[idx+1] == "arm64":
+                del compiler_so[idx:idx+2]
+
     if 'ARCHFLAGS' in os.environ and not stripArch:
         # User specified different -arch flags in the environ,
         # see also distutils.sysconfig
@@ -481,6 +511,8 @@ def get_platform_osx(_config_vars, osnam
 
             if len(archs) == 1:
                 machine = archs[0]
+            elif archs == ('arm64', 'x86_64'):
+                machine = 'universal2'
             elif archs == ('i386', 'ppc'):
                 machine = 'fat'
             elif archs == ('i386', 'x86_64'):
diff -pur a/Lib/ctypes/macholib/dyld.py b/Lib/ctypes/macholib/dyld.py
--- a/Lib/ctypes/macholib/dyld.py	2020-10-05 17:07:58.000000000 +0200
+++ b/Lib/ctypes/macholib/dyld.py	2020-11-05 14:28:53.000000000 +0100
@@ -6,6 +6,11 @@ import os
 from ctypes.macholib.framework import framework_info
 from ctypes.macholib.dylib import dylib_info
 from itertools import *
+try:
+    from _ctypes import _dyld_shared_cache_contains_path
+except ImportError:
+    def _dyld_shared_cache_contains_path(*args):
+        raise NotImplementedError
 
 __all__ = [
     'dyld_find', 'framework_find',
@@ -122,8 +127,15 @@ def dyld_find(name, executable_path=None
                 dyld_executable_path_search(name, executable_path),
                 dyld_default_search(name, env),
             ), env):
+
         if os.path.isfile(path):
             return path
+        try:
+            if _dyld_shared_cache_contains_path(path):
+                return path
+        except NotImplementedError:
+            pass
+
     raise ValueError("dylib %s could not be found" % (name,))
 
 def framework_find(fn, executable_path=None, env=None):
diff -pur a/Lib/ctypes/test/test_macholib.py b/Lib/ctypes/test/test_macholib.py
--- a/Lib/ctypes/test/test_macholib.py	2020-10-05 17:07:58.000000000 +0200
+++ b/Lib/ctypes/test/test_macholib.py	2020-11-05 14:28:53.000000000 +0100
@@ -45,19 +45,22 @@ def find_lib(name):
 class MachOTest(unittest.TestCase):
     @unittest.skipUnless(sys.platform == "darwin", 'OSX-specific test')
     def test_find(self):
-
-        self.assertEqual(find_lib('pthread'),
-                             '/usr/lib/libSystem.B.dylib')
+        # On Mac OS 11, system dylibs are only present in the shared cache,
+        # so symlinks like libpthread.dylib -> libSystem.B.dylib will not
+        # be resolved by dyld_find
+        self.assertIn(find_lib('pthread'),
+                              ('/usr/lib/libSystem.B.dylib', '/usr/lib/libpthread.dylib'))
 
         result = find_lib('z')
         # Issue #21093: dyld default search path includes $HOME/lib and
         # /usr/local/lib before /usr/lib, which caused test failures if
         # a local copy of libz exists in one of them. Now ignore the head
         # of the path.
-        self.assertRegex(result, r".*/lib/libz\..*.*\.dylib")
+        self.assertRegex(result, r".*/lib/libz.*\.dylib")
 
-        self.assertEqual(find_lib('IOKit'),
-                             '/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit')
+        self.assertIn(find_lib('IOKit'),
+                              ('/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit',
+                              '/System/Library/Frameworks/IOKit.framework/IOKit'))
 
 if __name__ == "__main__":
     unittest.main()
diff -pur a/Lib/distutils/tests/test_build_ext.py b/Lib/distutils/tests/test_build_ext.py
--- a/Lib/distutils/tests/test_build_ext.py	2020-10-05 17:07:58.000000000 +0200
+++ b/Lib/distutils/tests/test_build_ext.py	2020-11-05 14:28:53.000000000 +0100
@@ -492,7 +492,7 @@ class BuildExtTestCase(TempdirManager,
         # format the target value as defined in the Apple
         # Availability Macros.  We can't use the macro names since
         # at least one value we test with will not exist yet.
-        if target[1] < 10:
+        if target[:2] < (10, 10):
             # for 10.1 through 10.9.x -> "10n0"
             target = '%02d%01d0' % target
         else:
diff -pur a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py
--- a/Lib/test/test_bytes.py	2020-10-05 17:07:58.000000000 +0200
+++ b/Lib/test/test_bytes.py	2020-11-05 14:28:53.000000000 +0100
@@ -1034,6 +1034,7 @@ class BytesTest(BaseBytesTest, unittest.
             c_char_p)
 
         PyBytes_FromFormat = pythonapi.PyBytes_FromFormat
+        PyBytes_FromFormat.argtypes = (c_char_p,)
         PyBytes_FromFormat.restype = py_object
 
         # basic tests
diff -pur a/Lib/test/test_platform.py b/Lib/test/test_platform.py
--- a/Lib/test/test_platform.py	2020-10-05 17:07:58.000000000 +0200
+++ b/Lib/test/test_platform.py	2020-11-05 14:28:53.000000000 +0100
@@ -245,7 +245,7 @@ class PlatformTest(unittest.TestCase):
             self.assertEqual(res[1], ('', '', ''))
 
             if sys.byteorder == 'little':
-                self.assertIn(res[2], ('i386', 'x86_64'))
+                self.assertIn(res[2], ('i386', 'x86_64', 'arm64'))
             else:
                 self.assertEqual(res[2], 'PowerPC')
 
diff -pur a/Lib/test/test_posix.py b/Lib/test/test_posix.py
--- a/Lib/test/test_posix.py	2020-10-05 17:07:58.000000000 +0200
+++ b/Lib/test/test_posix.py	2020-11-05 14:28:53.000000000 +0100
@@ -1905,6 +1905,233 @@ class TestPosixSpawnP(unittest.TestCase,
         assert_python_ok(*args, PATH=path)
 
 
+@unittest.skipUnless(sys.platform == "darwin", "test weak linking on macOS")
+class TestPosixWeaklinking(unittest.TestCase):
+    # These test cases verify that weak linking support on macOS works
+    # as expected. These cases only test new behaviour introduced by weak linking,
+    # regular behaviour is tested by the normal test cases. 
+    #
+    # See the section on Weak Linking in Mac/README.txt for more information.
+    def setUp(self):
+        import sysconfig
+        import platform
+
+        config_vars = sysconfig.get_config_vars()
+        self.available = { nm for nm in config_vars if nm.startswith("HAVE_") and config_vars[nm] }
+        self.mac_ver = tuple(int(part) for part in platform.mac_ver()[0].split("."))
+
+    def _verify_available(self, name):
+        if name not in self.available:
+            raise unittest.SkipTest(f"{name} not weak-linked")
+
+    def test_pwritev(self):
+        self._verify_available("HAVE_PWRITEV")
+        if self.mac_ver >= (10, 16):
+            self.assertTrue(hasattr(os, "pwritev"), "os.pwritev is not available")
+            self.assertTrue(hasattr(os, "preadv"), "os.readv is not available")
+
+        else:
+            self.assertFalse(hasattr(os, "pwritev"), "os.pwritev is available")
+            self.assertFalse(hasattr(os, "preadv"), "os.readv is available")
+
+    def test_stat(self):
+        self._verify_available("HAVE_FSTATAT")
+        if self.mac_ver >= (10, 10):
+            self.assertIn("HAVE_FSTATAT", posix._have_functions)
+
+        else:
+            self.assertNotIn("HAVE_FSTATAT", posix._have_functions)
+
+            with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"):
+                os.stat("file", dir_fd=0)
+
+    def test_access(self):
+        self._verify_available("HAVE_FACCESSAT")
+        if self.mac_ver >= (10, 10):
+            self.assertIn("HAVE_FACCESSAT", posix._have_functions)
+
+        else:
+            self.assertNotIn("HAVE_FACCESSAT", posix._have_functions)
+
+            with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"):
+                os.access("file", os.R_OK, dir_fd=0)
+
+            with self.assertRaisesRegex(NotImplementedError, "follow_symlinks unavailable"):
+                os.access("file", os.R_OK, follow_symlinks=False)
+
+            with self.assertRaisesRegex(NotImplementedError, "effective_ids unavailable"):
+                os.access("file", os.R_OK, effective_ids=True)
+
+    def test_chmod(self):
+        self._verify_available("HAVE_FCHMODAT")
+        if self.mac_ver >= (10, 10):
+            self.assertIn("HAVE_FCHMODAT", posix._have_functions)
+
+        else:
+            self.assertNotIn("HAVE_FCHMODAT", posix._have_functions)
+            self.assertIn("HAVE_LCHMOD", posix._have_functions)
+
+            with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"):
+                os.chmod("file", 0o644, dir_fd=0)
+
+    def test_chown(self):
+        self._verify_available("HAVE_FCHOWNAT")
+        if self.mac_ver >= (10, 10):
+            self.assertIn("HAVE_FCHOWNAT", posix._have_functions)
+
+        else:
+            self.assertNotIn("HAVE_FCHOWNAT", posix._have_functions)
+            self.assertIn("HAVE_LCHOWN", posix._have_functions)
+
+            with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"):
+                os.chown("file", 0, 0, dir_fd=0)
+
+    def test_link(self):
+        self._verify_available("HAVE_LINKAT")
+        if self.mac_ver >= (10, 10):
+            self.assertIn("HAVE_LINKAT", posix._have_functions)
+
+        else:
+            self.assertNotIn("HAVE_LINKAT", posix._have_functions)
+
+            with self.assertRaisesRegex(NotImplementedError, "src_dir_fd unavailable"):
+                os.link("source", "target",  src_dir_fd=0)
+
+            with self.assertRaisesRegex(NotImplementedError, "dst_dir_fd unavailable"):
+                os.link("source", "target",  dst_dir_fd=0)
+
+            with self.assertRaisesRegex(NotImplementedError, "src_dir_fd unavailable"):
+                os.link("source", "target",  src_dir_fd=0, dst_dir_fd=0)
+
+            # issue 41355: !HAVE_LINKAT code path ignores the follow_symlinks flag
+            with os_helper.temp_dir() as base_path:
+                link_path = os.path.join(base_path, "link")
+                target_path = os.path.join(base_path, "target")
+                source_path = os.path.join(base_path, "source")
+
+                with open(source_path, "w") as fp:
+                    fp.write("data")
+
+                os.symlink("target", link_path)
+
+                # Calling os.link should fail in the link(2) call, and
+                # should not reject *follow_symlinks* (to match the
+                # behaviour you'd get when building on a platform without
+                # linkat)
+                with self.assertRaises(FileExistsError):
+                    os.link(source_path, link_path, follow_symlinks=True)
+
+                with self.assertRaises(FileExistsError):
+                    os.link(source_path, link_path, follow_symlinks=False)
+
+
+    def test_listdir_scandir(self):
+        self._verify_available("HAVE_FDOPENDIR")
+        if self.mac_ver >= (10, 10):
+            self.assertIn("HAVE_FDOPENDIR", posix._have_functions)
+
+        else:
+            self.assertNotIn("HAVE_FDOPENDIR", posix._have_functions)
+
+            with self.assertRaisesRegex(TypeError, "listdir: path should be string, bytes, os.PathLike or None, not int"):
+                os.listdir(0)
+
+            with self.assertRaisesRegex(TypeError, "scandir: path should be string, bytes, os.PathLike or None, not int"):
+                os.scandir(0)
+
+    def test_mkdir(self):
+        self._verify_available("HAVE_MKDIRAT")
+        if self.mac_ver >= (10, 10):
+            self.assertIn("HAVE_MKDIRAT", posix._have_functions)
+
+        else:
+            self.assertNotIn("HAVE_MKDIRAT", posix._have_functions)
+
+            with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"):
+                os.mkdir("dir", dir_fd=0)
+
+    def test_rename_replace(self):
+        self._verify_available("HAVE_RENAMEAT")
+        if self.mac_ver >= (10, 10):
+            self.assertIn("HAVE_RENAMEAT", posix._have_functions)
+
+        else:
+            self.assertNotIn("HAVE_RENAMEAT", posix._have_functions)
+
+            with self.assertRaisesRegex(NotImplementedError, "src_dir_fd and dst_dir_fd unavailable"):
+                os.rename("a", "b", src_dir_fd=0)
+
+            with self.assertRaisesRegex(NotImplementedError, "src_dir_fd and dst_dir_fd unavailable"):
+                os.rename("a", "b", dst_dir_fd=0)
+
+            with self.assertRaisesRegex(NotImplementedError, "src_dir_fd and dst_dir_fd unavailable"):
+                os.replace("a", "b", src_dir_fd=0)
+
+            with self.assertRaisesRegex(NotImplementedError, "src_dir_fd and dst_dir_fd unavailable"):
+                os.replace("a", "b", dst_dir_fd=0)
+
+    def test_unlink_rmdir(self):
+        self._verify_available("HAVE_UNLINKAT")
+        if self.mac_ver >= (10, 10):
+            self.assertIn("HAVE_UNLINKAT", posix._have_functions)
+
+        else:
+            self.assertNotIn("HAVE_UNLINKAT", posix._have_functions)
+
+            with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"):
+                os.unlink("path", dir_fd=0)
+
+            with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"):
+                os.rmdir("path", dir_fd=0)
+
+    def test_open(self):
+        self._verify_available("HAVE_OPENAT")
+        if self.mac_ver >= (10, 10):
+            self.assertIn("HAVE_OPENAT", posix._have_functions)
+
+        else:
+            self.assertNotIn("HAVE_OPENAT", posix._have_functions)
+
+            with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"):
+                os.open("path", os.O_RDONLY, dir_fd=0)
+
+    def test_readlink(self):
+        self._verify_available("HAVE_READLINKAT")
+        if self.mac_ver >= (10, 10):
+            self.assertIn("HAVE_READLINKAT", posix._have_functions)
+
+        else:
+            self.assertNotIn("HAVE_READLINKAT", posix._have_functions)
+
+            with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"):
+                os.readlink("path",  dir_fd=0)
+
+    def test_symlink(self):
+        self._verify_available("HAVE_SYMLINKAT")
+        if self.mac_ver >= (10, 10):
+            self.assertIn("HAVE_SYMLINKAT", posix._have_functions)
+
+        else:
+            self.assertNotIn("HAVE_SYMLINKAT", posix._have_functions)
+
+            with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"):
+                os.symlink("a", "b",  dir_fd=0)
+
+    def test_utime(self):
+        self._verify_available("HAVE_FUTIMENS")
+        self._verify_available("HAVE_UTIMENSAT")
+        if self.mac_ver >= (10, 13):
+            self.assertIn("HAVE_FUTIMENS", posix._have_functions)
+            self.assertIn("HAVE_UTIMENSAT", posix._have_functions)
+
+        else:
+            self.assertNotIn("HAVE_FUTIMENS", posix._have_functions)
+            self.assertNotIn("HAVE_UTIMENSAT", posix._have_functions)
+
+            with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"):
+                os.utime("path", dir_fd=0)
+
+
 def test_main():
     try:
         support.run_unittest(
@@ -1912,6 +2139,7 @@ def test_main():
             PosixGroupsTester,
             TestPosixSpawn,
             TestPosixSpawnP,
+            TestPosixWeaklinking
         )
     finally:
         support.reap_children()
diff -pur a/Lib/test/test_time.py b/Lib/test/test_time.py
--- a/Lib/test/test_time.py	2020-10-05 17:07:58.000000000 +0200
+++ b/Lib/test/test_time.py	2020-11-05 14:28:53.000000000 +0100
@@ -1040,6 +1040,36 @@ class TestOldPyTime(CPyTimeTestCase, uni
             with self.assertRaises(ValueError):
                 pytime_object_to_timespec(float('nan'), time_rnd)
 
+@unittest.skipUnless(sys.platform == "darwin", "test weak linking on macOS")
+class TestTimeWeaklinking(unittest.TestCase):
+    # These test cases verify that weak linking support on macOS works
+    # as expected. These cases only test new behaviour introduced by weak linking,
+    # regular behaviour is tested by the normal test cases.
+    #
+    # See the section on Weak Linking in Mac/README.txt for more information.
+    def test_clock_functions(self):
+        import sysconfig
+        import platform
+
+        config_vars = sysconfig.get_config_vars()
+        var_name = "HAVE_CLOCK_GETTIME"
+        if var_name not in config_vars or not config_vars[var_name]:
+            raise unittest.SkipTest(f"{var_name} is not available")
+
+        mac_ver = tuple(int(x) for x in platform.mac_ver()[0].split("."))
+
+        clock_names = [
+            "CLOCK_MONOTONIC", "clock_gettime", "clock_gettime_ns", "clock_settime",
+            "clock_settime_ns", "clock_getres"]
+        
+        if mac_ver >= (10, 12):
+            for name in clock_names:
+                self.assertTrue(hasattr(time, name), f"time.{name} is not available")
+
+        else:
+            for name in clock_names:
+                self.assertFalse(hasattr(time, name), f"time.{name} is available")
+
 
 if __name__ == "__main__":
     unittest.main()
diff -pur a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py
--- a/Lib/test/test_unicode.py	2020-10-05 17:07:58.000000000 +0200
+++ b/Lib/test/test_unicode.py	2020-11-05 14:28:53.000000000 +0100
@@ -2523,11 +2523,13 @@ class CAPITest(unittest.TestCase):
     def test_from_format(self):
         support.import_module('ctypes')
         from ctypes import (
