diff mbox

PR target/77408: Add -mcopy-reloc to avoid copy relocation

Message ID 20160831201807.GA2113@intel.com
State New
Headers show

Commit Message

H.J. Lu Aug. 31, 2016, 8:18 p.m. UTC
On x86, copy relocation is used in executable to access external data
defined in shared object as if it is defined locally. At run-time,
dynamic linker copies symbol data from shared object to executable and
its references from shared objects are resolved by GLOB_DAT relocation.
Since the copy of symbol data in executable is writable even if the
original symbol in shared object is read-only, this is a potential
security risk.

We can avoid copy relocation by always using PIC model to access
external data symbol.  If the external symbol is defined locally in
executable, linker can optimize instructions on memory operand with
GOTPCRELX/GOT32X relocation against external symbol into a different
form on immediate operand.

Without copy relocation, external symbols in executable are accessed
indirectly via the GOT slot. Even when the symbol is defined locally,
it is still referenced indirectly through a register. However, there
are a few side benefits:

1. Without copy relocation in executable for external symbol defined
in shared object, symbol size can be increased while still providing
backward binary compatibility.
2. Since protected symbols in shared objects are no longer copied to
executable at run-time, references of protected symbols within shared
objects can be resolved without GOT.

Tested on i686 and x86-64.  OK for master?


H.J.
---
gcc/

	PR target/77408
	* config/i386/i386.c (ix86_force_load_from_GOT_p): Return
	true on data symbols for -mno-copy-reloc.
	(legitimate_pic_address_disp_p): Allow copy relocation in
	64-bit PIE only with -mcopy-reloc.
	* config/i386/i386.opt (mcopy-reloc): New.
	* doc/invoke.texi: Document -mcopy-reloc.

gcc/testsuite/

	PR target/77408
	* gcc.target/i386/no-copy-reloc-1.c: New test.
	* gcc.target/i386/no-copy-reloc-2.c: Likewise.
	* gcc.target/i386/no-copy-reloc-3.c: Likewise.
	* gcc.target/i386/no-copy-reloc-4.c: Likewise.
	* gcc.target/i386/no-copy-reloc-5.c: Likewise.
	* gcc.target/i386/no-copy-reloc-6.c: Likewise.
	* gcc.target/i386/no-copy-reloc-7.c: Likewise.
	* gcc.target/i386/no-copy-reloc-8.c: Likewise.
	* gcc.target/i386/no-copy-reloc-9.c: Likewise.
---
 gcc/config/i386/i386.c                          | 22 +++++++++++++++-------
 gcc/config/i386/i386.opt                        |  4 ++++
 gcc/doc/invoke.texi                             |  7 ++++++-
 gcc/testsuite/gcc.target/i386/no-copy-reloc-1.c | 15 +++++++++++++++
 gcc/testsuite/gcc.target/i386/no-copy-reloc-2.c | 16 ++++++++++++++++
 gcc/testsuite/gcc.target/i386/no-copy-reloc-3.c | 14 ++++++++++++++
 gcc/testsuite/gcc.target/i386/no-copy-reloc-4.c | 14 ++++++++++++++
 gcc/testsuite/gcc.target/i386/no-copy-reloc-5.c | 15 +++++++++++++++
 gcc/testsuite/gcc.target/i386/no-copy-reloc-6.c | 14 ++++++++++++++
 gcc/testsuite/gcc.target/i386/no-copy-reloc-7.c | 14 ++++++++++++++
 gcc/testsuite/gcc.target/i386/no-copy-reloc-8.c | 12 ++++++++++++
 gcc/testsuite/gcc.target/i386/no-copy-reloc-9.c | 12 ++++++++++++
 12 files changed, 151 insertions(+), 8 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/no-copy-reloc-1.c
 create mode 100644 gcc/testsuite/gcc.target/i386/no-copy-reloc-2.c
 create mode 100644 gcc/testsuite/gcc.target/i386/no-copy-reloc-3.c
 create mode 100644 gcc/testsuite/gcc.target/i386/no-copy-reloc-4.c
 create mode 100644 gcc/testsuite/gcc.target/i386/no-copy-reloc-5.c
 create mode 100644 gcc/testsuite/gcc.target/i386/no-copy-reloc-6.c
 create mode 100644 gcc/testsuite/gcc.target/i386/no-copy-reloc-7.c
 create mode 100644 gcc/testsuite/gcc.target/i386/no-copy-reloc-8.c
 create mode 100644 gcc/testsuite/gcc.target/i386/no-copy-reloc-9.c
