This is the mail archive of the binutils-cvs@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[binutils-gdb] x86-64: Use PLT address for PC-relative reloc


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=451875b4f976a527395e9303224c7881b65e12ed

commit 451875b4f976a527395e9303224c7881b65e12ed
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Wed Feb 14 03:50:40 2018 -0800

    x86-64: Use PLT address for PC-relative reloc
    
    Since PLT in PDE and PC-relative PLT in PIE can be used as function
    address, there is no need for dynamic PC-relative relocation against
    a dynamic function definition in PIE.  Linker should resolve PC-relative
    reference to its PLT address.
    
    NB: i386 has non-PIC PLT and PIC PLT.  Only non-PIC PLT in PDE can
    be used as function address.  PIC PLT in PIE can't be used as
    function address.
    
    bfd/
    
    	PR ld/22842
    	* elf32-i386.c (elf_i386_check_relocs): Pass FALSE for non
    	PC-relative PLT to NEED_DYNAMIC_RELOCATION_P.
    	* elf64-x86-64.c (elf_x86_64_check_relocs): Create PLT for
    	R_X86_64_PC32 reloc against dynamic function in data section.
    	Pass TRUE for PC-relative PLT to NEED_DYNAMIC_RELOCATION_P.
    	(elf_x86_64_relocate_section): Use PLT for R_X86_64_PC32 reloc
    	against dynamic function in data section.
    	* elfxx-x86.c (elf_x86_allocate_dynrelocs): Use PLT in PIE as
    	function address only if pcrel_plt is true.
    	(_bfd_x86_elf_link_hash_table_create): Set pcrel_plt.
    	* elfxx-x86.h (NEED_DYNAMIC_RELOCATION_P): Add PCREL_PLT for
    	PC-relative PLT.  If PLT is PC-relative, don't generate dynamic
    	PC-relative relocation against a function definition in data
    	secton in PIE.  Remove the obsolete comments.
    	(elf_x86_link_hash_table): Add pcrel_plt.
    
    ld/
    
    	PR ld/22842
    	* testsuite/ld-i386/i386.exp: Run PR ld/22842 tests.
    	* testsuite/ld-x86-64/x86-64.exp: Likewise.
    	* testsuite/ld-i386/pr22842a.c: New file.
    	* testsuite/ld-i386/pr22842b.S: Likewise.
    	* testsuite/ld-x86-64/pr22842a.c: Likewise.
    	* testsuite/ld-x86-64/pr22842a.rd: Likewise.
    	* testsuite/ld-x86-64/pr22842b.S: Likewise.
    	* testsuite/ld-x86-64/pr22842b.rd: Likewise.

Diff:
---
 bfd/ChangeLog                      | 19 +++++++++++++++
 bfd/elf32-i386.c                   |  2 +-
 bfd/elf64-x86-64.c                 | 24 ++++++++++++++++--
 bfd/elfxx-x86.c                    | 22 ++++++++++++-----
 bfd/elfxx-x86.h                    | 50 +++++++++++++++++++++++---------------
 ld/ChangeLog                       | 12 +++++++++
 ld/testsuite/ld-i386/i386.exp      | 16 ++++++++++++
 ld/testsuite/ld-i386/pr22842a.c    | 20 +++++++++++++++
 ld/testsuite/ld-i386/pr22842b.S    | 41 +++++++++++++++++++++++++++++++
 ld/testsuite/ld-x86-64/pr22842a.c  | 20 +++++++++++++++
 ld/testsuite/ld-x86-64/pr22842a.rd |  4 +++
 ld/testsuite/ld-x86-64/pr22842b.S  | 20 +++++++++++++++
 ld/testsuite/ld-x86-64/pr22842b.rd |  4 +++
 ld/testsuite/ld-x86-64/x86-64.exp  | 25 +++++++++++++++++++
 14 files changed, 251 insertions(+), 28 deletions(-)

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 77cdfe8..b3afd99 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,22 @@
+2018-02-14  H.J. Lu  <hongjiu.lu@intel.com>
+
+	PR ld/22842
+	* elf32-i386.c (elf_i386_check_relocs): Pass FALSE for non
+	PC-relative PLT to NEED_DYNAMIC_RELOCATION_P.
+	* elf64-x86-64.c (elf_x86_64_check_relocs): Create PLT for
+	R_X86_64_PC32 reloc against dynamic function in data section.
+	Pass TRUE for PC-relative PLT to NEED_DYNAMIC_RELOCATION_P.
+	(elf_x86_64_relocate_section): Use PLT for R_X86_64_PC32 reloc
+	against dynamic function in data section.
+	* elfxx-x86.c (elf_x86_allocate_dynrelocs): Use PLT in PIE as
+	function address only if pcrel_plt is true.
+	(_bfd_x86_elf_link_hash_table_create): Set pcrel_plt.
+	* elfxx-x86.h (NEED_DYNAMIC_RELOCATION_P): Add PCREL_PLT for
+	PC-relative PLT.  If PLT is PC-relative, don't generate dynamic
+	PC-relative relocation against a function definition in data
+	secton in PIE.  Remove the obsolete comments.
+	(elf_x86_link_hash_table): Add pcrel_plt.
+
 2018-02-13  H.J. Lu  <hongjiu.lu@intel.com>
 
 	* elfxx-x86.c (elf_x86_allocate_dynrelocs): Check bfd_link_dll,
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index e74da3a..1a4b53a 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -1812,7 +1812,7 @@ do_relocation:
 
 	  size_reloc = FALSE;
 do_size:
