Message ID | 20210709145014.1350564-2-hjl.tools@gmail.com |
---|---|
State | New |
Headers | show |
Series | Implement indirect external access | expand |
On Fri, Jul 9, 2021 at 4:50 PM H.J. Lu <hjl.tools@gmail.com> wrote: > > -fdirect-extern-access is the default. With -fno-direct-extern-access: > > 1. Always use GOT to access undefined data and function symbols, > including in PIE and non-PIE. These will avoid copy relocations > in executables. This is compatible with existing executables and > shared libraries. > 2. In executable and shared library, bind symbols with the STV_PROTECTED > visibility locally: > a. The address of data symbol is the address of data body. > b. For systems without function descriptor, the function pointer is > the address of function body. > c. The resulting shared libraries may not be incompatible with > executables which have copy relocations on protected symbols or > use executable PLT entries as function addresses for protected > functions in shared libraries. > 3. Update asm_preferred_eh_data_format to select PC relative EH encoding > format with -fno-direct-extern-access to avoid copy relocation. > 4. Add ix86_reloc_rw_mask for TARGET_ASM_RELOC_RW_MASK to avoid copy > relocation with -fno-direct-extern-access. Did you check how relocations in .debug_info behave? I don't remember whether we're doing anything special there or if we just copy how we emit relocs in .text Richard. > gcc/ > > PR target/35513 > PR target/100593 > * common.opt: Add -fdirect-extern-access. > * config/i386/i386-protos.h (ix86_force_load_from_GOT_p): Add a > bool argument. > * config/i386/i386.c (ix86_force_load_from_GOT_p): Add a bool > argument to indicate call operand. Force non-call load > from GOT for -fno-direct-extern-access. > (legitimate_pic_address_disp_p): Avoid copy relocation in PIE > for -fno-direct-extern-access. > (ix86_print_operand): Pass true to ix86_force_load_from_GOT_p > for call operand. > (asm_preferred_eh_data_format): Use PC-relative format for > -fno-direct-extern-access to avoid copy relocation. Check > ptr_mode instead of TARGET_64BIT when selecting DW_EH_PE_sdata4. > (ix86_binds_local_p): Don't treat protected data as extern and > avoid copy relocation on common symbol with > -fno-direct-extern-access. > (ix86_reloc_rw_mask): New to avoid copy relocation for > -fno-direct-extern-access. > (TARGET_ASM_RELOC_RW_MASK): New. > * doc/invoke.texi: Document -f[no-]direct-extern-access. > > gcc/testsuite/ > > PR target/35513 > PR target/100593 > * g++.dg/pr35513-1.C: New file. > * g++.dg/pr35513-2.C: Likewise. > * gcc.target/i386/pr35513-1.c: Likewise. > * gcc.target/i386/pr35513-2.c: Likewise. > * gcc.target/i386/pr35513-3.c: Likewise. > * gcc.target/i386/pr35513-4.c: Likewise. > * gcc.target/i386/pr35513-5.c: Likewise. > * gcc.target/i386/pr35513-6.c: Likewise. > * gcc.target/i386/pr35513-7.c: Likewise. > * gcc.target/i386/pr35513-8.c: Likewise. > --- > gcc/common.opt | 4 ++ > gcc/config/i386/i386-protos.h | 2 +- > gcc/config/i386/i386.c | 50 +++++++++++++++------ > gcc/doc/invoke.texi | 13 ++++++ > gcc/testsuite/g++.dg/pr35513-1.C | 25 +++++++++++ > gcc/testsuite/g++.dg/pr35513-2.C | 53 +++++++++++++++++++++++ > gcc/testsuite/gcc.target/i386/pr35513-1.c | 16 +++++++ > gcc/testsuite/gcc.target/i386/pr35513-2.c | 15 +++++++ > gcc/testsuite/gcc.target/i386/pr35513-3.c | 15 +++++++ > gcc/testsuite/gcc.target/i386/pr35513-4.c | 15 +++++++ > gcc/testsuite/gcc.target/i386/pr35513-5.c | 15 +++++++ > gcc/testsuite/gcc.target/i386/pr35513-6.c | 14 ++++++ > gcc/testsuite/gcc.target/i386/pr35513-7.c | 15 +++++++ > gcc/testsuite/gcc.target/i386/pr35513-8.c | 41 ++++++++++++++++++ > 14 files changed, 278 insertions(+), 15 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/pr35513-1.C > create mode 100644 gcc/testsuite/g++.dg/pr35513-2.C > create mode 100644 gcc/testsuite/gcc.target/i386/pr35513-1.c > create mode 100644 gcc/testsuite/gcc.target/i386/pr35513-2.c > create mode 100644 gcc/testsuite/gcc.target/i386/pr35513-3.c > create mode 100644 gcc/testsuite/gcc.target/i386/pr35513-4.c > create mode 100644 gcc/testsuite/gcc.target/i386/pr35513-5.c > create mode 100644 gcc/testsuite/gcc.target/i386/pr35513-6.c > create mode 100644 gcc/testsuite/gcc.target/i386/pr35513-7.c > create mode 100644 gcc/testsuite/gcc.target/i386/pr35513-8.c > > diff --git a/gcc/common.opt b/gcc/common.opt > index d9da1131eda..67ad811d54d 100644 > --- a/gcc/common.opt > +++ b/gcc/common.opt > @@ -1432,6 +1432,10 @@ fdiagnostics-minimum-margin-width= > Common Joined UInteger Var(diagnostics_minimum_margin_width) Init(6) > Set minimum width of left margin of source code when showing source. > > +fdirect-extern-access > +Common Var(flag_direct_extern_access) Init(1) Optimization > +Do not use GOT to access external symbols. > + > fdisable- > Common Joined RejectNegative Var(common_deferred_options) Defer > -fdisable-[tree|rtl|ipa]-<pass>=range1+range2 Disable an optimization pass. > diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h > index 51376fcc454..693cc3e5c78 100644 > --- a/gcc/config/i386/i386-protos.h > +++ b/gcc/config/i386/i386-protos.h > @@ -79,7 +79,7 @@ extern bool ix86_expand_cmpstrn_or_cmpmem (rtx, rtx, rtx, rtx, rtx, bool); > extern bool constant_address_p (rtx); > extern bool legitimate_pic_operand_p (rtx); > extern bool legitimate_pic_address_disp_p (rtx); > -extern bool ix86_force_load_from_GOT_p (rtx); > +extern bool ix86_force_load_from_GOT_p (rtx, bool = false); > extern void print_reg (rtx, int, FILE*); > extern void ix86_print_operand (FILE *, rtx, int); > > diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c > index cff26909292..7dee311051d 100644 > --- a/gcc/config/i386/i386.c > +++ b/gcc/config/i386/i386.c > @@ -10312,13 +10312,17 @@ darwin_local_data_pic (rtx disp) > } > > /* True if the function symbol operand X should be loaded from GOT. > + If CALL_P is true, X is a call operand. > + > + NB: -fno-direct-extern-access doesn't force load from GOT for > + call. > > NB: In 32-bit mode, only non-PIC is allowed in inline assembly > statements, since a PIC register could not be available at the > call site. */ > > bool > -ix86_force_load_from_GOT_p (rtx x) > +ix86_force_load_from_GOT_p (rtx x, bool call_p) > { > return ((TARGET_64BIT || (!flag_pic && HAVE_AS_IX86_GOT32X)) > && !TARGET_PECOFF && !TARGET_MACHO > @@ -10326,11 +10330,12 @@ ix86_force_load_from_GOT_p (rtx x) > && ix86_cmodel != CM_LARGE > && ix86_cmodel != CM_LARGE_PIC > && GET_CODE (x) == SYMBOL_REF > - && SYMBOL_REF_FUNCTION_P (x) > - && (!flag_plt > - || (SYMBOL_REF_DECL (x) > - && lookup_attribute ("noplt", > - DECL_ATTRIBUTES (SYMBOL_REF_DECL (x))))) > + && ((!call_p && !flag_direct_extern_access) > + || (SYMBOL_REF_FUNCTION_P (x) > + && (!flag_plt > + || (SYMBOL_REF_DECL (x) > + && lookup_attribute ("noplt", > + DECL_ATTRIBUTES (SYMBOL_REF_DECL (x))))))) > && !SYMBOL_REF_LOCAL_P (x)); > } > > @@ -10596,7 +10601,8 @@ legitimate_pic_address_disp_p (rtx disp) > } > else if (!SYMBOL_REF_FAR_ADDR_P (op0) > && (SYMBOL_REF_LOCAL_P (op0) > - || (HAVE_LD_PIE_COPYRELOC > + || (flag_direct_extern_access > + && HAVE_LD_PIE_COPYRELOC > && flag_pie > && !SYMBOL_REF_WEAK (op0) > && !SYMBOL_REF_FUNCTION_P (op0))) > @@ -13498,7 +13504,7 @@ ix86_print_operand (FILE *file, rtx x, int code) > > if (code == 'P') > { > - if (ix86_force_load_from_GOT_p (x)) > + if (ix86_force_load_from_GOT_p (x, true)) > { > /* For inline assembly statement, load function address > from GOT with 'P' operand modifier to avoid PLT. */ > @@ -21935,10 +21941,10 @@ int > asm_preferred_eh_data_format (int code, int global) > { > /* PE-COFF is effectively always -fPIC because of the .reloc section. */ > - if (flag_pic || TARGET_PECOFF) > + if (flag_pic || TARGET_PECOFF || !flag_direct_extern_access) > { > int type = DW_EH_PE_sdata8; > - if (!TARGET_64BIT > + if (ptr_mode == SImode > || ix86_cmodel == CM_SMALL_PIC > || (ix86_cmodel == CM_MEDIUM_PIC && (global || code))) > type = DW_EH_PE_sdata4; > @@ -23028,10 +23034,21 @@ ix86_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update) > static bool > ix86_binds_local_p (const_tree exp) > { > - return default_binds_local_p_3 (exp, flag_shlib != 0, true, true, > - (!flag_pic > - || (TARGET_64BIT > - && HAVE_LD_PIE_COPYRELOC != 0))); > + return default_binds_local_p_3 (exp, flag_shlib != 0, true, > + flag_direct_extern_access, > + (flag_direct_extern_access > + && (!flag_pic > + || (TARGET_64BIT > + && HAVE_LD_PIE_COPYRELOC != 0)))); > +} > + > +/* If flag_pic or flag_direct_extern_access is false, then neither > + local nor global relocs should be placed in readonly memory. */ > + > +static int > +ix86_reloc_rw_mask (void) > +{ > + return (flag_pic || !flag_direct_extern_access) ? 3 : 0; > } > #endif > > @@ -24071,6 +24088,11 @@ ix86_run_selftests (void) > #define TARGET_GET_MULTILIB_ABI_NAME \ > ix86_get_multilib_abi_name > > +#if !TARGET_MACHO && !TARGET_DLLIMPORT_DECL_ATTRIBUTES > +# undef TARGET_ASM_RELOC_RW_MASK > +# define TARGET_ASM_RELOC_RW_MASK ix86_reloc_rw_mask > +#endif > + > static bool ix86_libc_has_fast_function (int fcode ATTRIBUTE_UNUSED) > { > #ifdef OPTION_GLIBC > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi > index e67d47af676..2959c84cc3d 100644 > --- a/gcc/doc/invoke.texi > +++ b/gcc/doc/invoke.texi > @@ -658,6 +658,7 @@ Objective-C and Objective-C++ Dialects}. > -fnon-call-exceptions -fdelete-dead-exceptions -funwind-tables @gol > -fasynchronous-unwind-tables @gol > -fno-gnu-unique @gol > +-fno-direct-extern-access @gol > -finhibit-size-directive -fcommon -fno-ident @gol > -fpcc-struct-return -fpic -fPIC -fpie -fPIE -fno-plt @gol > -fno-jump-tables -fno-bit-tests @gol > @@ -16633,6 +16634,18 @@ through the PLT for specific external functions. > In position-dependent code, a few targets also convert calls to > functions that are marked to not use the PLT to use the GOT instead. > > +@item -fno-direct-extern-access > +@opindex fno-direct-extern-access > +@opindex fdirect-extern-access > +Without @option{-fpic} nor @option{-fPIC}, always use the GOT pointer > +to access external symbols. With @option{-fpic} or @option{-fPIC}, > +treat access to protected symbols as local symbols. > + > +@strong{Warning:} shared libraries compiled with > +@option{-fno-direct-extern-access} and executable compiled with > +@option{-fdirect-extern-access} may not be binary compatible if > +protected symbols are used in shared libraries and executable. > + > @item -fno-jump-tables > @opindex fno-jump-tables > @opindex fjump-tables > diff --git a/gcc/testsuite/g++.dg/pr35513-1.C b/gcc/testsuite/g++.dg/pr35513-1.C > new file mode 100644 > index 00000000000..8423e826da8 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/pr35513-1.C > @@ -0,0 +1,25 @@ > +// { dg-do run } > +// { dg-options "-O2 -fno-direct-extern-access" } > + > +#include <iostream> > + > +class Bug > +{ > +}; > + > +int throw_bug() > +{ > + throw Bug(); > + > + return 0; > +} > + > +int main() > +{ > + try { > + std::cout << throw_bug(); > + } catch (Bug bug) { > + }; > + > + return 0; > +} > diff --git a/gcc/testsuite/g++.dg/pr35513-2.C b/gcc/testsuite/g++.dg/pr35513-2.C > new file mode 100644 > index 00000000000..56ed19ae1eb > --- /dev/null > +++ b/gcc/testsuite/g++.dg/pr35513-2.C > @@ -0,0 +1,53 @@ > +// { dg-do run } > +// { dg-options "-O2 -fno-direct-extern-access" } > + > +class Foo > +{ > +public: > + Foo(int n) : n_(n) { } > + int f() { return n_; } > + > + int badTest(); > + int goodTest(); > + > +private: > + > + int n_; > +}; > + > +int Foo::badTest() > +{ > + try { > + throw int(99); > + } > + > + catch (int &i) { > + n_ = 16; > + } > + > + return n_; > +} > + > + > +int Foo::goodTest() > +{ > + int n; > + > + try { > + throw int(99); > + } > + > + catch (int &i) { > + n = 16; > + } > + > + return n_; > +} > + > +int main() > +{ > + Foo foo(5); > + foo.goodTest(); > + foo.badTest(); > + return 0; > +} > diff --git a/gcc/testsuite/gcc.target/i386/pr35513-1.c b/gcc/testsuite/gcc.target/i386/pr35513-1.c > new file mode 100644 > index 00000000000..c5dbabc3704 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/pr35513-1.c > @@ -0,0 +1,16 @@ > +/* { dg-do compile { target *-*-linux* } } */ > +/* { dg-options "-O2 -fno-pic -fno-direct-extern-access" } */ > + > +extern void bar (void); > +extern void *p; > + > +void > +foo (void) > +{ > + p = &bar; > +} > + > +/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT," { target { ia32 && got32x_reloc } } } } */ > +/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ia32 && got32x_reloc } } } } */ > diff --git a/gcc/testsuite/gcc.target/i386/pr35513-2.c b/gcc/testsuite/gcc.target/i386/pr35513-2.c > new file mode 100644 > index 00000000000..8bb7cb4c13d > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/pr35513-2.c > @@ -0,0 +1,15 @@ > +/* { dg-do compile { target *-*-linux* } } */ > +/* { dg-options "-O2 -fno-pic -fno-direct-extern-access" } */ > + > +extern int bar; > + > +int > +foo (void) > +{ > + return bar; > +} > + > +/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT," { target { ia32 && got32x_reloc } } } } */ > +/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ia32 && got32x_reloc } } } } */ > diff --git a/gcc/testsuite/gcc.target/i386/pr35513-3.c b/gcc/testsuite/gcc.target/i386/pr35513-3.c > new file mode 100644 > index 00000000000..98dc54e3bf4 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/pr35513-3.c > @@ -0,0 +1,15 @@ > +/* { dg-do compile { target *-*-linux* } } */ > +/* { dg-options "-O2 -fpie -fno-direct-extern-access" } */ > + > +extern int bar; > + > +int > +foo (void) > +{ > + return bar; > +} > + > +/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT" { target { ia32 && got32x_reloc } } } } */ > +/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ia32 && got32x_reloc } } } } */ > diff --git a/gcc/testsuite/gcc.target/i386/pr35513-4.c b/gcc/testsuite/gcc.target/i386/pr35513-4.c > new file mode 100644 > index 00000000000..467081dad65 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/pr35513-4.c > @@ -0,0 +1,15 @@ > +/* { dg-do compile { target *-*-linux* } } */ > +/* { dg-options "-O2 -fplt -fno-pic -fno-direct-extern-access" } */ > + > +extern void foo (void); > + > +int > +bar (void) > +{ > + foo (); > + return 0; > +} > + > +/* { dg-final { scan-assembler "call\[ \t\]*foo" } } */ > +/* { dg-final { scan-assembler-not "foo@GOTPCREL" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "foo@GOT" { target ia32 } } } */ > diff --git a/gcc/testsuite/gcc.target/i386/pr35513-5.c b/gcc/testsuite/gcc.target/i386/pr35513-5.c > new file mode 100644 > index 00000000000..b0e61b08ba9 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/pr35513-5.c > @@ -0,0 +1,15 @@ > +/* { dg-do compile { target *-*-linux* } } */ > +/* { dg-options "-O2 -fplt -fpic -fno-direct-extern-access" } */ > + > +extern void foo (void); > + > +int > +bar (void) > +{ > + foo (); > + return 0; > +} > + > +/* { dg-final { scan-assembler "call\[ \t\]*foo@PLT" } } */ > +/* { dg-final { scan-assembler-not "foo@GOTPCREL" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "foo@GOT" { target ia32 } } } */ > diff --git a/gcc/testsuite/gcc.target/i386/pr35513-6.c b/gcc/testsuite/gcc.target/i386/pr35513-6.c > new file mode 100644 > index 00000000000..270504b8d0e > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/pr35513-6.c > @@ -0,0 +1,14 @@ > +/* { dg-do compile { target *-*-linux* } } */ > +/* { dg-options "-O2 -fplt -fno-pic -fno-direct-extern-access" } */ > + > +extern void foo (void); > + > +void > +bar (void) > +{ > + foo (); > +} > + > +/* { dg-final { scan-assembler "jmp\[ \t\]*foo" } } */ > +/* { dg-final { scan-assembler-not "foo@GOTPCREL" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "foo@GOT" { target ia32 } } } */ > diff --git a/gcc/testsuite/gcc.target/i386/pr35513-7.c b/gcc/testsuite/gcc.target/i386/pr35513-7.c > new file mode 100644 > index 00000000000..2c5a83ddef8 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/pr35513-7.c > @@ -0,0 +1,15 @@ > +/* { dg-do compile { target *-*-linux* } } */ > +/* { dg-options "-O2 -fplt -fpic -fno-direct-extern-access" } */ > + > +extern void foo (void); > + > +void > +bar (void) > +{ > + foo (); > +} > + > +/* { dg-final { scan-assembler "jmp\[ \t\]*foo@PLT" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler "call\[ \t\]*foo@PLT" { target ia32 } } } */ > +/* { dg-final { scan-assembler-not "foo@GOTPCREL" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "foo@GOT" { target ia32 } } } */ > diff --git a/gcc/testsuite/gcc.target/i386/pr35513-8.c b/gcc/testsuite/gcc.target/i386/pr35513-8.c > new file mode 100644 > index 00000000000..545979e99c2 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/pr35513-8.c > @@ -0,0 +1,41 @@ > +/* { dg-do assemble { target { *-*-linux* && { ! ia32 } } } } */ > +/* { dg-require-effective-target maybe_x32 } */ > +/* { dg-options "-mx32 -O2 -fno-pic -fexceptions -fasynchronous-unwind-tables -fno-direct-extern-access" } */ > + > +extern int foo (int); > +extern void exit (int __status) __attribute__ ((__nothrow__ )) __attribute__ ((__noreturn__)); > +struct __pthread_cleanup_frame > +{ > + void (*__cancel_routine) (void *); > + void *__cancel_arg; > + int __do_it; > + int __cancel_type; > +}; > +extern __inline void > +__pthread_cleanup_routine (struct __pthread_cleanup_frame *__frame) > +{ > + if (__frame->__do_it) > + __frame->__cancel_routine (__frame->__cancel_arg); > +} > +static int cl_called; > + > +static void > +cl (void *arg) > +{ > + ++cl_called; > +} > + > + > +void * > +tf_usleep (void *arg) > +{ > + > + do { struct __pthread_cleanup_frame __clframe __attribute__ ((__cleanup__ (__pthread_cleanup_routine))) = { .__cancel_routine = (cl), .__cancel_arg = ( > + ((void *)0)), .__do_it = 1 };; > + > + foo (arg == ((void *)0) ? (0x7fffffffL * 2UL + 1UL) : 0); > + > + __clframe.__do_it = (0); } while (0); > + > + exit (1); > +} > -- > 2.31.1 >
> diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c > index cff26909292..7dee311051d 100644 > --- a/gcc/config/i386/i386.c > +++ b/gcc/config/i386/i386.c > @@ -10312,13 +10312,17 @@ darwin_local_data_pic (rtx disp) > } > > /* True if the function symbol operand X should be loaded from GOT. > + If CALL_P is true, X is a call operand. > + > + NB: -fno-direct-extern-access doesn't force load from GOT for > + call. > > NB: In 32-bit mode, only non-PIC is allowed in inline assembly > statements, since a PIC register could not be available at the > call site. */ > > bool > -ix86_force_load_from_GOT_p (rtx x) > +ix86_force_load_from_GOT_p (rtx x, bool call_p) > { > return ((TARGET_64BIT || (!flag_pic && HAVE_AS_IX86_GOT32X)) > && !TARGET_PECOFF && !TARGET_MACHO > @@ -10326,11 +10330,12 @@ ix86_force_load_from_GOT_p (rtx x) > && ix86_cmodel != CM_LARGE > && ix86_cmodel != CM_LARGE_PIC > && GET_CODE (x) == SYMBOL_REF > - && SYMBOL_REF_FUNCTION_P (x) > - && (!flag_plt > - || (SYMBOL_REF_DECL (x) > - && lookup_attribute ("noplt", > - DECL_ATTRIBUTES (SYMBOL_REF_DECL (x))))) > + && ((!call_p && !flag_direct_extern_access) > + || (SYMBOL_REF_FUNCTION_P (x) > + && (!flag_plt > + || (SYMBOL_REF_DECL (x) > + && lookup_attribute ("noplt", > + DECL_ATTRIBUTES (SYMBOL_REF_DECL (x))))))) > && !SYMBOL_REF_LOCAL_P (x)); > } > > @@ -10596,7 +10601,8 @@ legitimate_pic_address_disp_p (rtx disp) > } > else if (!SYMBOL_REF_FAR_ADDR_P (op0) > && (SYMBOL_REF_LOCAL_P (op0) > - || (HAVE_LD_PIE_COPYRELOC > + || (flag_direct_extern_access > + && HAVE_LD_PIE_COPYRELOC > && flag_pie > && !SYMBOL_REF_WEAK (op0) > && !SYMBOL_REF_FUNCTION_P (op0))) > @@ -13498,7 +13504,7 @@ ix86_print_operand (FILE *file, rtx x, int code) > > if (code == 'P') > { > - if (ix86_force_load_from_GOT_p (x)) > + if (ix86_force_load_from_GOT_p (x, true)) > { > /* For inline assembly statement, load function address > from GOT with 'P' operand modifier to avoid PLT. */ > @@ -21935,10 +21941,10 @@ int > asm_preferred_eh_data_format (int code, int global) > { > /* PE-COFF is effectively always -fPIC because of the .reloc section. */ > - if (flag_pic || TARGET_PECOFF) > + if (flag_pic || TARGET_PECOFF || !flag_direct_extern_access) > { > int type = DW_EH_PE_sdata8; > - if (!TARGET_64BIT > + if (ptr_mode == SImode > || ix86_cmodel == CM_SMALL_PIC > || (ix86_cmodel == CM_MEDIUM_PIC && (global || code))) > type = DW_EH_PE_sdata4; > @@ -23028,10 +23034,21 @@ ix86_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update) > static bool > ix86_binds_local_p (const_tree exp) > { > - return default_binds_local_p_3 (exp, flag_shlib != 0, true, true, > - (!flag_pic > - || (TARGET_64BIT > - && HAVE_LD_PIE_COPYRELOC != 0))); > + return default_binds_local_p_3 (exp, flag_shlib != 0, true, > + flag_direct_extern_access, > + (flag_direct_extern_access > + && (!flag_pic > + || (TARGET_64BIT > + && HAVE_LD_PIE_COPYRELOC != 0)))); > +} Hope we can get rid of HAVE_LD_PIE_COPYRELOC unconditionally, probably separately. Patch is here: https://gcc.gnu.org/pipermail/gcc-patches/2021-May/570139.html
On Sun, Jul 11, 2021 at 11:13 PM Richard Biener <richard.guenther@gmail.com> wrote: > > On Fri, Jul 9, 2021 at 4:50 PM H.J. Lu <hjl.tools@gmail.com> wrote: > > > > -fdirect-extern-access is the default. With -fno-direct-extern-access: > > > > 1. Always use GOT to access undefined data and function symbols, > > including in PIE and non-PIE. These will avoid copy relocations > > in executables. This is compatible with existing executables and > > shared libraries. > > 2. In executable and shared library, bind symbols with the STV_PROTECTED > > visibility locally: > > a. The address of data symbol is the address of data body. > > b. For systems without function descriptor, the function pointer is > > the address of function body. > > c. The resulting shared libraries may not be incompatible with > > executables which have copy relocations on protected symbols or > > use executable PLT entries as function addresses for protected > > functions in shared libraries. > > 3. Update asm_preferred_eh_data_format to select PC relative EH encoding > > format with -fno-direct-extern-access to avoid copy relocation. > > 4. Add ix86_reloc_rw_mask for TARGET_ASM_RELOC_RW_MASK to avoid copy > > relocation with -fno-direct-extern-access. > > Did you check how relocations in .debug_info behave? I don't remember whether Yes, I did. I added ix86_reloc_rw_mask and use PC-relative format for EH pointer encodings to avoid copy relocation for -fno-direct-extern-access in read-only sections. > we're doing anything special there or if we just copy how we emit > relocs in .text > > Richard. > > > gcc/ > > > > PR target/35513 > > PR target/100593 > > * common.opt: Add -fdirect-extern-access. > > * config/i386/i386-protos.h (ix86_force_load_from_GOT_p): Add a > > bool argument. > > * config/i386/i386.c (ix86_force_load_from_GOT_p): Add a bool > > argument to indicate call operand. Force non-call load > > from GOT for -fno-direct-extern-access. > > (legitimate_pic_address_disp_p): Avoid copy relocation in PIE > > for -fno-direct-extern-access. > > (ix86_print_operand): Pass true to ix86_force_load_from_GOT_p > > for call operand. > > (asm_preferred_eh_data_format): Use PC-relative format for > > -fno-direct-extern-access to avoid copy relocation. Check > > ptr_mode instead of TARGET_64BIT when selecting DW_EH_PE_sdata4. > > (ix86_binds_local_p): Don't treat protected data as extern and > > avoid copy relocation on common symbol with > > -fno-direct-extern-access. > > (ix86_reloc_rw_mask): New to avoid copy relocation for > > -fno-direct-extern-access. > > (TARGET_ASM_RELOC_RW_MASK): New. > > * doc/invoke.texi: Document -f[no-]direct-extern-access. > > > > gcc/testsuite/ > > > > PR target/35513 > > PR target/100593 > > * g++.dg/pr35513-1.C: New file. > > * g++.dg/pr35513-2.C: Likewise. > > * gcc.target/i386/pr35513-1.c: Likewise. > > * gcc.target/i386/pr35513-2.c: Likewise. > > * gcc.target/i386/pr35513-3.c: Likewise. > > * gcc.target/i386/pr35513-4.c: Likewise. > > * gcc.target/i386/pr35513-5.c: Likewise. > > * gcc.target/i386/pr35513-6.c: Likewise. > > * gcc.target/i386/pr35513-7.c: Likewise. > > * gcc.target/i386/pr35513-8.c: Likewise. > > --- > > gcc/common.opt | 4 ++ > > gcc/config/i386/i386-protos.h | 2 +- > > gcc/config/i386/i386.c | 50 +++++++++++++++------ > > gcc/doc/invoke.texi | 13 ++++++ > > gcc/testsuite/g++.dg/pr35513-1.C | 25 +++++++++++ > > gcc/testsuite/g++.dg/pr35513-2.C | 53 +++++++++++++++++++++++ > > gcc/testsuite/gcc.target/i386/pr35513-1.c | 16 +++++++ > > gcc/testsuite/gcc.target/i386/pr35513-2.c | 15 +++++++ > > gcc/testsuite/gcc.target/i386/pr35513-3.c | 15 +++++++ > > gcc/testsuite/gcc.target/i386/pr35513-4.c | 15 +++++++ > > gcc/testsuite/gcc.target/i386/pr35513-5.c | 15 +++++++ > > gcc/testsuite/gcc.target/i386/pr35513-6.c | 14 ++++++ > > gcc/testsuite/gcc.target/i386/pr35513-7.c | 15 +++++++ > > gcc/testsuite/gcc.target/i386/pr35513-8.c | 41 ++++++++++++++++++ > > 14 files changed, 278 insertions(+), 15 deletions(-) > > create mode 100644 gcc/testsuite/g++.dg/pr35513-1.C > > create mode 100644 gcc/testsuite/g++.dg/pr35513-2.C > > create mode 100644 gcc/testsuite/gcc.target/i386/pr35513-1.c > > create mode 100644 gcc/testsuite/gcc.target/i386/pr35513-2.c > > create mode 100644 gcc/testsuite/gcc.target/i386/pr35513-3.c > > create mode 100644 gcc/testsuite/gcc.target/i386/pr35513-4.c > > create mode 100644 gcc/testsuite/gcc.target/i386/pr35513-5.c > > create mode 100644 gcc/testsuite/gcc.target/i386/pr35513-6.c > > create mode 100644 gcc/testsuite/gcc.target/i386/pr35513-7.c > > create mode 100644 gcc/testsuite/gcc.target/i386/pr35513-8.c > > > > diff --git a/gcc/common.opt b/gcc/common.opt > > index d9da1131eda..67ad811d54d 100644 > > --- a/gcc/common.opt > > +++ b/gcc/common.opt > > @@ -1432,6 +1432,10 @@ fdiagnostics-minimum-margin-width= > > Common Joined UInteger Var(diagnostics_minimum_margin_width) Init(6) > > Set minimum width of left margin of source code when showing source. > > > > +fdirect-extern-access > > +Common Var(flag_direct_extern_access) Init(1) Optimization > > +Do not use GOT to access external symbols. > > + > > fdisable- > > Common Joined RejectNegative Var(common_deferred_options) Defer > > -fdisable-[tree|rtl|ipa]-<pass>=range1+range2 Disable an optimization pass. > > diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h > > index 51376fcc454..693cc3e5c78 100644 > > --- a/gcc/config/i386/i386-protos.h > > +++ b/gcc/config/i386/i386-protos.h > > @@ -79,7 +79,7 @@ extern bool ix86_expand_cmpstrn_or_cmpmem (rtx, rtx, rtx, rtx, rtx, bool); > > extern bool constant_address_p (rtx); > > extern bool legitimate_pic_operand_p (rtx); > > extern bool legitimate_pic_address_disp_p (rtx); > > -extern bool ix86_force_load_from_GOT_p (rtx); > > +extern bool ix86_force_load_from_GOT_p (rtx, bool = false); > > extern void print_reg (rtx, int, FILE*); > > extern void ix86_print_operand (FILE *, rtx, int); > > > > diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c > > index cff26909292..7dee311051d 100644 > > --- a/gcc/config/i386/i386.c > > +++ b/gcc/config/i386/i386.c > > @@ -10312,13 +10312,17 @@ darwin_local_data_pic (rtx disp) > > } > > > > /* True if the function symbol operand X should be loaded from GOT. > > + If CALL_P is true, X is a call operand. > > + > > + NB: -fno-direct-extern-access doesn't force load from GOT for > > + call. > > > > NB: In 32-bit mode, only non-PIC is allowed in inline assembly > > statements, since a PIC register could not be available at the > > call site. */ > > > > bool > > -ix86_force_load_from_GOT_p (rtx x) > > +ix86_force_load_from_GOT_p (rtx x, bool call_p) > > { > > return ((TARGET_64BIT || (!flag_pic && HAVE_AS_IX86_GOT32X)) > > && !TARGET_PECOFF && !TARGET_MACHO > > @@ -10326,11 +10330,12 @@ ix86_force_load_from_GOT_p (rtx x) > > && ix86_cmodel != CM_LARGE > > && ix86_cmodel != CM_LARGE_PIC > > && GET_CODE (x) == SYMBOL_REF > > - && SYMBOL_REF_FUNCTION_P (x) > > - && (!flag_plt > > - || (SYMBOL_REF_DECL (x) > > - && lookup_attribute ("noplt", > > - DECL_ATTRIBUTES (SYMBOL_REF_DECL (x))))) > > + && ((!call_p && !flag_direct_extern_access) > > + || (SYMBOL_REF_FUNCTION_P (x) > > + && (!flag_plt > > + || (SYMBOL_REF_DECL (x) > > + && lookup_attribute ("noplt", > > + DECL_ATTRIBUTES (SYMBOL_REF_DECL (x))))))) > > && !SYMBOL_REF_LOCAL_P (x)); > > } > > > > @@ -10596,7 +10601,8 @@ legitimate_pic_address_disp_p (rtx disp) > > } > > else if (!SYMBOL_REF_FAR_ADDR_P (op0) > > && (SYMBOL_REF_LOCAL_P (op0) > > - || (HAVE_LD_PIE_COPYRELOC > > + || (flag_direct_extern_access > > + && HAVE_LD_PIE_COPYRELOC > > && flag_pie > > && !SYMBOL_REF_WEAK (op0) > > && !SYMBOL_REF_FUNCTION_P (op0))) > > @@ -13498,7 +13504,7 @@ ix86_print_operand (FILE *file, rtx x, int code) > > > > if (code == 'P') > > { > > - if (ix86_force_load_from_GOT_p (x)) > > + if (ix86_force_load_from_GOT_p (x, true)) > > { > > /* For inline assembly statement, load function address > > from GOT with 'P' operand modifier to avoid PLT. */ > > @@ -21935,10 +21941,10 @@ int > > asm_preferred_eh_data_format (int code, int global) > > { > > /* PE-COFF is effectively always -fPIC because of the .reloc section. */ > > - if (flag_pic || TARGET_PECOFF) > > + if (flag_pic || TARGET_PECOFF || !flag_direct_extern_access) > > { > > int type = DW_EH_PE_sdata8; > > - if (!TARGET_64BIT > > + if (ptr_mode == SImode > > || ix86_cmodel == CM_SMALL_PIC > > || (ix86_cmodel == CM_MEDIUM_PIC && (global || code))) > > type = DW_EH_PE_sdata4; > > @@ -23028,10 +23034,21 @@ ix86_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update) > > static bool > > ix86_binds_local_p (const_tree exp) > > { > > - return default_binds_local_p_3 (exp, flag_shlib != 0, true, true, > > - (!flag_pic > > - || (TARGET_64BIT > > - && HAVE_LD_PIE_COPYRELOC != 0))); > > + return default_binds_local_p_3 (exp, flag_shlib != 0, true, > > + flag_direct_extern_access, > > + (flag_direct_extern_access > > + && (!flag_pic > > + || (TARGET_64BIT > > + && HAVE_LD_PIE_COPYRELOC != 0)))); > > +} > > + > > +/* If flag_pic or flag_direct_extern_access is false, then neither > > + local nor global relocs should be placed in readonly memory. */ > > + > > +static int > > +ix86_reloc_rw_mask (void) > > +{ > > + return (flag_pic || !flag_direct_extern_access) ? 3 : 0; > > } > > #endif > > > > @@ -24071,6 +24088,11 @@ ix86_run_selftests (void) > > #define TARGET_GET_MULTILIB_ABI_NAME \ > > ix86_get_multilib_abi_name > > > > +#if !TARGET_MACHO && !TARGET_DLLIMPORT_DECL_ATTRIBUTES > > +# undef TARGET_ASM_RELOC_RW_MASK > > +# define TARGET_ASM_RELOC_RW_MASK ix86_reloc_rw_mask > > +#endif > > + > > static bool ix86_libc_has_fast_function (int fcode ATTRIBUTE_UNUSED) > > { > > #ifdef OPTION_GLIBC > > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi > > index e67d47af676..2959c84cc3d 100644 > > --- a/gcc/doc/invoke.texi > > +++ b/gcc/doc/invoke.texi > > @@ -658,6 +658,7 @@ Objective-C and Objective-C++ Dialects}. > > -fnon-call-exceptions -fdelete-dead-exceptions -funwind-tables @gol > > -fasynchronous-unwind-tables @gol > > -fno-gnu-unique @gol > > +-fno-direct-extern-access @gol > > -finhibit-size-directive -fcommon -fno-ident @gol > > -fpcc-struct-return -fpic -fPIC -fpie -fPIE -fno-plt @gol > > -fno-jump-tables -fno-bit-tests @gol > > @@ -16633,6 +16634,18 @@ through the PLT for specific external functions. > > In position-dependent code, a few targets also convert calls to > > functions that are marked to not use the PLT to use the GOT instead. > > > > +@item -fno-direct-extern-access > > +@opindex fno-direct-extern-access > > +@opindex fdirect-extern-access > > +Without @option{-fpic} nor @option{-fPIC}, always use the GOT pointer > > +to access external symbols. With @option{-fpic} or @option{-fPIC}, > > +treat access to protected symbols as local symbols. > > + > > +@strong{Warning:} shared libraries compiled with > > +@option{-fno-direct-extern-access} and executable compiled with > > +@option{-fdirect-extern-access} may not be binary compatible if > > +protected symbols are used in shared libraries and executable. > > + > > @item -fno-jump-tables > > @opindex fno-jump-tables > > @opindex fjump-tables > > diff --git a/gcc/testsuite/g++.dg/pr35513-1.C b/gcc/testsuite/g++.dg/pr35513-1.C > > new file mode 100644 > > index 00000000000..8423e826da8 > > --- /dev/null > > +++ b/gcc/testsuite/g++.dg/pr35513-1.C > > @@ -0,0 +1,25 @@ > > +// { dg-do run } > > +// { dg-options "-O2 -fno-direct-extern-access" } > > + > > +#include <iostream> > > + > > +class Bug > > +{ > > +}; > > + > > +int throw_bug() > > +{ > > + throw Bug(); > > + > > + return 0; > > +} > > + > > +int main() > > +{ > > + try { > > + std::cout << throw_bug(); > > + } catch (Bug bug) { > > + }; > > + > > + return 0; > > +} > > diff --git a/gcc/testsuite/g++.dg/pr35513-2.C b/gcc/testsuite/g++.dg/pr35513-2.C > > new file mode 100644 > > index 00000000000..56ed19ae1eb > > --- /dev/null > > +++ b/gcc/testsuite/g++.dg/pr35513-2.C > > @@ -0,0 +1,53 @@ > > +// { dg-do run } > > +// { dg-options "-O2 -fno-direct-extern-access" } > > + > > +class Foo > > +{ > > +public: > > + Foo(int n) : n_(n) { } > > + int f() { return n_; } > > + > > + int badTest(); > > + int goodTest(); > > + > > +private: > > + > > + int n_; > > +}; > > + > > +int Foo::badTest() > > +{ > > + try { > > + throw int(99); > > + } > > + > > + catch (int &i) { > > + n_ = 16; > > + } > > + > > + return n_; > > +} > > + > > + > > +int Foo::goodTest() > > +{ > > + int n; > > + > > + try { > > + throw int(99); > > + } > > + > > + catch (int &i) { > > + n = 16; > > + } > > + > > + return n_; > > +} > > + > > +int main() > > +{ > > + Foo foo(5); > > + foo.goodTest(); > > + foo.badTest(); > > + return 0; > > +} > > diff --git a/gcc/testsuite/gcc.target/i386/pr35513-1.c b/gcc/testsuite/gcc.target/i386/pr35513-1.c > > new file mode 100644 > > index 00000000000..c5dbabc3704 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/i386/pr35513-1.c > > @@ -0,0 +1,16 @@ > > +/* { dg-do compile { target *-*-linux* } } */ > > +/* { dg-options "-O2 -fno-pic -fno-direct-extern-access" } */ > > + > > +extern void bar (void); > > +extern void *p; > > + > > +void > > +foo (void) > > +{ > > + p = &bar; > > +} > > + > > +/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */ > > +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT," { target { ia32 && got32x_reloc } } } } */ > > +/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ! ia32 } } } } */ > > +/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ia32 && got32x_reloc } } } } */ > > diff --git a/gcc/testsuite/gcc.target/i386/pr35513-2.c b/gcc/testsuite/gcc.target/i386/pr35513-2.c > > new file mode 100644 > > index 00000000000..8bb7cb4c13d > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/i386/pr35513-2.c > > @@ -0,0 +1,15 @@ > > +/* { dg-do compile { target *-*-linux* } } */ > > +/* { dg-options "-O2 -fno-pic -fno-direct-extern-access" } */ > > + > > +extern int bar; > > + > > +int > > +foo (void) > > +{ > > + return bar; > > +} > > + > > +/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */ > > +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT," { target { ia32 && got32x_reloc } } } } */ > > +/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ! ia32 } } } } */ > > +/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ia32 && got32x_reloc } } } } */ > > diff --git a/gcc/testsuite/gcc.target/i386/pr35513-3.c b/gcc/testsuite/gcc.target/i386/pr35513-3.c > > new file mode 100644 > > index 00000000000..98dc54e3bf4 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/i386/pr35513-3.c > > @@ -0,0 +1,15 @@ > > +/* { dg-do compile { target *-*-linux* } } */ > > +/* { dg-options "-O2 -fpie -fno-direct-extern-access" } */ > > + > > +extern int bar; > > + > > +int > > +foo (void) > > +{ > > + return bar; > > +} > > + > > +/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */ > > +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT" { target { ia32 && got32x_reloc } } } } */ > > +/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ! ia32 } } } } */ > > +/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ia32 && got32x_reloc } } } } */ > > diff --git a/gcc/testsuite/gcc.target/i386/pr35513-4.c b/gcc/testsuite/gcc.target/i386/pr35513-4.c > > new file mode 100644 > > index 00000000000..467081dad65 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/i386/pr35513-4.c > > @@ -0,0 +1,15 @@ > > +/* { dg-do compile { target *-*-linux* } } */ > > +/* { dg-options "-O2 -fplt -fno-pic -fno-direct-extern-access" } */ > > + > > +extern void foo (void); > > + > > +int > > +bar (void) > > +{ > > + foo (); > > + return 0; > > +} > > + > > +/* { dg-final { scan-assembler "call\[ \t\]*foo" } } */ > > +/* { dg-final { scan-assembler-not "foo@GOTPCREL" { target { ! ia32 } } } } */ > > +/* { dg-final { scan-assembler-not "foo@GOT" { target ia32 } } } */ > > diff --git a/gcc/testsuite/gcc.target/i386/pr35513-5.c b/gcc/testsuite/gcc.target/i386/pr35513-5.c > > new file mode 100644 > > index 00000000000..b0e61b08ba9 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/i386/pr35513-5.c > > @@ -0,0 +1,15 @@ > > +/* { dg-do compile { target *-*-linux* } } */ > > +/* { dg-options "-O2 -fplt -fpic -fno-direct-extern-access" } */ > > + > > +extern void foo (void); > > + > > +int > > +bar (void) > > +{ > > + foo (); > > + return 0; > > +} > > + > > +/* { dg-final { scan-assembler "call\[ \t\]*foo@PLT" } } */ > > +/* { dg-final { scan-assembler-not "foo@GOTPCREL" { target { ! ia32 } } } } */ > > +/* { dg-final { scan-assembler-not "foo@GOT" { target ia32 } } } */ > > diff --git a/gcc/testsuite/gcc.target/i386/pr35513-6.c b/gcc/testsuite/gcc.target/i386/pr35513-6.c > > new file mode 100644 > > index 00000000000..270504b8d0e > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/i386/pr35513-6.c > > @@ -0,0 +1,14 @@ > > +/* { dg-do compile { target *-*-linux* } } */ > > +/* { dg-options "-O2 -fplt -fno-pic -fno-direct-extern-access" } */ > > + > > +extern void foo (void); > > + > > +void > > +bar (void) > > +{ > > + foo (); > > +} > > + > > +/* { dg-final { scan-assembler "jmp\[ \t\]*foo" } } */ > > +/* { dg-final { scan-assembler-not "foo@GOTPCREL" { target { ! ia32 } } } } */ > > +/* { dg-final { scan-assembler-not "foo@GOT" { target ia32 } } } */ > > diff --git a/gcc/testsuite/gcc.target/i386/pr35513-7.c b/gcc/testsuite/gcc.target/i386/pr35513-7.c > > new file mode 100644 > > index 00000000000..2c5a83ddef8 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/i386/pr35513-7.c > > @@ -0,0 +1,15 @@ > > +/* { dg-do compile { target *-*-linux* } } */ > > +/* { dg-options "-O2 -fplt -fpic -fno-direct-extern-access" } */ > > + > > +extern void foo (void); > > + > > +void > > +bar (void) > > +{ > > + foo (); > > +} > > + > > +/* { dg-final { scan-assembler "jmp\[ \t\]*foo@PLT" { target { ! ia32 } } } } */ > > +/* { dg-final { scan-assembler "call\[ \t\]*foo@PLT" { target ia32 } } } */ > > +/* { dg-final { scan-assembler-not "foo@GOTPCREL" { target { ! ia32 } } } } */ > > +/* { dg-final { scan-assembler-not "foo@GOT" { target ia32 } } } */ > > diff --git a/gcc/testsuite/gcc.target/i386/pr35513-8.c b/gcc/testsuite/gcc.target/i386/pr35513-8.c > > new file mode 100644 > > index 00000000000..545979e99c2 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/i386/pr35513-8.c > > @@ -0,0 +1,41 @@ > > +/* { dg-do assemble { target { *-*-linux* && { ! ia32 } } } } */ > > +/* { dg-require-effective-target maybe_x32 } */ > > +/* { dg-options "-mx32 -O2 -fno-pic -fexceptions -fasynchronous-unwind-tables -fno-direct-extern-access" } */ > > + > > +extern int foo (int); > > +extern void exit (int __status) __attribute__ ((__nothrow__ )) __attribute__ ((__noreturn__)); > > +struct __pthread_cleanup_frame > > +{ > > + void (*__cancel_routine) (void *); > > + void *__cancel_arg; > > + int __do_it; > > + int __cancel_type; > > +}; > > +extern __inline void > > +__pthread_cleanup_routine (struct __pthread_cleanup_frame *__frame) > > +{ > > + if (__frame->__do_it) > > + __frame->__cancel_routine (__frame->__cancel_arg); > > +} > > +static int cl_called; > > + > > +static void > > +cl (void *arg) > > +{ > > + ++cl_called; > > +} > > + > > + > > +void * > > +tf_usleep (void *arg) > > +{ > > + > > + do { struct __pthread_cleanup_frame __clframe __attribute__ ((__cleanup__ (__pthread_cleanup_routine))) = { .__cancel_routine = (cl), .__cancel_arg = ( > > + ((void *)0)), .__do_it = 1 };; > > + > > + foo (arg == ((void *)0) ? (0x7fffffffL * 2UL + 1UL) : 0); > > + > > + __clframe.__do_it = (0); } while (0); > > + > > + exit (1); > > +} > > -- > > 2.31.1 > >
On Mon, Jul 12, 2021 at 5:13 AM H.J. Lu <hjl.tools@gmail.com> wrote: > > On Sun, Jul 11, 2021 at 11:13 PM Richard Biener > <richard.guenther@gmail.com> wrote: > > > > On Fri, Jul 9, 2021 at 4:50 PM H.J. Lu <hjl.tools@gmail.com> wrote: > > > > > > -fdirect-extern-access is the default. With -fno-direct-extern-access: > > > > > > 1. Always use GOT to access undefined data and function symbols, > > > including in PIE and non-PIE. These will avoid copy relocations > > > in executables. This is compatible with existing executables and > > > shared libraries. > > > 2. In executable and shared library, bind symbols with the STV_PROTECTED > > > visibility locally: > > > a. The address of data symbol is the address of data body. > > > b. For systems without function descriptor, the function pointer is > > > the address of function body. > > > c. The resulting shared libraries may not be incompatible with > > > executables which have copy relocations on protected symbols or > > > use executable PLT entries as function addresses for protected > > > functions in shared libraries. > > > 3. Update asm_preferred_eh_data_format to select PC relative EH encoding > > > format with -fno-direct-extern-access to avoid copy relocation. > > > 4. Add ix86_reloc_rw_mask for TARGET_ASM_RELOC_RW_MASK to avoid copy > > > relocation with -fno-direct-extern-access. > > > > Did you check how relocations in .debug_info behave? I don't remember whether > > Yes, I did. I added ix86_reloc_rw_mask and use PC-relative format for > EH pointer encodings to avoid copy relocation for -fno-direct-extern-access > in read-only sections. PING: https://gcc.gnu.org/pipermail/gcc-patches/2021-July/574846.html > > we're doing anything special there or if we just copy how we emit > > relocs in .text > > > > Richard.
diff --git a/gcc/common.opt b/gcc/common.opt index d9da1131eda..67ad811d54d 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -1432,6 +1432,10 @@ fdiagnostics-minimum-margin-width= Common Joined UInteger Var(diagnostics_minimum_margin_width) Init(6) Set minimum width of left margin of source code when showing source. +fdirect-extern-access +Common Var(flag_direct_extern_access) Init(1) Optimization +Do not use GOT to access external symbols. + fdisable- Common Joined RejectNegative Var(common_deferred_options) Defer -fdisable-[tree|rtl|ipa]-<pass>=range1+range2 Disable an optimization pass. diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h index 51376fcc454..693cc3e5c78 100644 --- a/gcc/config/i386/i386-protos.h +++ b/gcc/config/i386/i386-protos.h @@ -79,7 +79,7 @@ extern bool ix86_expand_cmpstrn_or_cmpmem (rtx, rtx, rtx, rtx, rtx, bool); extern bool constant_address_p (rtx); extern bool legitimate_pic_operand_p (rtx); extern bool legitimate_pic_address_disp_p (rtx); -extern bool ix86_force_load_from_GOT_p (rtx); +extern bool ix86_force_load_from_GOT_p (rtx, bool = false); extern void print_reg (rtx, int, FILE*); extern void ix86_print_operand (FILE *, rtx, int); diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index cff26909292..7dee311051d 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -10312,13 +10312,17 @@ darwin_local_data_pic (rtx disp) } /* True if the function symbol operand X should be loaded from GOT. + If CALL_P is true, X is a call operand. + + NB: -fno-direct-extern-access doesn't force load from GOT for + call. NB: In 32-bit mode, only non-PIC is allowed in inline assembly statements, since a PIC register could not be available at the call site. */ bool -ix86_force_load_from_GOT_p (rtx x) +ix86_force_load_from_GOT_p (rtx x, bool call_p) { return ((TARGET_64BIT || (!flag_pic && HAVE_AS_IX86_GOT32X)) && !TARGET_PECOFF && !TARGET_MACHO @@ -10326,11 +10330,12 @@ ix86_force_load_from_GOT_p (rtx x) && ix86_cmodel != CM_LARGE && ix86_cmodel != CM_LARGE_PIC && GET_CODE (x) == SYMBOL_REF - && SYMBOL_REF_FUNCTION_P (x) - && (!flag_plt - || (SYMBOL_REF_DECL (x) - && lookup_attribute ("noplt", - DECL_ATTRIBUTES (SYMBOL_REF_DECL (x))))) + && ((!call_p && !flag_direct_extern_access) + || (SYMBOL_REF_FUNCTION_P (x) + && (!flag_plt + || (SYMBOL_REF_DECL (x) + && lookup_attribute ("noplt", + DECL_ATTRIBUTES (SYMBOL_REF_DECL (x))))))) && !SYMBOL_REF_LOCAL_P (x)); } @@ -10596,7 +10601,8 @@ legitimate_pic_address_disp_p (rtx disp) } else if (!SYMBOL_REF_FAR_ADDR_P (op0) && (SYMBOL_REF_LOCAL_P (op0) - || (HAVE_LD_PIE_COPYRELOC + || (flag_direct_extern_access + && HAVE_LD_PIE_COPYRELOC && flag_pie && !SYMBOL_REF_WEAK (op0) && !SYMBOL_REF_FUNCTION_P (op0))) @@ -13498,7 +13504,7 @@ ix86_print_operand (FILE *file, rtx x, int code) if (code == 'P') { - if (ix86_force_load_from_GOT_p (x)) + if (ix86_force_load_from_GOT_p (x, true)) { /* For inline assembly statement, load function address from GOT with 'P' operand modifier to avoid PLT. */ @@ -21935,10 +21941,10 @@ int asm_preferred_eh_data_format (int code, int global) { /* PE-COFF is effectively always -fPIC because of the .reloc section. */ - if (flag_pic || TARGET_PECOFF) + if (flag_pic || TARGET_PECOFF || !flag_direct_extern_access) { int type = DW_EH_PE_sdata8; - if (!TARGET_64BIT + if (ptr_mode == SImode || ix86_cmodel == CM_SMALL_PIC || (ix86_cmodel == CM_MEDIUM_PIC && (global || code))) type = DW_EH_PE_sdata4; @@ -23028,10 +23034,21 @@ ix86_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update) static bool ix86_binds_local_p (const_tree exp) { - return default_binds_local_p_3 (exp, flag_shlib != 0, true, true, - (!flag_pic - || (TARGET_64BIT - && HAVE_LD_PIE_COPYRELOC != 0))); + return default_binds_local_p_3 (exp, flag_shlib != 0, true, + flag_direct_extern_access, + (flag_direct_extern_access + && (!flag_pic + || (TARGET_64BIT + && HAVE_LD_PIE_COPYRELOC != 0)))); +} + +/* If flag_pic or flag_direct_extern_access is false, then neither + local nor global relocs should be placed in readonly memory. */ + +static int +ix86_reloc_rw_mask (void) +{ + return (flag_pic || !flag_direct_extern_access) ? 3 : 0; } #endif @@ -24071,6 +24088,11 @@ ix86_run_selftests (void) #define TARGET_GET_MULTILIB_ABI_NAME \ ix86_get_multilib_abi_name +#if !TARGET_MACHO && !TARGET_DLLIMPORT_DECL_ATTRIBUTES +# undef TARGET_ASM_RELOC_RW_MASK +# define TARGET_ASM_RELOC_RW_MASK ix86_reloc_rw_mask +#endif + static bool ix86_libc_has_fast_function (int fcode ATTRIBUTE_UNUSED) { #ifdef OPTION_GLIBC diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index e67d47af676..2959c84cc3d 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -658,6 +658,7 @@ Objective-C and Objective-C++ Dialects}. -fnon-call-exceptions -fdelete-dead-exceptions -funwind-tables @gol -fasynchronous-unwind-tables @gol -fno-gnu-unique @gol +-fno-direct-extern-access @gol -finhibit-size-directive -fcommon -fno-ident @gol -fpcc-struct-return -fpic -fPIC -fpie -fPIE -fno-plt @gol -fno-jump-tables -fno-bit-tests @gol @@ -16633,6 +16634,18 @@ through the PLT for specific external functions. In position-dependent code, a few targets also convert calls to functions that are marked to not use the PLT to use the GOT instead. +@item -fno-direct-extern-access +@opindex fno-direct-extern-access +@opindex fdirect-extern-access +Without @option{-fpic} nor @option{-fPIC}, always use the GOT pointer +to access external symbols. With @option{-fpic} or @option{-fPIC}, +treat access to protected symbols as local symbols. + +@strong{Warning:} shared libraries compiled with +@option{-fno-direct-extern-access} and executable compiled with +@option{-fdirect-extern-access} may not be binary compatible if +protected symbols are used in shared libraries and executable. + @item -fno-jump-tables @opindex fno-jump-tables @opindex fjump-tables diff --git a/gcc/testsuite/g++.dg/pr35513-1.C b/gcc/testsuite/g++.dg/pr35513-1.C new file mode 100644 index 00000000000..8423e826da8 --- /dev/null +++ b/gcc/testsuite/g++.dg/pr35513-1.C @@ -0,0 +1,25 @@ +// { dg-do run } +// { dg-options "-O2 -fno-direct-extern-access" } + +#include <iostream> + +class Bug +{ +}; + +int throw_bug() +{ + throw Bug(); + + return 0; +} + +int main() +{ + try { + std::cout << throw_bug(); + } catch (Bug bug) { + }; + + return 0; +} diff --git a/gcc/testsuite/g++.dg/pr35513-2.C b/gcc/testsuite/g++.dg/pr35513-2.C new file mode 100644 index 00000000000..56ed19ae1eb --- /dev/null +++ b/gcc/testsuite/g++.dg/pr35513-2.C @@ -0,0 +1,53 @@ +// { dg-do run } +// { dg-options "-O2 -fno-direct-extern-access" } + +class Foo +{ +public: + Foo(int n) : n_(n) { } + int f() { return n_; } + + int badTest(); + int goodTest(); + +private: + + int n_; +}; + +int Foo::badTest() +{ + try { + throw int(99); + } + + catch (int &i) { + n_ = 16; + } + + return n_; +} + + +int Foo::goodTest() +{ + int n; + + try { + throw int(99); + } + + catch (int &i) { + n = 16; + } + + return n_; +} + +int main() +{ + Foo foo(5); + foo.goodTest(); + foo.badTest(); + return 0; +} diff --git a/gcc/testsuite/gcc.target/i386/pr35513-1.c b/gcc/testsuite/gcc.target/i386/pr35513-1.c new file mode 100644 index 00000000000..c5dbabc3704 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr35513-1.c @@ -0,0 +1,16 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fno-pic -fno-direct-extern-access" } */ + +extern void bar (void); +extern void *p; + +void +foo (void) +{ + p = &bar; +} + +/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT," { target { ia32 && got32x_reloc } } } } */ +/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ia32 && got32x_reloc } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr35513-2.c b/gcc/testsuite/gcc.target/i386/pr35513-2.c new file mode 100644 index 00000000000..8bb7cb4c13d --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr35513-2.c @@ -0,0 +1,15 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fno-pic -fno-direct-extern-access" } */ + +extern int bar; + +int +foo (void) +{ + return bar; +} + +/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT," { target { ia32 && got32x_reloc } } } } */ +/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ia32 && got32x_reloc } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr35513-3.c b/gcc/testsuite/gcc.target/i386/pr35513-3.c new file mode 100644 index 00000000000..98dc54e3bf4 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr35513-3.c @@ -0,0 +1,15 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fpie -fno-direct-extern-access" } */ + +extern int bar; + +int +foo (void) +{ + return bar; +} + +/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT" { target { ia32 && got32x_reloc } } } } */ +/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ia32 && got32x_reloc } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr35513-4.c b/gcc/testsuite/gcc.target/i386/pr35513-4.c new file mode 100644 index 00000000000..467081dad65 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr35513-4.c @@ -0,0 +1,15 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fplt -fno-pic -fno-direct-extern-access" } */ + +extern void foo (void); + +int +bar (void) +{ + foo (); + return 0; +} + +/* { dg-final { scan-assembler "call\[ \t\]*foo" } } */ +/* { dg-final { scan-assembler-not "foo@GOTPCREL" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "foo@GOT" { target ia32 } } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr35513-5.c b/gcc/testsuite/gcc.target/i386/pr35513-5.c new file mode 100644 index 00000000000..b0e61b08ba9 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr35513-5.c @@ -0,0 +1,15 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fplt -fpic -fno-direct-extern-access" } */ + +extern void foo (void); + +int +bar (void) +{ + foo (); + return 0; +} + +/* { dg-final { scan-assembler "call\[ \t\]*foo@PLT" } } */ +/* { dg-final { scan-assembler-not "foo@GOTPCREL" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "foo@GOT" { target ia32 } } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr35513-6.c b/gcc/testsuite/gcc.target/i386/pr35513-6.c new file mode 100644 index 00000000000..270504b8d0e --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr35513-6.c @@ -0,0 +1,14 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fplt -fno-pic -fno-direct-extern-access" } */ + +extern void foo (void); + +void +bar (void) +{ + foo (); +} + +/* { dg-final { scan-assembler "jmp\[ \t\]*foo" } } */ +/* { dg-final { scan-assembler-not "foo@GOTPCREL" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "foo@GOT" { target ia32 } } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr35513-7.c b/gcc/testsuite/gcc.target/i386/pr35513-7.c new file mode 100644 index 00000000000..2c5a83ddef8 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr35513-7.c @@ -0,0 +1,15 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fplt -fpic -fno-direct-extern-access" } */ + +extern void foo (void); + +void +bar (void) +{ + foo (); +} + +/* { dg-final { scan-assembler "jmp\[ \t\]*foo@PLT" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "call\[ \t\]*foo@PLT" { target ia32 } } } */ +/* { dg-final { scan-assembler-not "foo@GOTPCREL" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "foo@GOT" { target ia32 } } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr35513-8.c b/gcc/testsuite/gcc.target/i386/pr35513-8.c new file mode 100644 index 00000000000..545979e99c2 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr35513-8.c @@ -0,0 +1,41 @@ +/* { dg-do assemble { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-require-effective-target maybe_x32 } */ +/* { dg-options "-mx32 -O2 -fno-pic -fexceptions -fasynchronous-unwind-tables -fno-direct-extern-access" } */ + +extern int foo (int); +extern void exit (int __status) __attribute__ ((__nothrow__ )) __attribute__ ((__noreturn__)); +struct __pthread_cleanup_frame +{ + void (*__cancel_routine) (void *); + void *__cancel_arg; + int __do_it; + int __cancel_type; +}; +extern __inline void +__pthread_cleanup_routine (struct __pthread_cleanup_frame *__frame) +{ + if (__frame->__do_it) + __frame->__cancel_routine (__frame->__cancel_arg); +} +static int cl_called; + +static void +cl (void *arg) +{ + ++cl_called; +} + + +void * +tf_usleep (void *arg) +{ + + do { struct __pthread_cleanup_frame __clframe __attribute__ ((__cleanup__ (__pthread_cleanup_routine))) = { .__cancel_routine = (cl), .__cancel_arg = ( + ((void *)0)), .__do_it = 1 };; + + foo (arg == ((void *)0) ? (0x7fffffffL * 2UL + 1UL) : 0); + + __clframe.__do_it = (0); } while (0); + + exit (1); +}