AArch64: Add support for -mdirect-extern-access

Message ID PAWPR08MB8982C07FA68CA1BAF8B6C10883009@PAWPR08MB8982.eurprd08.prod.outlook.com
State New
Headers
Series AArch64: Add support for -mdirect-extern-access |

Commit Message

Wilco Dijkstra Nov. 11, 2022, 2:48 p.m. UTC
  Add a new option -mdirect-extern-access similar to other targets.  This removes
GOT indirections on external symbols with -fPIE, resulting in significantly
better code quality.  With -fPIC it only affects protected symbols, allowing
for more efficient shared libraries which can be linked with standard PIE
binaries (this is what LLVM does by default, so this improves interoperability
with LLVM). This patch doesn't affect ABI, but in the future GCC and LLVM
should converge to using the same ABI.

Regress and bootstrap pass, OK for commit?

gcc/
	* config/aarch64/aarch64.cc (aarch64_binds_local_p): New function.
	(aarch64_symbol_binds_local_p): Refactor, support direct extern access.
	* config/aarch64/aarch64-linux.h (TARGET_BINDS_LOCAL_P):
	Use aarch64_binds_local_p.
	* config/aarch64/aarch64-freebsd.h (TARGET_BINDS_LOCAL_P): Likewise.
	* config/aarch64/aarch64-protos.h: Add aarch64_binds_local_p.
	* doc/gcc/gcc-command-options/option-summary.rst: Add
	-mdirect-extern-access.
	* doc/gcc/gcc-command-options/machine-dependent-options/aarch64-options.rst:
	Add description of -mdirect-extern-access.

gcc/testsuite/
	* gcc.target/aarch64/pr66912-2.c: New test.

---
  

Comments

Richard Sandiford Nov. 16, 2022, 10:54 a.m. UTC | #1
Wilco Dijkstra <Wilco.Dijkstra@arm.com> writes:
> Add a new option -mdirect-extern-access similar to other targets.  This removes
> GOT indirections on external symbols with -fPIE, resulting in significantly
> better code quality.  With -fPIC it only affects protected symbols, allowing
> for more efficient shared libraries which can be linked with standard PIE
> binaries (this is what LLVM does by default, so this improves interoperability
> with LLVM). This patch doesn't affect ABI, but in the future GCC and LLVM
> should converge to using the same ABI.

Can you go into more detail about:

    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

If this is LLVM's default for PIC (and by assumption shared libraries),
is it then invalid to use -mdirect-extern-access for any PIEs that
are linked against those shared libraries and use protected symbols
from those libraries?  How would a user know that one of the shared
libraries they're linking against was built in this way?

It looks like the main difference between this implementation and
the x86 one is that x86 allows direct accesses to common symbols.
What's the reason for not doing that for AArch64?  Does it not work,
is it a false optimisation (i.e. pessimisation), or did it not seem
important now that -fno-common is the default?

Thanks,
Richard

>
> Regress and bootstrap pass, OK for commit?
>
> gcc/
>         * config/aarch64/aarch64.cc (aarch64_binds_local_p): New function.
>         (aarch64_symbol_binds_local_p): Refactor, support direct extern access.
>         * config/aarch64/aarch64-linux.h (TARGET_BINDS_LOCAL_P):
>         Use aarch64_binds_local_p.
>         * config/aarch64/aarch64-freebsd.h (TARGET_BINDS_LOCAL_P): Likewise.
>         * config/aarch64/aarch64-protos.h: Add aarch64_binds_local_p.
>         * doc/gcc/gcc-command-options/option-summary.rst: Add
>         -mdirect-extern-access.
>         * doc/gcc/gcc-command-options/machine-dependent-options/aarch64-options.rst:
>         Add description of -mdirect-extern-access.
>
> gcc/testsuite/
>         * gcc.target/aarch64/pr66912-2.c: New test.
>
> ---
>
> 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 } } */
  
Wilco Dijkstra Nov. 17, 2022, 4:42 p.m. UTC | #2
Hi Richard,

> Can you go into more detail about:
>
>    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
>
> If this is LLVM's default for PIC (and by assumption shared libraries),
> is it then invalid to use -mdirect-extern-access for any PIEs that
> are linked against those shared libraries and use protected symbols
> from those libraries?  How would a user know that one of the shared
> libraries they're linking against was built in this way?