-	  if (NEED_DYNAMIC_RELOCATION_P (info, h, sec, r_type,
+	  if (NEED_DYNAMIC_RELOCATION_P (info, FALSE, h, sec, r_type,
 					 R_386_32))
 	    {
 	      struct elf_dyn_relocs *p;
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index 0e4bb2e..00ed5d1 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -2135,7 +2135,17 @@ pointer:
 		     as pointer, make sure that PLT is used if foo is
 		     a function defined in a shared library.  */
 		  if ((sec->flags & SEC_CODE) == 0)
-		    h->pointer_equality_needed = 1;
+		    {
+		      h->pointer_equality_needed = 1;
+		      if (bfd_link_pie (info)
+			  && h->type == STT_FUNC
+			  && !h->def_regular
+			  && h->def_dynamic)
+			{
+			  h->needs_plt = 1;
+			  h->plt.refcount = 1;
+			}
+		    }
 		}
 	      else if (r_type != R_X86_64_PC32_BND
 		       && r_type != R_X86_64_PC64)
@@ -2173,7 +2183,7 @@ pointer:
 
 	  size_reloc = FALSE;
 do_size:
-	  if (NEED_DYNAMIC_RELOCATION_P (info, h, sec, r_type,
+	  if (NEED_DYNAMIC_RELOCATION_P (info, TRUE, h, sec, r_type,
 					 htab->pointer_r_type))
 	    {
 	      struct elf_dyn_relocs *p;
@@ -2968,6 +2978,7 @@ do_ifunc_pointer:
 	      break;
 	    }
 
+use_plt:
 	  if (h->plt.offset != (bfd_vma) -1)
 	    {
 	      if (htab->plt_second != NULL)
@@ -3046,6 +3057,15 @@ do_ifunc_pointer:
 		return elf_x86_64_need_pic (info, input_bfd, input_section,
 					    h, NULL, NULL, howto);
 	    }
+	  /* Since x86-64 has PC-relative PLT, we can use PLT in PIE
+	     as function address.  */
+	  else if (h != NULL
+		   && (input_section->flags & SEC_CODE) == 0
+		   && bfd_link_pie (info)
+		   && h->type == STT_FUNC
+		   && !h->def_regular
+		   && h->def_dynamic)
+	    goto use_plt;
 	  /* Fall through.  */
 
 	case R_X86_64_8:
diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c
index bd36707..05d283b 100644
--- a/bfd/elfxx-x86.c
+++ b/bfd/elfxx-x86.c
@@ -179,6 +179,7 @@ elf_x86_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
 	  asection *s = htab->elf.splt;
 	  asection *second_s = htab->plt_second;
 	  asection *got_s = htab->plt_got;
+	  bfd_boolean use_plt;
 
 	  /* If this is the first .plt entry, make room for the special
 	     first entry.  The .plt section is used by prelink to undo
@@ -196,12 +197,19 @@ elf_x86_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
 	    }
 
 	  /* If this symbol is not defined in a regular file, and we are
-	     not generating a shared library, then set the symbol to this
-	     location in the .plt.  This is required to make function
-	     pointers compare as equal between the normal executable and
-	     the shared library.  */
-	  if (! bfd_link_dll (info)
-	      && !h->def_regular)
+	     generating PDE, then set the symbol to this location in the
+	     .plt.  This is required to make function pointers compare
+	     as equal between PDE and the shared library.
+
+	     NB: If PLT is PC-relative, we can use the .plt in PIE for
+	     function address. */
+	  if (h->def_regular)
+	    use_plt = FALSE;
+	  else if (htab->pcrel_plt)
+	    use_plt = ! bfd_link_dll (info);
+	  else
+	    use_plt = bfd_link_pde (info);
+	  if (use_plt)
 	    {
 	      if (use_plt_got)
 		{
@@ -771,6 +779,7 @@ _bfd_x86_elf_link_hash_table_create (bfd *abfd)
       ret->dt_reloc_sz = DT_RELASZ;
       ret->dt_reloc_ent = DT_RELAENT;
       ret->got_entry_size = 8;
+      ret->pcrel_plt = TRUE;
       ret->tls_get_addr = "__tls_get_addr";
     }
   if (ABI_64_P (abfd))
@@ -798,6 +807,7 @@ _bfd_x86_elf_link_hash_table_create (bfd *abfd)
 	  ret->dt_reloc_ent = DT_RELENT;
 	  ret->sizeof_reloc = sizeof (Elf32_External_Rel);
 	  ret->got_entry_size = 4;
+	  ret->pcrel_plt = FALSE;
 	  ret->pointer_r_type = R_386_32;
 	  ret->dynamic_interpreter = ELF32_DYNAMIC_INTERPRETER;
 	  ret->dynamic_interpreter_size
diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h
index 0162a90..f84fe01 100644
--- a/bfd/elfxx-x86.h
+++ b/bfd/elfxx-x86.h
@@ -76,14 +76,11 @@
    into the shared library.  However, if we are linking with -Bsymbolic,
    we do not need to copy a reloc against a global symbol which is
    defined in an object we are including in the link (i.e., DEF_REGULAR
-   is set).  At this point we have not seen all the input files, so it
-   is possible that DEF_REGULAR is not set now but will be set later (it
-   is never cleared).  In case of a weak definition, DEF_REGULAR may be
-   cleared later by a strong definition in a shared library.  We account
-   for that possibility below by storing information in the relocs_copied
-   field of the hash table entry.  A similar situation occurs when
-   creating shared libraries and symbol visibility changes render the
-   symbol local.
+   is set).
+
+   If PCREL_PLT is true, don't generate dynamic relocation in PIE for
+   PC-relative relocation against a dynamic function definition in data
+   section when PLT address can be used.
 
    If on the other hand, we are creating an executable, we may need to
    keep relocations for symbols satisfied by a dynamic library if we
@@ -91,23 +88,30 @@
 
    We also need to generate dynamic pointer relocation against
    STT_GNU_IFUNC symbol in the non-code section.  */
-#define NEED_DYNAMIC_RELOCATION_P(INFO, H, SEC, R_TYPE, POINTER_TYPE) \
+#define NEED_DYNAMIC_RELOCATION_P(INFO, PCREL_PLT, H, SEC, R_TYPE, \
+				  POINTER_TYPE) \
   ((bfd_link_pic (INFO) \
     && (! X86_PCREL_TYPE_P (R_TYPE) \
 	|| ((H) != NULL \
 	    && (! (bfd_link_pie (INFO) \
 		   || SYMBOLIC_BIND ((INFO), (H))) \
 		|| (H)->root.type == bfd_link_hash_defweak \
-		|| !(H)->def_regular)))) \
-		|| ((H) != NULL \
-		    && (H)->type == STT_GNU_IFUNC \
-		    && (R_TYPE) == POINTER_TYPE \
-		    && ((SEC)->flags & SEC_CODE) == 0) \
-		    || (ELIMINATE_COPY_RELOCS \
-			&& !bfd_link_pic (INFO) \
-			&& (H) != NULL \
-			&& ((H)->root.type == bfd_link_hash_defweak \
-			    || !(H)->def_regular)))
+		|| (!(bfd_link_pie (INFO) \
+		      && (PCREL_PLT) \
+		      && (H)->plt.refcount > 0 \
+		      && ((SEC)->flags & SEC_CODE) == 0 \
+		      && (H)->type == STT_FUNC \
+		      && (H)->def_dynamic) \
+		    && !(H)->def_regular))))) \
+   || ((H) != NULL \
+       && (H)->type == STT_GNU_IFUNC \
+       && (R_TYPE) == POINTER_TYPE \
+       && ((SEC)->flags & SEC_CODE) == 0) \
+   || (ELIMINATE_COPY_RELOCS \
+       && !bfd_link_pic (INFO) \
+       && (H) != NULL \
+       && ((H)->root.type == bfd_link_hash_defweak \
+	   || !(H)->def_regular)))
 
 /* TRUE if dynamic relocation should be generated.  Don't copy a
    pc-relative relocation into the output file if the symbol needs
@@ -482,6 +486,14 @@ struct elf_x86_link_hash_table
   /* TRUE if GOT is referenced.  */
   unsigned int got_referenced : 1;
 
