diff mbox

Relocations to use when eliding plts

Message ID CAMe9rOohkVFdsDyNe-RXsXUerM2YrawbrTW9X5opub1zMf8EmA@mail.gmail.com
State New
Headers show

Commit Message

H.J. Lu May 27, 2015, 9:38 p.m. UTC
On Wed, May 27, 2015 at 1:03 PM, Richard Henderson <rth@redhat.com> wrote:
> There's one problem with the couple of patches that I've seen go by wrt eliding
> PLTs with -z now, and relaxing inlined PLTs (aka -fno-plt):
>
> They're currently using the same relocations used by data, and thus the linker
> and dynamic linker must ensure that pointer equality is maintained.  Which
> results in branch-to-branch-(to-branch) situations.
>

Your test exposed a linker bug:

https://sourceware.org/bugzilla/show_bug.cgi?id=18458

I checked in this patch to fix it.
diff mbox

Patch

From 8ded2ddc8bac501c1ee0706cb3d3ef3fb1c10b85 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Wed, 27 May 2015 14:32:24 -0700
Subject: [PATCH] Convert PLT reloc only if pointer equality isn't needed

When pointer equality needed, we can't replace PLT relocations with
GOT relocations for -z now.  This patch checks if pointer equality is
needed before converting PLT relocations to GOT relocations.

bfd/

	PR binutils/18458
	* elf32-i386.c (elf_i386_check_relocs): Create .plt.got section
	for now binding only if pointer equality isn't needed.
	(elf_i386_allocate_dynrelocs): Use .plt.got section for now
	binding only if pointer equality isn't needed.
	* elf64-x86-64.c (elf_x86_64_check_relocs): Create .plt.got
	section for now binding only if pointer equality isn't needed.
	(elf_x86_64_allocate_dynrelocs): Use .plt.got section for now
	binding only if pointer equality isn't needed.

ld/testsuite/

	PR binutils/18458
	* ld-elf/shared.exp (build_tests): Build libpr18458a.so and
	libpr18458b.so.
	(run_tests): Run pr18458 test.
	* ld-elf/pr18458a.c: New file.
	* ld-elf/pr18458b.c: Likewise.
	* ld-elf/pr18458c.c: Likewise.