Yes, the usage model is that you'd either use it for static PIE or only on
data that is not shared. If you get it wrong them you'll get the copy
relocation error. In the future we need to decide what the ABI is and
ensure GCC and LLVM are compatible. An import feature to mark symbols
that may be overridden by a shared library would be useful too.

> It looks like the main difference between this implementation and
> the x86 one is that x86 allows direct accesses to common symbols.
> What's the reason for not doing that for AArch64?  Does it not work,
> is it a false optimisation (i.e. pessimisation), or did it not seem
> important now that -fno-common is the default?

I don't see any difference in the way common symbols are accessed on x86,
so it's not clear which cases common_local_p param actually affects (eg. with
-fPIC there is always a GOT indirection for common symbols).

Cheers,
Wilco
  
Richard Sandiford Nov. 17, 2022, 5:30 p.m. UTC | #3
Wilco Dijkstra <Wilco.Dijkstra@arm.com> writes:
> Hi Richard,
>
>> Can you go into more detail about:
>>
>>    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
>>
>> If this is LLVM's default for PIC (and by assumption shared libraries),
>> is it then invalid to use -mdirect-extern-access for any PIEs that
>> are linked against those shared libraries and use protected symbols
>> from those libraries?  How would a user know that one of the shared
>> libraries they're linking against was built in this way?
>
> Yes, the usage model is that you'd either use it for static PIE or only on
> data that is not shared. If you get it wrong them you'll get the copy
> relocation error.

Thanks.  I think I'm still missing something though.  If, for the
non-executable case, people should only use the feature on data that
is not shared, why do we need to relax the binds-local condition for
protected symbols on -fPIC?  Oughtn't the symbol to be hidden rather
than protected if the data isn't shared?

I can understand the reasoning for the PIE changes but I'm still
struggling with the PIC-but-not-PIE bits.

> In the future we need to decide what the ABI is and
> ensure GCC and LLVM are compatible. An import feature to mark symbols
> that may be overridden by a shared library would be useful too.
>
>> It looks like the main difference between this implementation and
>> the x86 one is that x86 allows direct accesses to common symbols.
>> What's the reason for not doing that for AArch64?  Does it not work,
>> is it a false optimisation (i.e. pessimisation), or did it not seem
>> important now that -fno-common is the default?
>
> I don't see any difference in the way common symbols are accessed on x86,
> so it's not clear which cases common_local_p param actually affects (eg. with
> -fPIC there is always a GOT indirection for common symbols).

Hmm, OK.  Could it be for one of the other languages?  But yeah,
if we don't have a testcase for it, I agree it's better to leave
things as they are.

Thanks,
Richard
  
Ramana Radhakrishnan Nov. 17, 2022, 8:52 p.m. UTC | #4
On Thu, Nov 17, 2022 at 5:30 PM Richard Sandiford via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> Wilco Dijkstra <Wilco.Dijkstra@arm.com> writes:
> > Hi Richard,
> >
> >> Can you go into more detail about:
> >>
> >>    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
> >>
> >> If this is LLVM's default for PIC (and by assumption shared libraries),
> >> is it then invalid to use -mdirect-extern-access for any PIEs that
> >> are linked against those shared libraries and use protected symbols
> >> from those libraries?  How would a user know that one of the shared
> >> libraries they're linking against was built in this way?
> >
> > Yes, the usage model is that you'd either use it for static PIE or only on
> > data that is not shared. If you get it wrong them you'll get the copy
> > relocation error.
>
> Thanks.  I think I'm still missing something though.  If, for the
> non-executable case, people should only use the feature on data that
> is not shared, why do we need to relax the binds-local condition for
> protected symbols on -fPIC?  Oughtn't the symbol to be hidden rather
> than protected if the data isn't shared?
>
> I can understand the reasoning for the PIE changes but I'm still
> struggling with the PIC-but-not-PIE bits.

I think I'm with Richard S on hidden vs protected on first reading. I
can see why this works out of the box and can even be default for
static-pie.

Any reason why this is not on by default - it's early enough in the
stage3 cycle and we can always flip the defaults if there are more
problems found.