diff mbox

Patch

diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index a229a73..c84a351 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -15172,13 +15172,20 @@  darwin_local_data_pic (rtx disp)
 bool
 ix86_force_load_from_GOT_p (rtx x)
 {
-  return ((TARGET_64BIT || HAVE_AS_IX86_GOT32X)
-	  && !TARGET_PECOFF && !TARGET_MACHO
-	  && !flag_plt && !flag_pic
-	  && ix86_cmodel != CM_LARGE
-	  && GET_CODE (x) == SYMBOL_REF
-	  && SYMBOL_REF_FUNCTION_P (x)
-	  && !SYMBOL_REF_LOCAL_P (x));
+  if ((TARGET_64BIT || HAVE_AS_IX86_GOT32X)
+      && !TARGET_PECOFF
+      && !flag_pic
+      && !TARGET_MACHO
+      && ix86_cmodel != CM_LARGE
+      && GET_CODE (x) == SYMBOL_REF
+      && !SYMBOL_REF_LOCAL_P (x))
+    {
+      if (SYMBOL_REF_FUNCTION_P (x))
+	return !flag_plt;
+      else
+	return !flag_copy_reloc;
+    }
+  return false;
 }
 
 /* Determine if a given RTX is a valid constant.  We already know this
@@ -15439,6 +15446,7 @@  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_copy_reloc
 			   && flag_pie
 			   && !SYMBOL_REF_WEAK (op0)
 			   && !SYMBOL_REF_FUNCTION_P (op0)))
diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt
index 4b75ba8..aef23d9 100644
--- a/gcc/config/i386/i386.opt
+++ b/gcc/config/i386/i386.opt
@@ -897,3 +897,7 @@  Attempt to avoid generating instruction sequences containing ret bytes.
 mgeneral-regs-only
 Target Report RejectNegative Mask(GENERAL_REGS_ONLY) Var(ix86_target_flags) Save
 Generate code which uses only the general registers.
+
+mcopy-reloc
+Target Report Var(flag_copy_reloc) Init(1)
+Allow copy relocation when accessing external data.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 87da1f1..71bec15 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -1179,7 +1179,7 @@  See RS/6000 and PowerPC Options.
 -msse2avx -mfentry -mrecord-mcount -mnop-mcount -m8bit-idiv @gol
 -mavx256-split-unaligned-load -mavx256-split-unaligned-store @gol
 -malign-data=@var{type} -mstack-protector-guard=@var{guard} @gol
--mmitigate-rop -mgeneral-regs-only}
+-mmitigate-rop -mgeneral-regs-only -mcopy-reloc}
 
 @emph{x86 Windows Options}
 @gccoptlist{-mconsole -mcygwin -mno-cygwin -mdll @gol
@@ -24653,6 +24653,11 @@  Generate code that uses only the general-purpose registers.  This
 prevents the compiler from using floating-point, vector, mask and bound
 registers.
 
+@item -mcopy-reloc
+@opindex mcopy-reloc
+Generate code that uses copy relocation in executable to access external
+data defined in shared object.  It is enabled by default.
+
 @end table
 
 These @samp{-m} switches are supported in addition to the above
diff --git a/gcc/testsuite/gcc.target/i386/no-copy-reloc-1.c b/gcc/testsuite/gcc.target/i386/no-copy-reloc-1.c
new file mode 100644
index 0000000..94de223
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/no-copy-reloc-1.c
@@ -0,0 +1,15 @@ 
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -mno-copy-reloc" } */
+
+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|lea\)\(l|q\)\[ \t\]*\(\\\$|\)bar\\(%rip\\)" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "\(mov|lea\)l\[ \t\]*\(\\\$|\)bar," { target { ia32 && got32x_reloc } } } } */
diff --git a/gcc/testsuite/gcc.target/i386/no-copy-reloc-2.c b/gcc/testsuite/gcc.target/i386/no-copy-reloc-2.c
new file mode 100644
index 0000000..90205a4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/no-copy-reloc-2.c
@@ -0,0 +1,16 @@ 
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -mno-copy-reloc" } */
+
+extern int bar;
+extern int *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|lea\)\(l|q\)\[ \t\]*\(\\\$|\)bar\\(%rip\\)" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ia32 && got32x_reloc } } } } */
diff --git a/gcc/testsuite/gcc.target/i386/no-copy-reloc-3.c b/gcc/testsuite/gcc.target/i386/no-copy-reloc-3.c
new file mode 100644
index 0000000..c8c7cf1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/no-copy-reloc-3.c
@@ -0,0 +1,14 @@ 
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -mno-copy-reloc" } */
+
+static int bar;
+
+int *
+foo (void)
+{
+  return &bar;
+}
+
+/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*\\\$bar," } } */
+/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "movl\[ \t\]*bar@GOT," { target { ia32 && got32x_reloc } } } } */
diff --git a/gcc/testsuite/gcc.target/i386/no-copy-reloc-4.c b/gcc/testsuite/gcc.target/i386/no-copy-reloc-4.c
new file mode 100644
index 0000000..fbfa63a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/no-copy-reloc-4.c
@@ -0,0 +1,14 @@ 
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -mno-copy-reloc" } */
+
+extern int bar __attribute__ ((visibility ("hidden")));
+
+int *
+foo (void)
+{
+  return &bar;
+}
+
+/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*\\\$bar," } } */
+/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "movl\[ \t\]*bar@GOT," { target { ia32 && got32x_reloc } } } } */
diff --git a/gcc/testsuite/gcc.target/i386/no-copy-reloc-5.c b/gcc/testsuite/gcc.target/i386/no-copy-reloc-5.c
new file mode 100644
index 0000000..d5ec6a7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/no-copy-reloc-5.c
@@ -0,0 +1,15 @@ 
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -mno-copy-reloc" } */
+
+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|lea\)\(l|q\)\[ \t\]*\(\\\$|\)bar\\(%rip\\)" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "\(mov|lea\)l\[ \t\]*\(\\\$|\)bar," { target { ia32 && got32x_reloc } } } } */
diff --git a/gcc/testsuite/gcc.target/i386/no-copy-reloc-6.c b/gcc/testsuite/gcc.target/i386/no-copy-reloc-6.c
new file mode 100644
index 0000000..9eff04f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/no-copy-reloc-6.c
@@ -0,0 +1,14 @@ 
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -mno-copy-reloc" } */
+
+extern int bar;
+
+int
+check (int *p)
+{
+  return p != &bar;
+}
+
+/* { dg-final { scan-assembler "cmp\(l|q\)\[ \t\]*.*bar@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT," { target { ia32 && got32x_reloc } } } } */
+/* { dg-final { scan-assembler-not "cmp\(l|q\)\[ \t\]*\\\$bar," } } */
diff --git a/gcc/testsuite/gcc.target/i386/no-copy-reloc-7.c b/gcc/testsuite/gcc.target/i386/no-copy-reloc-7.c
new file mode 100644
index 0000000..9c1dec0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/no-copy-reloc-7.c
@@ -0,0 +1,14 @@ 
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -mno-copy-reloc" } */
+
+extern int bar[];
+
+int *
+foo (void)
+{
+  return &bar[1];
+}
+
+/* { 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\\+4," } } */
diff --git a/gcc/testsuite/gcc.target/i386/no-copy-reloc-8.c b/gcc/testsuite/gcc.target/i386/no-copy-reloc-8.c
new file mode 100644
index 0000000..5d490a7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/no-copy-reloc-8.c
@@ -0,0 +1,12 @@ 
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpie -mno-copy-reloc" } */
+
+extern int glob_a;
+
+int foo ()
+{
+  return glob_a;
+}
+
+/* { dg-final { scan-assembler "glob_a@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "glob_a@GOT\\(" { target { ia32 } } } } */
diff --git a/gcc/testsuite/gcc.target/i386/no-copy-reloc-9.c b/gcc/testsuite/gcc.target/i386/no-copy-reloc-9.c
new file mode 100644
index 0000000..5d490a7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/no-copy-reloc-9.c
@@ -0,0 +1,12 @@ 
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpie -mno-copy-reloc" } */
+
+extern int glob_a;
+
+int foo ()
+{
+  return glob_a;
+}
+
+/* { dg-final { scan-assembler "glob_a@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "glob_a@GOT\\(" { target { ia32 } } } } */