diff --git a/gcc/config/aarch64/aarch64-freebsd.h b/gcc/config/aarch64/aarch64-freebsd.h
index 13beb3781b61afd82d767884f3c16ff8eead09cc..20bc0f48e484686cd3754613bf20bb3521079d48 100644
--- a/gcc/config/aarch64/aarch64-freebsd.h
+++ b/gcc/config/aarch64/aarch64-freebsd.h
@@ -71,7 +71,7 @@
    strong definitions in dependent shared libraries, will resolve
    to COPY relocated symbol in the executable.  See PR65780.  */
 #undef TARGET_BINDS_LOCAL_P
-#define TARGET_BINDS_LOCAL_P default_binds_local_p_2
+#define TARGET_BINDS_LOCAL_P aarch64_binds_local_p
 
 /* Use the AAPCS type for wchar_t, override the one from
    config/freebsd.h.  */
diff --git a/gcc/config/aarch64/aarch64-linux.h b/gcc/config/aarch64/aarch64-linux.h
index 5e4553d79f5053f2da0eb381e0805f47aec964ae..6c962402155d60b82610d4f65af5182d6faa47ad 100644
--- a/gcc/config/aarch64/aarch64-linux.h
+++ b/gcc/config/aarch64/aarch64-linux.h
@@ -70,7 +70,7 @@
    strong definitions in dependent shared libraries, will resolve
    to COPY relocated symbol in the executable.  See PR65780.  */
 #undef TARGET_BINDS_LOCAL_P
-#define TARGET_BINDS_LOCAL_P default_binds_local_p_2
+#define TARGET_BINDS_LOCAL_P aarch64_binds_local_p
 
 /* Define this to be nonzero if static stack checking is supported.  */
 #define STACK_CHECK_STATIC_BUILTIN 1
diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
index 238820581c5ee7617f8eed1df2cf5418b1127e19..fac754f78c1d7606ba90e1034820a62466b96b63 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -1072,5 +1072,6 @@ const char *aarch64_sls_barrier (int);
 const char *aarch64_indirect_call_asm (rtx);
 extern bool aarch64_harden_sls_retbr_p (void);
 extern bool aarch64_harden_sls_blr_p (void);
+extern bool aarch64_binds_local_p (const_tree);
 
 #endif /* GCC_AARCH64_PROTOS_H */
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index d1f979ebcf80333d957f8ad8631deef47dc693a5..ab4c42c34da5b15f6739c9b0a7ebaafda9488f2d 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -19185,9 +19185,29 @@ aarch64_tlsdesc_abi_id ()
 static bool
 aarch64_symbol_binds_local_p (const_rtx x)
 {
-  return (SYMBOL_REF_DECL (x)
-	  ? targetm.binds_local_p (SYMBOL_REF_DECL (x))
-	  : SYMBOL_REF_LOCAL_P (x));
+  if (!SYMBOL_REF_DECL (x))
+    return SYMBOL_REF_LOCAL_P (x);
+
+  if (targetm.binds_local_p (SYMBOL_REF_DECL (x)))
+    return true;
+
+  /* In PIE binaries avoid a GOT indirection on non-weak data symbols if
+     aarch64_direct_extern_access is true.  */
+  if (flag_pie && aarch64_direct_extern_access && !SYMBOL_REF_WEAK (x)
+      && !SYMBOL_REF_FUNCTION_P (x))
+    return true;
+
+  return false;
+}
+
+/* Implement TARGET_BINDS_LOCAL_P hook.  */
+
+bool
+aarch64_binds_local_p (const_tree exp)
+{
+  /* Protected symbols are local if aarch64_direct_extern_access is true.  */
+  return default_binds_local_p_3 (exp, flag_shlib != 0, true,
+				  !aarch64_direct_extern_access, !flag_pic);
 }
 
 /* Return true if SYMBOL_REF X is thread local */