+  /* TRUE if PLT is PC-relative.  PLT in PDE and PC-relative PLT in PIE
+     can be used as function address.
+
+     NB: i386 has non-PIC PLT and PIC PLT.  Only non-PIC PLT in PDE can
+     be used as function address.  PIC PLT in PIE can't be used as
+     function address.  */
+  unsigned int pcrel_plt : 1;
+
   bfd_vma (*r_info) (bfd_vma, bfd_vma);
   bfd_vma (*r_sym) (bfd_vma);
   bfd_boolean (*is_reloc_section) (const char *);
diff --git a/ld/ChangeLog b/ld/ChangeLog
index 42ddf8b..c8a967a 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,15 @@
+2018-02-14  H.J. Lu  <hongjiu.lu@intel.com>
+
+	PR ld/22842
+	* testsuite/ld-i386/i386.exp: Run PR ld/22842 tests.
+	* testsuite/ld-x86-64/x86-64.exp: Likewise.
+	* testsuite/ld-i386/pr22842a.c: New file.
+	* testsuite/ld-i386/pr22842b.S: Likewise.
+	* testsuite/ld-x86-64/pr22842a.c: Likewise.
+	* testsuite/ld-x86-64/pr22842a.rd: Likewise.
+	* testsuite/ld-x86-64/pr22842b.S: Likewise.
+	* testsuite/ld-x86-64/pr22842b.rd: Likewise.
+
 2018-02-14  Maciej W. Rozycki  <macro@mips.com>
 
 	* ldlex.h (ldlex_command): Remove prototype.