You probably need a rebase for the documentation bits,.

regards
Ramana


Ramana
  
Li, Pan2 via Gcc-patches Nov. 17, 2022, 9:20 p.m. UTC | #5
> +.. 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.

I think current GCC and Clang's behavior is:

* -mdirect-extern-access is the default for -fno-pic. This is to enable optimizations for -static programs but may introduce copy relocations.
* -mno-direct-extern-access is the default for -fpie and -fpic. This uses some GOT-generating relocations which can be optimized out (lld, see https://maskray.me/blog/2021-08-29-all-about-global-offset-table) but the instruction is nevertheless slightly longer.

(-mdirect-extern-access for -fpic probably doesn't make sense.)

The option I introduced to Clang is -fdirect-access-external-data
(see https://maskray.me/blog/2021-01-09-copy-relocations-canonical-plt-entries-and-protected).
If -mdirect-extern-access gets more popular, I can add a Clang alias.
But I am opposed to forcing a GNU property for -mdirect-extern-access/-mno-direct-extern-access.

FWIW I used https://gist.github.com/MaskRay/c03a90922003df666551589f1629df22 to test my Clang changes related to -fno-semantic-interposition
on various visibility attributes x non-weak/weak x nopic/pie/pic x dllimport/not x ...

On 2022-11-17, Ramana Radhakrishnan wrote:
>On Thu, Nov 17, 2022 at 5:30 PM Richard Sandiford via Gcc-patches
><gcc-patches@gcc.gnu.org> wrote:
>>
>> Wilco Dijkstra <Wilco.Dijkstra@arm.com> writes:
>> > Hi Richard,
>> >
>> >> Can you go into more detail about:
>> >>
>> >>    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
>> >>
>> >> If this is LLVM's default for PIC (and by assumption shared libraries),
>> >> is it then invalid to use -mdirect-extern-access for any PIEs that
>> >> are linked against those shared libraries and use protected symbols
>> >> from those libraries?  How would a user know that one of the shared
>> >> libraries they're linking against was built in this way?
>> >
>> > Yes, the usage model is that you'd either use it for static PIE or only on
>> > data that is not shared. If you get it wrong them you'll get the copy
>> > relocation error.
>>
>> Thanks.  I think I'm still missing something though.  If, for the
>> non-executable case, people should only use the feature on data that
>> is not shared, why do we need to relax the binds-local condition for
>> protected symbols on -fPIC?  Oughtn't the symbol to be hidden rather
>> than protected if the data isn't shared?
>>
>> I can understand the reasoning for the PIE changes but I'm still
>> struggling with the PIC-but-not-PIE bits.
>
>I think I'm with Richard S on hidden vs protected on first reading. I
>can see why this works out of the box and can even be default for
>static-pie.
>
>Any reason why this is not on by default - it's early enough in the
>stage3 cycle and we can always flip the defaults if there are more
>problems found.
>
>You probably need a rebase for the documentation bits,.
>
>regards
>Ramana
>
>
>Ramana


+  is :option:`-mno-direct-extern-access`.
  
Andrew Pinski Nov. 17, 2022, 9:37 p.m. UTC | #6
On Thu, Nov 17, 2022 at 1:21 PM maskray--- via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> > +.. 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.
>
> I think current GCC and Clang's behavior is:
>
> * -mdirect-extern-access is the default for -fno-pic. This is to enable optimizations for -static programs but may introduce copy relocations.
> * -mno-direct-extern-access is the default for -fpie and -fpic. This uses some GOT-generating relocations which can be optimized out (lld, see https://maskray.me/blog/2021-08-29-all-about-global-offset-table) but the instruction is nevertheless slightly longer.
>
> (-mdirect-extern-access for -fpic probably doesn't make sense.)
>
> The option I introduced to Clang is -fdirect-access-external-data
> (see https://maskray.me/blog/2021-01-09-copy-relocations-canonical-plt-entries-and-protected).
> If -mdirect-extern-access gets more popular, I can add a Clang alias.
> But I am opposed to forcing a GNU property for -mdirect-extern-access/-mno-direct-extern-access.
>
> FWIW I used https://gist.github.com/MaskRay/c03a90922003df666551589f1629df22 to test my Clang changes related to -fno-semantic-interposition
> on various visibility attributes x non-weak/weak x nopic/pie/pic x dllimport/not x ...


The x86_64 discussion about this is here
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98112 .
I think clang changing the ABI is just broken and should think twice
before we do it for GCC.

And there is a lot of visibility protected issues filed in GCC bug
databases specifically about copy relocs too.
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56527
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=37611
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=19520
https://sourceware.org/bugzilla/show_bug.cgi?id=28875
https://sourceware.org/bugzilla/show_bug.cgi?id=28877
I also suspect clang's behavior is still broken too.

Thanks,
Andrew

>
> On 2022-11-17, Ramana Radhakrishnan wrote:
> >On Thu, Nov 17, 2022 at 5:30 PM Richard Sandiford via Gcc-patches
> ><gcc-patches@gcc.gnu.org> wrote:
> >>
> >> Wilco Dijkstra <Wilco.Dijkstra@arm.com> writes:
> >> > Hi Richard,
> >> >
> >> >> Can you go into more detail about:
> >> >>
> >> >>    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
> >> >>
> >> >> If this is LLVM's default for PIC (and by assumption shared libraries),
> >> >> is it then invalid to use -mdirect-extern-access for any PIEs that
> >> >> are linked against those shared libraries and use protected symbols
> >> >> from those libraries?  How would a user know that one of the shared
> >> >> libraries they're linking against was built in this way?
> >> >
> >> > Yes, the usage model is that you'd either use it for static PIE or only on
> >> > data that is not shared. If you get it wrong them you'll get the copy
> >> > relocation error.
> >>
> >> Thanks.  I think I'm still missing something though.  If, for the
> >> non-executable case, people should only use the feature on data that
> >> is not shared, why do we need to relax the binds-local condition for
> >> protected symbols on -fPIC?  Oughtn't the symbol to be hidden rather
> >> than protected if the data isn't shared?
> >>
> >> I can understand the reasoning for the PIE changes but I'm still
> >> struggling with the PIC-but-not-PIE bits.
> >
> >I think I'm with Richard S on hidden vs protected on first reading. I
> >can see why this works out of the box and can even be default for
> >static-pie.
> >
> >Any reason why this is not on by default - it's early enough in the
> >stage3 cycle and we can always flip the defaults if there are more
> >problems found.
> >
> >You probably need a rebase for the documentation bits,.
> >
> >regards
> >Ramana
> >
> >
> >Ramana
>
>
> +  is :option:`-mno-direct-extern-access`.
  
Fangrui Song Nov. 17, 2022, 9:46 p.m. UTC | #7
On Thu, Nov 17, 2022 at 1:37 PM Andrew Pinski <pinskia@gmail.com> wrote:
>
> On Thu, Nov 17, 2022 at 1:21 PM maskray--- via Gcc-patches
> <gcc-patches@gcc.gnu.org> wrote:
> >
> > > +.. 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.
> >
> > I think current GCC and Clang's behavior is:
> >
> > * -mdirect-extern-access is the default for -fno-pic. This is to enable optimizations for -static programs but may introduce copy relocations.
> > * -mno-direct-extern-access is the default for -fpie and -fpic. This uses some GOT-generating relocations which can be optimized out (lld, see https://maskray.me/blog/2021-08-29-all-about-global-offset-table) but the instruction is nevertheless slightly longer.
> >
> > (-mdirect-extern-access for -fpic probably doesn't make sense.)
> >
> > The option I introduced to Clang is -fdirect-access-external-data
> > (see https://maskray.me/blog/2021-01-09-copy-relocations-canonical-plt-entries-and-protected).
> > If -mdirect-extern-access gets more popular, I can add a Clang alias.
> > But I am opposed to forcing a GNU property for -mdirect-extern-access/-mno-direct-extern-access.
> >
> > FWIW I used https://gist.github.com/MaskRay/c03a90922003df666551589f1629df22 to test my Clang changes related to -fno-semantic-interposition
> > on various visibility attributes x non-weak/weak x nopic/pie/pic x dllimport/not x ...
>
>
> The x86_64 discussion about this is here
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98112 .
> I think clang changing the ABI is just broken and should think twice
> before we do it for GCC.
>
> And there is a lot of visibility protected issues filed in GCC bug
> databases specifically about copy relocs too.
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56527
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=37611
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=19520
> https://sourceware.org/bugzilla/show_bug.cgi?id=28875
> https://sourceware.org/bugzilla/show_bug.cgi?id=28877
> I also suspect clang's behavior is still broken too.
>
> Thanks,
> Andrew

Well, I don't think Clang changed ABI regarding -fno-pic/-fpie/-fpic.
As I did archaeology on
https://maskray.me/blog/2021-01-09-copy-relocations-canonical-plt-entries-and-protected
"Reflection on protected data symbols and copy relocations"
GCC 5 x86-64 made a change and GCC aarch64 accidentally picked up the change.

"""
On the GCC side, in -fpic mode, using GOT-generating relocations when
accessing a protected variable subverts the point using the protected
visibility. The unneeded pessimization is the foremost complaint. The
pessimization applies to all ports with #define TARGET_BINDS_LOCAL_P
default_binds_local_p_2. aarch64 moved to default_binds_local_p_2
accidentally by
https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=cbddf64c0243816b45e6680754a251c603245dbc.

For GCC<5 (and all versions of Clang), direct accesses to protected
variables are produced in -fpic code. Mixing such object files can
still silently break copy relocations on protected data symbols.
Therefore, GNU ld made the controversial change
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=commit;h=ca3fe95e469b9daec153caa2c90665f5daaec2b5
to error in -shared mode.
"""


> >
> > On 2022-11-17, Ramana Radhakrishnan wrote:
> > >On Thu, Nov 17, 2022 at 5:30 PM Richard Sandiford via Gcc-patches
> > ><gcc-patches@gcc.gnu.org> wrote:
> > >>
> > >> Wilco Dijkstra <Wilco.Dijkstra@arm.com> writes:
> > >> > Hi Richard,
> > >> >
> > >> >> Can you go into more detail about:
> > >> >>
> > >> >>    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
> > >> >>
> > >> >> If this is LLVM's default for PIC (and by assumption shared libraries),
> > >> >> is it then invalid to use -mdirect-extern-access for any PIEs that
> > >> >> are linked against those shared libraries and use protected symbols
> > >> >> from those libraries?  How would a user know that one of the shared
> > >> >> libraries they're linking against was built in this way?
> > >> >
> > >> > Yes, the usage model is that you'd either use it for static PIE or only on
> > >> > data that is not shared. If you get it wrong them you'll get the copy
> > >> > relocation error.
> > >>
> > >> Thanks.  I think I'm still missing something though.  If, for the
> > >> non-executable case, people should only use the feature on data that
> > >> is not shared, why do we need to relax the binds-local condition for
> > >> protected symbols on -fPIC?  Oughtn't the symbol to be hidden rather
> > >> than protected if the data isn't shared?
> > >>
> > >> I can understand the reasoning for the PIE changes but I'm still
> > >> struggling with the PIC-but-not-PIE bits.
> > >
> > >I think I'm with Richard S on hidden vs protected on first reading. I
> > >can see why this works out of the box and can even be default for
> > >static-pie.
> > >
> > >Any reason why this is not on by default - it's early enough in the
> > >stage3 cycle and we can always flip the defaults if there are more
> > >problems found.
> > >
> > >You probably need a rebase for the documentation bits,.
> > >
> > >regards
> > >Ramana
> > >
> > >
> > >Ramana
> >
> >
> > +  is :option:`-mno-direct-extern-access`.
  
Andrew Pinski Nov. 17, 2022, 9:55 p.m. UTC | #8
On Thu, Nov 17, 2022 at 1:46 PM Fangrui Song <maskray@google.com> wrote:
>
> On Thu, Nov 17, 2022 at 1:37 PM Andrew Pinski <pinskia@gmail.com> wrote:
> >
> > On Thu, Nov 17, 2022 at 1:21 PM maskray--- via Gcc-patches
> > <gcc-patches@gcc.gnu.org> wrote:
> > >
> > > > +.. 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.
> > >
> > > I think current GCC and Clang's behavior is:
> > >
> > > * -mdirect-extern-access is the default for -fno-pic. This is to enable optimizations for -static programs but may introduce copy relocations.
> > > * -mno-direct-extern-access is the default for -fpie and -fpic. This uses some GOT-generating relocations which can be optimized out (lld, see https://maskray.me/blog/2021-08-29-all-about-global-offset-table) but the instruction is nevertheless slightly longer.
> > >
> > > (-mdirect-extern-access for -fpic probably doesn't make sense.)
> > >
> > > The option I introduced to Clang is -fdirect-access-external-data
> > > (see https://maskray.me/blog/2021-01-09-copy-relocations-canonical-plt-entries-and-protected).
> > > If -mdirect-extern-access gets more popular, I can add a Clang alias.
> > > But I am opposed to forcing a GNU property for -mdirect-extern-access/-mno-direct-extern-access.
> > >
> > > FWIW I used https://gist.github.com/MaskRay/c03a90922003df666551589f1629df22 to test my Clang changes related to -fno-semantic-interposition
> > > on various visibility attributes x non-weak/weak x nopic/pie/pic x dllimport/not x ...
> >
> >
> > The x86_64 discussion about this is here
> > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98112 .
> > I think clang changing the ABI is just broken and should think twice
> > before we do it for GCC.
> >
> > And there is a lot of visibility protected issues filed in GCC bug
> > databases specifically about copy relocs too.
> > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56527
> > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=37611
> > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=19520
> > https://sourceware.org/bugzilla/show_bug.cgi?id=28875
> > https://sourceware.org/bugzilla/show_bug.cgi?id=28877
> > I also suspect clang's behavior is still broken too.
> >
> > Thanks,
> > Andrew
>
> Well, I don't think Clang changed ABI regarding -fno-pic/-fpie/-fpic.
> As I did archaeology on
> https://maskray.me/blog/2021-01-09-copy-relocations-canonical-plt-entries-and-protected
> "Reflection on protected data symbols and copy relocations"
> GCC 5 x86-64 made a change and GCC aarch64 accidentally picked up the change.

You missed: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65248 (or
rather r5-7961-ga5eef8e9b02474 ) was the change to fix protected .


>
> """
> On the GCC side, in -fpic mode, using GOT-generating relocations when
> accessing a protected variable subverts the point using the protected
> visibility. The unneeded pessimization is the foremost complaint. The
> pessimization applies to all ports with #define TARGET_BINDS_LOCAL_P
> default_binds_local_p_2. aarch64 moved to default_binds_local_p_2
> accidentally by
> https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=cbddf64c0243816b45e6680754a251c603245dbc.

This was NOT by accident. In fact you just looked into the commit and
NOT the actually email which submitted the patch:
https://gcc.gnu.org/legacy-ml/gcc-patches/2015-04/msg01432.html
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65780

"As s390/arm/aarch64 seems to work fine
(generate a COPY relocation and thus define symbol locally) in non-PIE
executables, this patch changes those to a function that has been added for
that behavior."


Thanks,
Andrew Pinski

>
> For GCC<5 (and all versions of Clang), direct accesses to protected
> variables are produced in -fpic code. Mixing such object files can
> still silently break copy relocations on protected data symbols.
> Therefore, GNU ld made the controversial change
> https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=commit;h=ca3fe95e469b9daec153caa2c90665f5daaec2b5
> to error in -shared mode.
> """
>
>
> > >
> > > On 2022-11-17, Ramana Radhakrishnan wrote:
> > > >On Thu, Nov 17, 2022 at 5:30 PM Richard Sandiford via Gcc-patches
> > > ><gcc-patches@gcc.gnu.org> wrote:
> > > >>
> > > >> Wilco Dijkstra <Wilco.Dijkstra@arm.com> writes:
> > > >> > Hi Richard,
> > > >> >
> > > >> >> Can you go into more detail about:
> > > >> >>
> > > >> >>    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
> > > >> >>
> > > >> >> If this is LLVM's default for PIC (and by assumption shared libraries),
> > > >> >> is it then invalid to use -mdirect-extern-access for any PIEs that
> > > >> >> are linked against those shared libraries and use protected symbols
> > > >> >> from those libraries?  How would a user know that one of the shared
> > > >> >> libraries they're linking against was built in this way?
> > > >> >
> > > >> > Yes, the usage model is that you'd either use it for static PIE or only on
> > > >> > data that is not shared. If you get it wrong them you'll get the copy
> > > >> > relocation error.
> > > >>
> > > >> Thanks.  I think I'm still missing something though.  If, for the
> > > >> non-executable case, people should only use the feature on data that
> > > >> is not shared, why do we need to relax the binds-local condition for
> > > >> protected symbols on -fPIC?  Oughtn't the symbol to be hidden rather
> > > >> than protected if the data isn't shared?
> > > >>
> > > >> I can understand the reasoning for the PIE changes but I'm still
> > > >> struggling with the PIC-but-not-PIE bits.
> > > >
> > > >I think I'm with Richard S on hidden vs protected on first reading. I
> > > >can see why this works out of the box and can even be default for
> > > >static-pie.
> > > >
> > > >Any reason why this is not on by default - it's early enough in the
> > > >stage3 cycle and we can always flip the defaults if there are more
> > > >problems found.
> > > >
> > > >You probably need a rebase for the documentation bits,.
> > > >
> > > >regards
> > > >Ramana
> > > >
> > > >
> > > >Ramana
> > >
> > >
> > > +  is :option:`-mno-direct-extern-access`.
>
>
>
> --
> 宋方睿
  
Fangrui Song Nov. 17, 2022, 10:07 p.m. UTC | #9
On Thu, Nov 17, 2022 at 1:55 PM Andrew Pinski <pinskia@gmail.com> wrote:
>
> On Thu, Nov 17, 2022 at 1:46 PM Fangrui Song <maskray@google.com> wrote:
> >
> > On Thu, Nov 17, 2022 at 1:37 PM Andrew Pinski <pinskia@gmail.com> wrote:
> > >
> > > On Thu, Nov 17, 2022 at 1:21 PM maskray--- via Gcc-patches
> > > <gcc-patches@gcc.gnu.org> wrote:
> > > >
> > > > > +.. 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.
> > > >
> > > > I think current GCC and Clang's behavior is:
> > > >
> > > > * -mdirect-extern-access is the default for -fno-pic. This is to enable optimizations for -static programs but may introduce copy relocations.
> > > > * -mno-direct-extern-access is the default for -fpie and -fpic. This uses some GOT-generating relocations which can be optimized out (lld, see https://maskray.me/blog/2021-08-29-all-about-global-offset-table) but the instruction is nevertheless slightly longer.
> > > >
> > > > (-mdirect-extern-access for -fpic probably doesn't make sense.)
> > > >
> > > > The option I introduced to Clang is -fdirect-access-external-data
> > > > (see https://maskray.me/blog/2021-01-09-copy-relocations-canonical-plt-entries-and-protected).
> > > > If -mdirect-extern-access gets more popular, I can add a Clang alias.
> > > > But I am opposed to forcing a GNU property for -mdirect-extern-access/-mno-direct-extern-access.
> > > >
> > > > FWIW I used https://gist.github.com/MaskRay/c03a90922003df666551589f1629df22 to test my Clang changes related to -fno-semantic-interposition
> > > > on various visibility attributes x non-weak/weak x nopic/pie/pic x dllimport/not x ...
> > >
> > >
> > > The x86_64 discussion about this is here
> > > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98112 .
> > > I think clang changing the ABI is just broken and should think twice
> > > before we do it for GCC.
> > >
> > > And there is a lot of visibility protected issues filed in GCC bug
> > > databases specifically about copy relocs too.
> > > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56527
> > > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=37611
> > > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=19520
> > > https://sourceware.org/bugzilla/show_bug.cgi?id=28875
> > > https://sourceware.org/bugzilla/show_bug.cgi?id=28877
> > > I also suspect clang's behavior is still broken too.
> > >
> > > Thanks,
> > > Andrew
> >
> > Well, I don't think Clang changed ABI regarding -fno-pic/-fpie/-fpic.
> > As I did archaeology on
> > https://maskray.me/blog/2021-01-09-copy-relocations-canonical-plt-entries-and-protected
> > "Reflection on protected data symbols and copy relocations"
> > GCC 5 x86-64 made a change and GCC aarch64 accidentally picked up the change.
>
> You missed: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65248 (or
> rather r5-7961-ga5eef8e9b02474 ) was the change to fix protected .

I didn't. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65248 proposed a problem.
It could be resolved as "wontfix. copy relocations are just
incompatible with protected symbols as an optimization (which is the
very purpose of inventing protected)"
but was resolved by pessimizing GCC codegen. This led to heated
discussion in several places including
https://sourceware.org/legacy-ml/binutils/2016-03/msg00312.html (which
my article linked to).

>
> >
> > """
> > On the GCC side, in -fpic mode, using GOT-generating relocations when
> > accessing a protected variable subverts the point using the protected
> > visibility. The unneeded pessimization is the foremost complaint. The
> > pessimization applies to all ports with #define TARGET_BINDS_LOCAL_P
> > default_binds_local_p_2. aarch64 moved to default_binds_local_p_2
> > accidentally by
> > https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=cbddf64c0243816b45e6680754a251c603245dbc.
>
> This was NOT by accident. In fact you just looked into the commit and
> NOT the actually email which submitted the patch:
> https://gcc.gnu.org/legacy-ml/gcc-patches/2015-04/msg01432.html
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65780

This aarch64 commit was by accident. The code happened to change both
COMMON symbol and protected behaviors.
While the COMMON symbol behavior was intentional, the proteced symbol
behavior was not.

> "As s390/arm/aarch64 seems to work fine
> (generate a COPY relocation and thus define symbol locally) in non-PIE
> executables, this patch changes those to a function that has been added for
> that behavior."
>
>
> Thanks,
> Andrew Pinski
>
> >
> > For GCC<5 (and all versions of Clang), direct accesses to protected
> > variables are produced in -fpic code. Mixing such object files can
> > still silently break copy relocations on protected data symbols.
> > Therefore, GNU ld made the controversial change
> > https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=commit;h=ca3fe95e469b9daec153caa2c90665f5daaec2b5
> > to error in -shared mode.
> > """
> >
> >
> > > >
> > > > On 2022-11-17, Ramana Radhakrishnan wrote:
> > > > >On Thu, Nov 17, 2022 at 5:30 PM Richard Sandiford via Gcc-patches
> > > > ><gcc-patches@gcc.gnu.org> wrote:
> > > > >>
> > > > >> Wilco Dijkstra <Wilco.Dijkstra@arm.com> writes:
> > > > >> > Hi Richard,
> > > > >> >
> > > > >> >> Can you go into more detail about:
> > > > >> >>
> > > > >> >>    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
> > > > >> >>
> > > > >> >> If this is LLVM's default for PIC (and by assumption shared libraries),
> > > > >> >> is it then invalid to use -mdirect-extern-access for any PIEs that
> > > > >> >> are linked against those shared libraries and use protected symbols
> > > > >> >> from those libraries?  How would a user know that one of the shared
> > > > >> >> libraries they're linking against was built in this way?
> > > > >> >
> > > > >> > Yes, the usage model is that you'd either use it for static PIE or only on
> > > > >> > data that is not shared. If you get it wrong them you'll get the copy
> > > > >> > relocation error.
> > > > >>
> > > > >> Thanks.  I think I'm still missing something though.  If, for the
> > > > >> non-executable case, people should only use the feature on data that
> > > > >> is not shared, why do we need to relax the binds-local condition for
> > > > >> protected symbols on -fPIC?  Oughtn't the symbol to be hidden rather
> > > > >> than protected if the data isn't shared?
> > > > >>
> > > > >> I can understand the reasoning for the PIE changes but I'm still
> > > > >> struggling with the PIC-but-not-PIE bits.
> > > > >
> > > > >I think I'm with Richard S on hidden vs protected on first reading. I
> > > > >can see why this works out of the box and can even be default for
> > > > >static-pie.
> > > > >
> > > > >Any reason why this is not on by default - it's early enough in the
> > > > >stage3 cycle and we can always flip the defaults if there are more
> > > > >problems found.
> > > > >
> > > > >You probably need a rebase for the documentation bits,.
> > > > >
> > > > >regards
> > > > >Ramana
> > > > >
> > > > >
> > > > >Ramana
> > > >
> > > >
> > > > +  is :option:`-mno-direct-extern-access`.
> >
> >
> >
> > --
> > 宋方睿
  

Patch

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 } } */