diff --git a/gcc/config/aarch64/aarch64.opt b/gcc/config/aarch64/aarch64.opt
index b89b20450710592101b93f4f3b5dc33d152d1eb6..6251a36b544a03955361b445c9f5dfad3740eea8 100644
--- a/gcc/config/aarch64/aarch64.opt
+++ b/gcc/config/aarch64/aarch64.opt
@@ -299,3 +299,7 @@ Constant memset size in bytes from which to start using MOPS sequence.
 -param=aarch64-vect-unroll-limit=
 Target Joined UInteger Var(aarch64_vect_unroll_limit) Init(4) Param
 Limit how much the autovectorizer may unroll a loop.
+
+mdirect-extern-access
+Target Var(aarch64_direct_extern_access) Init(0)
+Do not indirect accesses to external symbols via the GOT.
diff --git a/gcc/doc/gcc/gcc-command-options/machine-dependent-options/aarch64-options.rst b/gcc/doc/gcc/gcc-command-options/machine-dependent-options/aarch64-options.rst
index c2b23a6ee97ef2b7c74119f22c1d3e3d85385f4d..599c37fe299dc142d25d2133a4cd0b861e34fd01 100644
--- a/gcc/doc/gcc/gcc-command-options/machine-dependent-options/aarch64-options.rst
+++ b/gcc/doc/gcc/gcc-command-options/machine-dependent-options/aarch64-options.rst
@@ -389,6 +389,20 @@ These options are defined for AArch64 implementations:
   The default is :samp:`-msve-vector-bits=scalable`, which produces
   vector-length agnostic code.
 
+.. option:: -mdirect-extern-access, -mno-direct-extern-access
+
+  Use direct accesses for external data symbols.  It avoids a GOT indirection
+  on all external data symbols with :option:`-fpie` or :option:`-fPIE`.  This is
+  useful for executables linked with :option:`-static` or :option:`-static-pie`.
+  With :option:`-fpic` or :option:`-fPIC`, it only affects accesses to protected
+  data symbols.  It has no effect on non-position independent code.  The default
+  is :option:`-mno-direct-extern-access`.
+
+  .. warning::
+
+    Use :option:`-mdirect-extern-access` either in shared libraries or in
+    executables, but not in both.  Protected symbols used both in a shared
+    library and executable may cause linker errors or fail to work correctly.
 
 .. _aarch64-feature-modifiers:
 
diff --git a/gcc/doc/gcc/gcc-command-options/option-summary.rst b/gcc/doc/gcc/gcc-command-options/option-summary.rst
index d068f98feac27d95f1402a530a78b553d623d2e9..dbc9b45ae1db12737aca3a6fd246b88a0e9467c2 100644
--- a/gcc/doc/gcc/gcc-command-options/option-summary.rst
+++ b/gcc/doc/gcc/gcc-command-options/option-summary.rst
@@ -634,7 +634,8 @@ in the following sections.
   :option:`-moverride=string`  :option:`-mverbose-cost-dump` |gol|
   :option:`-mstack-protector-guard=guard` :option:`-mstack-protector-guard-reg=sysreg` |gol|
   :option:`-mstack-protector-guard-offset=offset` :option:`-mtrack-speculation` |gol|
-  :option:`-moutline-atomics`
+  :option:`-moutline-atomics` |gol|
+  :option:`-mdirect-extern-access`
 
   *Adapteva Epiphany Options*
 
diff --git a/gcc/testsuite/gcc.target/aarch64/pr66912-2.c b/gcc/testsuite/gcc.target/aarch64/pr66912-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..58e6e1f37116bff77015a7321890ece30c9e6a5c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/pr66912-2.c
@@ -0,0 +1,41 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpic" } */
+/* { dg-require-effective-target fpic } */
+
+__attribute__((visibility("protected")))
+int n_common;
+
+__attribute__((weak, visibility("protected")))
+int n_weak_common;
+
+__attribute__((visibility("protected")))
+int n_init = -1;
+
+__attribute__((weak, visibility("protected")))
+int n_weak_init = -1;
+
+int
+f1 ()
+{
+  return n_common;
+}
+
+int
+f2 ()
+{
+  return n_weak_common;
+}
+
+int
+f3 ()
+{
+  return n_init;
+}
+
+int
+f4 ()
+{
+  return n_weak_init;
+}
+
+/* { dg-final { scan-assembler-times ":got" 0 } } */
