Bug 17827 - PIE copy relocations are broken with pointers
Summary: PIE copy relocations are broken with pointers
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: 2.25
: P2 normal
Target Milestone: 2.26
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-01-11 15:39 UTC by H.J. Lu
Modified: 2015-01-12 11:55 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description H.J. Lu 2015-01-11 15:39:39 UTC
On Linux/x86-64 with GCC 5:

[hjl@gnu-tools-1 pr17689-2]$ cat x.c 
#if 0
#include <stdio.h>
extern char *program_invocation_name;
int
main ()
{
  printf ("%s\n", program_invocation_name);
  return 0;
}
#else
extern char *bar_alias;
extern void foo (char *);
char **ptr = &bar_alias;

int
main ()
{
  foo (bar_alias);
  foo (*ptr);
  return 0;
}
#endif

[hjl@gnu-tools-1 pr17689-2]$ cat bar.c
#include <stdio.h>

char *bar = "PASS";
extern char *bar_alias __attribute__ ((weak, alias ("bar")));

void
foo (char *x)
{
  printf ("%s\n", x);
}
[hjl@gnu-tools-1 pr17689-2]$ make
gcc -pie -o x x.o libbar.so -Wl,-rpath,.
/usr/local/bin/ld: x.o(.data.rel+0x0): reloc against `bar_alias': error 4
/usr/local/bin/ld: final link failed: Nonrepresentable section on output
collect2: error: ld returned 1 exit status
make: *** [x] Error 1
[hjl@gnu-tools-1 pr17689-2]$
Comment 1 Sourceware Commits 2015-01-12 04:36:21 UTC
commit 9d1d54d5a7e3b634895e6e434646c706eb55c082
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Sun Jan 11 08:04:27 2015 -0800

    Only discard space for pc-relative relocs symbols
    
    When building PIE, we should only discard space for pc-relative relocs
    symbols which turn out to need copy relocs.
    
    bfd/
    
    	PR ld/17827
    	* elf64-x86-64.c (elf_x86_64_allocate_dynrelocs): For PIE,
    	only discard space for pc-relative relocs symbols which turn
    	out to need copy relocs.
    
    ld/testsuite/
    
    	PR ld/17827
    	* ld-x86-64/pr17689.out: Updated.
    	* ld-x86-64/pr17689b.S: Likewise.
    
    	* ld-x86-64/pr17827.rd: New file.
    
    	* ld-x86-64/x86-64.exp: Run PR ld/17827 test.

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 70b138b..234d559 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,10 @@
+2015-01-11  H.J. Lu  <hongjiu.lu@intel.com>
+
+	PR ld/17827
+	* elf64-x86-64.c (elf_x86_64_allocate_dynrelocs): For PIE,
+	only discard space for pc-relative relocs symbols which turn
+	out to need copy relocs.
+
 2015-01-09  Nick Clifton  <nickc@redhat.com>
 
 	* tekhex.c (getvalue): Fix thinko in test for correct extraction
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index 581ee17..6b7d3c9 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -2742,13 +2742,23 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
 		       && ! bfd_elf_link_record_dynamic_symbol (info, h))
 		return FALSE;
 	    }
-	  /* For PIE, discard space for relocs against symbols which
-	     turn out to need copy relocs.  */
+	  /* For PIE, discard space for pc-relative relocs against
+	     symbols which turn out to need copy relocs.  */
 	  else if (info->executable
 		   && (h->needs_copy || eh->needs_copy)
 		   && h->def_dynamic
 		   && !h->def_regular)
-	    eh->dyn_relocs = NULL;
+	    {
+	      struct elf_dyn_relocs **pp;
+
+	      for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
+		{
+		  if (p->pc_count != 0)
+		    *pp = p->next;
+		  else
+		    pp = &p->next;
+		}
+	    }
 	}
     }
   else if (ELIMINATE_COPY_RELOCS)
diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog
index 229e006..e6903f7 100644
--- a/ld/testsuite/ChangeLog
+++ b/ld/testsuite/ChangeLog
@@ -1,3 +1,13 @@
+2015-01-11  H.J. Lu  <hongjiu.lu@intel.com>
+
+	PR ld/17827
+	* ld-x86-64/pr17689.out: Updated.
+	* ld-x86-64/pr17689b.S: Likewise.
+
+	* ld-x86-64/pr17827.rd: New file.
+
+	* ld-x86-64/x86-64.exp: Run PR ld/17827 test.
+
 2015-01-08  Jan Beulich  <jbeulich@suse.com>
 
 	* ld-x86-64/pr14207.d: Adjust expecations to cover the
diff --git a/ld/testsuite/ld-x86-64/pr17689.out b/ld/testsuite/ld-x86-64/pr17689.out
index 7ef22e9..38e0352 100644
--- a/ld/testsuite/ld-x86-64/pr17689.out
+++ b/ld/testsuite/ld-x86-64/pr17689.out
@@ -1 +1,2 @@
 PASS
+PASS
diff --git a/ld/testsuite/ld-x86-64/pr17689b.S b/ld/testsuite/ld-x86-64/pr17689b.S
index c95f891..64485c7 100644
--- a/ld/testsuite/ld-x86-64/pr17689b.S
+++ b/ld/testsuite/ld-x86-64/pr17689b.S
@@ -5,8 +5,18 @@ main:
 	subq	$8, %rsp
 	movq	bar_alias(%rip), %rdi
 	call	foo@PLT
+	movq	ptr(%rip), %rax
+	movq	(%rax), %rdi
+	call	foo@PLT
 	xorl	%eax, %eax
 	addq	$8, %rsp
 	ret
 	.size	main, .-main
+	.globl	ptr
+	.section	.data.rel,"aw",@progbits
+	.align 8
+	.type	ptr, @object
+	.size	ptr, 8
+ptr:
+	.quad	bar_alias
 	.section	.note.GNU-stack,"",@progbits
diff --git a/ld/testsuite/ld-x86-64/pr17827.rd b/ld/testsuite/ld-x86-64/pr17827.rd
new file mode 100644
index 0000000..d78ea2f
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr17827.rd
@@ -0,0 +1,4 @@
+#failif
+#...
+[0-9a-f ]+R_X86_64_NONE.*
+#...
diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp
index aa8555f..5b49bff 100644
--- a/ld/testsuite/ld-x86-64/x86-64.exp
+++ b/ld/testsuite/ld-x86-64/x86-64.exp
@@ -432,6 +432,14 @@ if { [isnative] && [which $CC] != 0 } {
 	    {{readelf {-Wr} pr17689.rd}} \
 	    "pr17689" \
 	] \
+	[list \
+	    "Build pr17827 with PIE without -fPIE" \
+	    "tmpdir/pr17689.so -pie" \
+	    "" \
+	    { pr17689b.S } \
+	    {{readelf {-Wr} pr17827.rd}} \
+	    "pr17827" \
+	] \
     ]
 
     run_ld_link_exec_tests [] [list \
Comment 2 Joel Brobecker 2015-01-12 04:47:55 UTC
Sorry about the diff. I was trying to reproduce, and forgot to exclude the diff from the call to the script that fails those commits. It's a one-off.
Comment 3 H.J. Lu 2015-01-12 11:55:12 UTC
Checked the fix into master and 2.25 branches.