---
 bfd/ChangeLog                  | 12 ++++++++++++
 bfd/elf32-i386.c               |  5 +++--
 bfd/elf64-x86-64.c             |  5 +++--
 ld/testsuite/ChangeLog         | 10 ++++++++++
 ld/testsuite/ld-elf/pr18458a.c |  6 ++++++
 ld/testsuite/ld-elf/pr18458b.c |  6 ++++++
 ld/testsuite/ld-elf/pr18458c.c | 18 ++++++++++++++++++
 ld/testsuite/ld-elf/shared.exp |  9 +++++++++
 8 files changed, 67 insertions(+), 4 deletions(-)
 create mode 100644 ld/testsuite/ld-elf/pr18458a.c
 create mode 100644 ld/testsuite/ld-elf/pr18458b.c
 create mode 100644 ld/testsuite/ld-elf/pr18458c.c

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 87a0bff..a8a0ad9 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,15 @@ 
+2015-05-27  H.J. Lu  <hongjiu.lu@intel.com>
+
+	PR binutils/18458
+	* elf32-i386.c (elf_i386_check_relocs): Create .plt.got section
+	for now binding only if pointer equality isn't needed.
+	(elf_i386_allocate_dynrelocs): Use .plt.got section for now
+	binding only if pointer equality isn't needed.
+	* elf64-x86-64.c (elf_x86_64_check_relocs): Create .plt.got
+	section for now binding only if pointer equality isn't needed.
+	(elf_x86_64_allocate_dynrelocs): Use .plt.got section for now
+	binding only if pointer equality isn't needed.
+
 2015-05-26  H.J. Lu  <hongjiu.lu@intel.com>
 
 	PR binutils/18437
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index 23d50e1..f3aee96 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -1885,7 +1885,8 @@  do_size:
       if (use_plt_got
 	  && h != NULL
 	  && h->plt.refcount > 0
-	  && ((info->flags & DF_BIND_NOW) || h->got.refcount > 0)
+	  && (((info->flags & DF_BIND_NOW) && !h->pointer_equality_needed)
+	      || h->got.refcount > 0)
 	  && htab->plt_got == NULL)
 	{
 	  /* Create the GOT procedure linkage table.  */
@@ -2323,7 +2324,7 @@  elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
     {
       bfd_boolean use_plt_got;
 
-      if ((info->flags & DF_BIND_NOW))
+      if ((info->flags & DF_BIND_NOW) && !h->pointer_equality_needed)
 	{
 	  /* Don't use the regular PLT for DF_BIND_NOW. */
 	  h->plt.offset = (bfd_vma) -1;
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index 4428f97..072c00b 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -2080,7 +2080,8 @@  do_size:
       if (use_plt_got
 	  && h != NULL
 	  && h->plt.refcount > 0
-	  && ((info->flags & DF_BIND_NOW) || h->got.refcount > 0)
+	  && (((info->flags & DF_BIND_NOW) && !h->pointer_equality_needed)
+	      || h->got.refcount > 0)
 	  && htab->plt_got == NULL)
 	{
 	  /* Create the GOT procedure linkage table.  */
@@ -2542,7 +2543,7 @@  elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
     {
       bfd_boolean use_plt_got;
 
-      if ((info->flags & DF_BIND_NOW))
+      if ((info->flags & DF_BIND_NOW) && !h->pointer_equality_needed)
 	{
 	  /* Don't use the regular PLT for DF_BIND_NOW. */
 	  h->plt.offset = (bfd_vma) -1;
diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog
index e6a551c..779fc03 100644
--- a/ld/testsuite/ChangeLog
+++ b/ld/testsuite/ChangeLog
@@ -1,3 +1,13 @@ 
+2015-05-27  H.J. Lu  <hongjiu.lu@intel.com>
+
+	PR binutils/18458
+	* ld-elf/shared.exp (build_tests): Build libpr18458a.so and
+	libpr18458b.so.
+	(run_tests): Run pr18458 test.
+	* ld-elf/pr18458a.c: New file.
+	* ld-elf/pr18458b.c: Likewise.
+	* ld-elf/pr18458c.c: Likewise.
+
 2015-05-16  H.J. Lu  <hongjiu.lu@intel.com>
 
 	* ld-i386/i386.exp: Run PR ld/17689 tests with -z now.
diff --git a/ld/testsuite/ld-elf/pr18458a.c b/ld/testsuite/ld-elf/pr18458a.c
new file mode 100644
index 0000000..d6aa49f
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr18458a.c
@@ -0,0 +1,6 @@ 
+#include <stdio.h>
+void 
+a (void)
+{
+  printf("PASS\n");
+}
diff --git a/ld/testsuite/ld-elf/pr18458b.c b/ld/testsuite/ld-elf/pr18458b.c
new file mode 100644
index 0000000..33c1cb6
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr18458b.c
@@ -0,0 +1,6 @@ 
+extern void a (void);
+void
+b (void)
+{
+  a();
+}
diff --git a/ld/testsuite/ld-elf/pr18458c.c b/ld/testsuite/ld-elf/pr18458c.c
new file mode 100644
index 0000000..d40f98c
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr18458c.c
@@ -0,0 +1,18 @@ 
+extern void a(void);
+extern void b(void);
+
+void dummy (void)
+{
+  a();
+}
+int
+compare (void (*f)(void))
+{
+  return a == f;
+}
+int
+main (void)
+{
+  b ();
+  return 0;
+}
diff --git a/ld/testsuite/ld-elf/shared.exp b/ld/testsuite/ld-elf/shared.exp
index 8aa7a32..bcbe8e2 100644
--- a/ld/testsuite/ld-elf/shared.exp
+++ b/ld/testsuite/ld-elf/shared.exp
@@ -267,6 +267,12 @@  set build_tests {
   {"Build pr16457"
    "tmpdir/libpr16452b.so -Wl,-rpath=tmpdir" ""
    {pr16452b.c} {{objdump {-p} pr16457.od}} "pr16457"}
+  {"Build libpr18458a.so"
+   "-shared -Wl,-z,now" "-fPIC"
+   {pr18458a.c} {} "libpr18458a.so"}
+  {"Build libpr18458b.so"
+   "-shared -Wl,-z,now tmpdir/libpr18458a.so" "-fPIC"
+   {pr18458b.c} {} "libpr18458b.so"}
 }
 
 run_cc_link_tests $build_tests
@@ -417,6 +423,9 @@  set run_tests {
     {"Run pr2404"
      "tmpdir/pr2404b.o tmpdir/libpr2404a.so" ""
      {dummy.c} "pr2404" "pr2404.out"}
+    {"Run pr18458"
+     "tmpdir/libpr18458a.so tmpdir/libpr18458b.so -z now" ""
+     {pr18458c.c} "pr18458" "pass.out"}
 }
 
 # NetBSD ELF systems do not currently support the .*_array sections.
-- 
1.9.3