diff --git a/ld/testsuite/ld-i386/i386.exp b/ld/testsuite/ld-i386/i386.exp
index e4ec07d..ba2cce8 100644
--- a/ld/testsuite/ld-i386/i386.exp
+++ b/ld/testsuite/ld-i386/i386.exp
@@ -1273,6 +1273,14 @@ if { [isnative]
 	    {} \
 	    "pr21997-1.so" \
 	] \
+	[list \
+	    "Build pr22842.so" \
+	    "-shared" \
+	    "-fPIC" \
+	    { pr22842a.c } \
+	    {} \
+	    "pr22842.so" \
+	] \
     ]
 
     run_ld_link_exec_tests [list \
@@ -1371,6 +1379,14 @@ if { [isnative]
 	    "pr21997-1-pie-2" \
 	    "pass.out" \
 	] \
+	[list \
+	    "Build pr22842" \
+	    "-pie -Wl,--no-as-needed tmpdir/pr22842.so" \
+	    "" \
+	    { pr22842b.S } \
+	    "pr22842" \
+	    "pass.out" \
+	] \
     ]
 
     if { [at_least_gcc_version 5 0] } {
diff --git a/ld/testsuite/ld-i386/pr22842a.c b/ld/testsuite/ld-i386/pr22842a.c
new file mode 100644
index 0000000..52489bb
--- /dev/null
+++ b/ld/testsuite/ld-i386/pr22842a.c
@@ -0,0 +1,20 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+void
+test (void)
+{
+  static int count;
+  if (count)
+    printf("PASS\n");
+  count++;
+}
+
+void
+foo (void (*bar) (void))
+{
+  if (bar != test)
+    abort ();
+  bar ();
+  test ();
+}
diff --git a/ld/testsuite/ld-i386/pr22842b.S b/ld/testsuite/ld-i386/pr22842b.S
new file mode 100644
index 0000000..d959a5f
--- /dev/null
+++ b/ld/testsuite/ld-i386/pr22842b.S
@@ -0,0 +1,41 @@
+	.text
+	.globl	main
+	.type	main, @function
+main:
+	leal	4(%esp), %ecx
+	andl	$-16, %esp
+	pushl	-4(%ecx)
+	pushl	%ebp
+	movl	%esp, %ebp
+	pushl	%ebx
+	pushl	%ecx
+	call	__x86.get_pc_thunk.bx
+	addl	$_GLOBAL_OFFSET_TABLE_, %ebx
+	subl	$12, %esp
+	movl	bar@GOT(%ebx), %eax
+	addl	(%eax), %eax
+	pushl	%eax
+	call	foo@PLT
+	addl	$16, %esp
+	leal	-8(%ebp), %esp
+	xorl	%eax, %eax
+	popl	%ecx
+	popl	%ebx
+	popl	%ebp
+	leal	-4(%ecx), %esp
+	ret
+	.size	main, .-main
+	.section	.text.__x86.get_pc_thunk.bx,"axG",@progbits,__x86.get_pc_thunk.bx,comdat
+	.globl	__x86.get_pc_thunk.bx
+	.hidden	__x86.get_pc_thunk.bx
+	.type	__x86.get_pc_thunk.bx, @function
+__x86.get_pc_thunk.bx:
+	movl	(%esp), %ebx
+	ret
+
+	.data
+	.p2align 2
+bar:
+	.long	test - .
+
+	.section	.note.GNU-stack,"",@progbits
diff --git a/ld/testsuite/ld-x86-64/pr22842a.c b/ld/testsuite/ld-x86-64/pr22842a.c
new file mode 100644
index 0000000..52489bb
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22842a.c
@@ -0,0 +1,20 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+void
+test (void)
+{
+  static int count;
+  if (count)
+    printf("PASS\n");
+  count++;
+}
+
+void
+foo (void (*bar) (void))
+{
+  if (bar != test)
+    abort ();
+  bar ();
+  test ();
+}
diff --git a/ld/testsuite/ld-x86-64/pr22842a.rd b/ld/testsuite/ld-x86-64/pr22842a.rd
new file mode 100644
index 0000000..d78ea2f
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22842a.rd
@@ -0,0 +1,4 @@
+#failif
+#...
+[0-9a-f ]+R_X86_64_NONE.*
+#...
diff --git a/ld/testsuite/ld-x86-64/pr22842b.S b/ld/testsuite/ld-x86-64/pr22842b.S
new file mode 100644
index 0000000..f0659cd
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22842b.S
@@ -0,0 +1,20 @@
+	.text
+	.globl	main
+	.type	main,@function
+main:
+	pushq	%rax
+        movslq  bar(%rip), %rax
+        leaq    bar(%rip), %rdi
+	addq	%rax, %rdi
+
+	callq	foo
+	xorl	%eax, %eax
+	popq	%rcx
+	retq
+
+	.data
+	.p2align 2
+bar:
+	.long	test - .
+
+	.section	.note.GNU-stack,"",@progbits
diff --git a/ld/testsuite/ld-x86-64/pr22842b.rd b/ld/testsuite/ld-x86-64/pr22842b.rd
new file mode 100644
index 0000000..f1036d5
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22842b.rd
@@ -0,0 +1,4 @@
+#failif
+#...
+[0-9a-f ]+R_X86_64_PC32 +[0-9a-f]+ +test \+ 0
+#...
diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp
index 8442663..2a46266 100644
--- a/ld/testsuite/ld-x86-64/x86-64.exp
+++ b/ld/testsuite/ld-x86-64/x86-64.exp
@@ -1190,6 +1190,23 @@ if { [isnative] && [which $CC] != 0 } {
 	    {{readelf -drW pr22791-2.rd}} \
 	    "pr22791-2" \
 	] \
+	[list \
+	    "Build pr22842.so" \
+	    "-shared" \
+	    "-fPIC" \
+	    { pr22842a.c } \
+	    {} \
+	    "pr22842.so" \
+	] \
+	[list \
+	    "Build pr22842" \
+	    "-pie -Wl,--no-as-needed tmpdir/pr22842.so" \
+	    "" \
+	    { pr22842b.S } \
+	    {{readelf -rW pr22842a.rd} \
+	     {readelf -rW pr22842b.rd}} \
+	    "pr22842" \
+	] \
     ]
 
     if  {[istarget "x86_64-*-linux*-gnux32"]} {
@@ -1524,6 +1541,14 @@ if { [isnative] && [which $CC] != 0 } {
 	    "pass.out" \
 	    "$NOPIE_CFLAGS" \
 	] \
+	[list \
+	    "Build pr22842" \
+	    "-pie -Wl,--no-as-needed tmpdir/pr22842.so" \
+	    "" \
+	    { pr22842b.S } \
+	    "pr22842" \
+	    "pass.out" \
+	] \
     ]
 
     # Run-time tests which require working ifunc attribute support.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]