x86-64: Treat PC32 relocation with branch as PLT32

Message ID 20180206133536.10841-1-hjl.tools@gmail.com
State New
Headers show
Series
  • x86-64: Treat PC32 relocation with branch as PLT32
Related show

Commit Message

H.J. Lu Feb. 6, 2018, 1:35 p.m.
Since there is no need to prepare for PLT branch on x86-64, we can treat
PC32 relocation with branch as PLT32 relocation.  It allows building PIE
and shared objects from PC32 relocation with branch.

bfd/

	PR ld/22791
	* elf64-x86-64.c (is_32bit_relative_branch): Moved.
	(elf_x86_64_check_relocs): Treat PC32 relocations with branch
	as PLT32.
	(elf_x86_64_relocate_section): Check PIC relocations in PIE.
	Use PLT for PC32 relocations with branch.

ld/

	PR ld/22791
	* testsuite/ld-x86-64/x86-64.exp: Run PR ld/22791 tests.
	* testsuite/ld-x86-64/pr22791-1.err: New file.
	* testsuite/ld-x86-64/pr22791-1a.c: Likewise.
	* testsuite/ld-x86-64/pr22791-1b.s: Likewise.
	* testsuite/ld-x86-64/pr22791-2.rd: Likewise.
	* testsuite/ld-x86-64/pr22791-2a.c: Likewise.
	* testsuite/ld-x86-64/pr22791-2b.c: Likewise.
	* testsuite/ld-x86-64/pr22791-2c.c: Likewise.
---
 bfd/elf64-x86-64.c                   | 67 +++++++++++++++++++++++-------------
 ld/testsuite/ld-x86-64/pr22791-1.err |  2 ++
 ld/testsuite/ld-x86-64/pr22791-1a.c  |  4 +++
 ld/testsuite/ld-x86-64/pr22791-1b.s  |  6 ++++
 ld/testsuite/ld-x86-64/pr22791-2.rd  |  6 ++++
 ld/testsuite/ld-x86-64/pr22791-2a.c  |  7 ++++
 ld/testsuite/ld-x86-64/pr22791-2b.c  |  7 ++++
 ld/testsuite/ld-x86-64/pr22791-2c.c  |  8 +++++
 ld/testsuite/ld-x86-64/x86-64.exp    | 47 +++++++++++++++++++++++++
 9 files changed, 131 insertions(+), 23 deletions(-)
 create mode 100644 ld/testsuite/ld-x86-64/pr22791-1.err
 create mode 100644 ld/testsuite/ld-x86-64/pr22791-1a.c
 create mode 100644 ld/testsuite/ld-x86-64/pr22791-1b.s
 create mode 100644 ld/testsuite/ld-x86-64/pr22791-2.rd
 create mode 100644 ld/testsuite/ld-x86-64/pr22791-2a.c
 create mode 100644 ld/testsuite/ld-x86-64/pr22791-2b.c
 create mode 100644 ld/testsuite/ld-x86-64/pr22791-2c.c

-- 
2.14.3

Comments

Florian Weimer Feb. 6, 2018, 2:55 p.m. | #1
On 02/06/2018 02:35 PM, H.J. Lu wrote:
> +/* Is the instruction before OFFSET in CONTENTS a 32bit relative

> +   branch?  */

> +

> +static bfd_boolean

> +is_32bit_relative_branch (bfd_byte *contents, bfd_vma offset)

> +{

> +  /* Opcode		Instruction

> +     0xe8		call

> +     0xe9		jump

> +     0x0f 0x8x		conditional jump */

> +  return ((offset > 0

> +	   && (contents [offset - 1] == 0xe8

> +	       || contents [offset - 1] == 0xe9))

> +	  || (offset > 1

> +	      && contents [offset - 2] == 0x0f

> +	      && (contents [offset - 1] & 0xf0) == 0x80));

> +}


How is this safe, considering that R_X86_64_PC32 is also used for jump 
tables and the like?

Thanks,
Florian
Cary Coutant Feb. 6, 2018, 6:15 p.m. | #2
> How is this safe, considering that R_X86_64_PC32 is also used for jump

> tables and the like?


Agreed.

If it's a branch instruction that could be treated as PLT32, the
compiler should emit a PLT32 reloc. We already reduce PLT32 to PC32 in
the linker when the symbol is fully resolved, so the effect is the
same, but without the danger of accidentally changing a non-branch.

-cary
H.J. Lu Feb. 6, 2018, 6:42 p.m. | #3
On Tue, Feb 6, 2018 at 10:15 AM, Cary Coutant <ccoutant@gmail.com> wrote:
>> How is this safe, considering that R_X86_64_PC32 is also used for jump

>> tables and the like?

>

> Agreed.

>

> If it's a branch instruction that could be treated as PLT32, the

> compiler should emit a PLT32 reloc. We already reduce PLT32 to PC32 in

> the linker when the symbol is fully resolved, so the effect is the

> same, but without the danger of accidentally changing a non-branch.

>


Here is a patch to generate PLT32 reloc in assembler.  No compiler change
is needed.

-- 
H.J.
From dd1f094bd81560d6c7d8c8b1a6fce7a18ee1feee Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Tue, 6 Feb 2018 05:23:04 -0800
Subject: [PATCH] x86-64: Generate branch with PLT32 relocation

Since there is no need to prepare for PLT branch on x86-64, generate
R_X86_64_PLT32, instead of R_X86_64_PC32, if possible, which can be
used as a marker for 32-bit PC-relative branches.

bfd/

	PR ld/22791
	* elf64-x86-64.c (is_32bit_relative_branch): Removed.
	(elf_x86_64_relocate_section): Check PIC relocations in PIE.
	Remove is_32bit_relative_branch usage.  Disallow PC32 reloc
	against protected function in shared object.

gas/

	* config/tc-i386.c (need_plt32_p): New function.
	(output_jump): Generate BFD_RELOC_X86_64_PLT32 if possible.
	(md_estimate_size_before_relax): Likewise.
	* testsuite/gas/i386/reloc64.d: Updated.
	* testsuite/gas/i386/x86-64-jump.d: Likewise.
	* testsuite/gas/i386/x86-64-mpx-branch-1.d: Likewise.
	* testsuite/gas/i386/x86-64-mpx-branch-2.d: Likewise.
	* testsuite/gas/i386/x86-64-relax-2.d: Likewise.
	* testsuite/gas/i386/x86-64-relax-3.d: Likewise.
	* testsuite/gas/i386/ilp32/reloc64.d: Likewise.
	* testsuite/gas/i386/ilp32/x86-64-branch.d: Likewise.

ld/

	PR ld/22791
	* testsuite/ld-x86-64/x86-64.exp: Run PR ld/22791 tests.
	* testsuite/ld-x86-64/pr22791-1.err: New file.
	* testsuite/ld-x86-64/pr22791-1a.c: Likewise.
	* testsuite/ld-x86-64/pr22791-1b.s: Likewise.
	* testsuite/ld-x86-64/pr22791-2.rd: Likewise.
	* testsuite/ld-x86-64/pr22791-2a.c: Likewise.
	* testsuite/ld-x86-64/pr22791-2b.c: Likewise.
	* testsuite/ld-x86-64/pr22791-2c.c: Likewise.
---
 bfd/elf64-x86-64.c                           | 45 +++++++---------------
 gas/config/tc-i386.c                         | 57 +++++++++++++++++++++++++++-
 gas/testsuite/gas/i386/ilp32/reloc64.d       |  2 +-
 gas/testsuite/gas/i386/ilp32/x86-64-branch.d |  6 +--
 gas/testsuite/gas/i386/reloc64.d             |  2 +-
 gas/testsuite/gas/i386/x86-64-jump.d         |  4 +-
 gas/testsuite/gas/i386/x86-64-mpx-branch-1.d |  6 +--
 gas/testsuite/gas/i386/x86-64-mpx-branch-2.d |  6 +--
 gas/testsuite/gas/i386/x86-64-relax-2.d      |  4 +-
 gas/testsuite/gas/i386/x86-64-relax-3.d      |  2 +-
 ld/testsuite/ld-x86-64/pr22791-1.err         |  2 +
 ld/testsuite/ld-x86-64/pr22791-1a.c          |  4 ++
 ld/testsuite/ld-x86-64/pr22791-1b.s          |  6 +++
 ld/testsuite/ld-x86-64/pr22791-2.rd          |  6 +++
 ld/testsuite/ld-x86-64/pr22791-2a.c          |  7 ++++
 ld/testsuite/ld-x86-64/pr22791-2b.c          |  7 ++++
 ld/testsuite/ld-x86-64/pr22791-2c.c          |  8 ++++
 ld/testsuite/ld-x86-64/x86-64.exp            | 47 +++++++++++++++++++++++
 18 files changed, 172 insertions(+), 49 deletions(-)
 create mode 100644 ld/testsuite/ld-x86-64/pr22791-1.err
 create mode 100644 ld/testsuite/ld-x86-64/pr22791-1a.c
 create mode 100644 ld/testsuite/ld-x86-64/pr22791-1b.s
 create mode 100644 ld/testsuite/ld-x86-64/pr22791-2.rd
 create mode 100644 ld/testsuite/ld-x86-64/pr22791-2a.c
 create mode 100644 ld/testsuite/ld-x86-64/pr22791-2b.c
 create mode 100644 ld/testsuite/ld-x86-64/pr22791-2c.c

diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index aad9b85296..aa6a47121b 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -2307,24 +2307,6 @@ elf_x86_64_tpoff (struct bfd_link_info *info, bfd_vma address)
   return address - static_tls_size - htab->tls_sec->vma;
 }
 
-/* Is the instruction before OFFSET in CONTENTS a 32bit relative
-   branch?  */
-
-static bfd_boolean
-is_32bit_relative_branch (bfd_byte *contents, bfd_vma offset)
-{
-  /* Opcode		Instruction
-     0xe8		call
-     0xe9		jump
-     0x0f 0x8x		conditional jump */
-  return ((offset > 0
-	   && (contents [offset - 1] == 0xe8
-	       || contents [offset - 1] == 0xe9))
-	  || (offset > 1
-	      && contents [offset - 2] == 0x0f
-	      && (contents [offset - 1] & 0xf0) == 0x80));
-}
-
 /* Relocate an x86_64 ELF section.  */
 
 static bfd_boolean
@@ -3023,14 +3005,18 @@ do_ifunc_pointer:
 	case R_X86_64_PC32:
 	case R_X86_64_PC32_BND:
 	  /* Don't complain about -fPIC if the symbol is undefined when
-	     building executable unless it is unresolved weak symbol or
-	     -z nocopyreloc is used.  */
+	     building executable unless it is unresolved weak symbol,
+	     references a dynamic definition in PIE or -z nocopyreloc
+	     is used.  */
 	  if ((input_section->flags & SEC_ALLOC) != 0
 	      && (input_section->flags & SEC_READONLY) != 0
 	      && h != NULL
 	      && ((bfd_link_executable (info)
 		   && ((h->root.type == bfd_link_hash_undefweak
 			&& !resolved_to_zero)
+		       || (bfd_link_pie (info)
+			   && !h->def_regular
+			   && h->def_dynamic)
 		       || ((info->nocopyreloc
 			    || (eh->def_protected
 				&& elf_has_no_copy_on_protected (h->root.u.def.section->owner)))
@@ -3039,26 +3025,21 @@ do_ifunc_pointer:
 		  || bfd_link_dll (info)))
 	    {
 	      bfd_boolean fail = FALSE;
-	      bfd_boolean branch
-		= ((r_type == R_X86_64_PC32
-		    || r_type == R_X86_64_PC32_BND)
-		   && is_32bit_relative_branch (contents, rel->r_offset));
-
 	      if (SYMBOL_REFERENCES_LOCAL_P (info, h))
 		{
 		  /* Symbol is referenced locally.  Make sure it is
-		     defined locally or for a branch.  */
-		  fail = (!(h->def_regular || ELF_COMMON_DEF_P (h))
-			  && !branch);
+		     defined locally.  */
+		  fail = !(h->def_regular || ELF_COMMON_DEF_P (h));
 		}
 	      else if (!(bfd_link_pie (info)
 			 && (h->needs_copy || eh->needs_copy)))
 		{
 		  /* Symbol doesn't need copy reloc and isn't referenced
-		     locally.  We only allow branch to symbol with
-		     non-default visibility. */
-		  fail = (!branch
-			  || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT);
+		     locally.  Address of protected function may not be
+		     reachable at run-time.  */
+		  fail = (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+			  || (ELF_ST_VISIBILITY (h->other) == STV_PROTECTED
+			      && h->type == STT_FUNC));
 		}
 
 	      if (fail)
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index 32a8b31d30..357e561bfe 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -7023,12 +7023,54 @@ output_branch (void)
   frag_var (rs_machine_dependent, 5, i.reloc[0], subtype, sym, off, p);
 }
 
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+/* Return TRUE iff PLT32 relocation should be used for branching to
+   symbol S.  */
+
+static bfd_boolean
+need_plt32_p (symbolS *s)
+{
+  /* PLT32 relocation is ELF only.  */
+  if (!IS_ELF)
+    return FALSE;
+
+  /* Since there is no need to prepare for PLT branch on x86-64, we
+     can generate R_X86_64_PLT32, instead of R_X86_64_PC32, which can
+     be used as a marker for 32-bit PC-relative branches.  */
+  if (!object_64bit)
+    return FALSE;
+
+  /* Global symbol with hidden or internal visibilities doesn't need
+     PLT32 relocation.  */
+  switch (ELF_ST_VISIBILITY (S_GET_OTHER (s)))
+    {
+    default:
+      break;
+    case STV_INTERNAL:
+    case STV_HIDDEN:
+      return FALSE;
+    }
+
+  /* Weak or undefined symbol need PLT32 relocation.  */
+  if (S_IS_WEAK (s) || !S_IS_DEFINED (s))
+    return TRUE;
+
+  /* Non-global symbol doesn't need PLT32 relocation.  */
+  if (! S_IS_EXTERNAL (s))
+    return FALSE;
+
+  /* Other global symbols need PLT32 relocation.  */
+  return TRUE;
+}
+#endif
+
 static void
 output_jump (void)
 {
   char *p;
   int size;
   fixS *fixP;
+  bfd_reloc_code_real_type jump_reloc = i.reloc[0];
 
   if (i.tm.opcode_modifier.jumpbyte)
     {
@@ -7096,8 +7138,17 @@ output_jump (void)
       abort ();
     }
 
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+  if (size == 4
+      && jump_reloc == NO_RELOC
+      && need_plt32_p (i.op[0].disps->X_add_symbol))
+    jump_reloc = BFD_RELOC_X86_64_PLT32;
+#endif
+
+  jump_reloc = reloc (size, 1, 1, jump_reloc);
+
   fixP = fix_new_exp (frag_now, p - frag_now->fr_literal, size,
-		      i.op[0].disps, 1, reloc (size, 1, 1, i.reloc[0]));
+		      i.op[0].disps, 1, jump_reloc);
 
   /* All jumps handled here are signed, but don't use a signed limit
      check for 32 and 16 bit jumps as we want to allow wrap around at
@@ -9315,6 +9366,10 @@ md_estimate_size_before_relax (fragS *fragP, segT segment)
 	reloc_type = (enum bfd_reloc_code_real) fragP->fr_var;
       else if (size == 2)
 	reloc_type = BFD_RELOC_16_PCREL;
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+      else if (need_plt32_p (fragP->fr_symbol))
+	reloc_type = BFD_RELOC_X86_64_PLT32;
+#endif
       else
 	reloc_type = BFD_RELOC_32_PCREL;
 
diff --git a/gas/testsuite/gas/i386/ilp32/reloc64.d b/gas/testsuite/gas/i386/ilp32/reloc64.d
index 53083f31d2..f6bc628448 100644
--- a/gas/testsuite/gas/i386/ilp32/reloc64.d
+++ b/gas/testsuite/gas/i386/ilp32/reloc64.d
@@ -16,7 +16,7 @@ Disassembly of section \.text:
 .*[ 	]+R_X86_64_PC8[ 	]+xtrn\+0x0*1
 .*[ 	]+R_X86_64_PC32[ 	]+xtrn-0x0*4
 .*[ 	]+R_X86_64_PC32[ 	]+xtrn-0x0*4
-.*[ 	]+R_X86_64_PC32[ 	]+xtrn-0x0*4
+.*[ 	]+R_X86_64_PLT32[ 	]+xtrn-0x0*4
 .*[ 	]+R_X86_64_PC8[ 	]+xtrn-0x0*1
 .*[ 	]+R_X86_64_GOT32[ 	]+xtrn
 .*[ 	]+R_X86_64_GOT32[ 	]+xtrn
diff --git a/gas/testsuite/gas/i386/ilp32/x86-64-branch.d b/gas/testsuite/gas/i386/ilp32/x86-64-branch.d
index 915dbf3f1c..45ab6178b9 100644
--- a/gas/testsuite/gas/i386/ilp32/x86-64-branch.d
+++ b/gas/testsuite/gas/i386/ilp32/x86-64-branch.d
@@ -20,9 +20,9 @@ Disassembly of section .text:
 [ 	]*[a-f0-9]+:	66 ff 20             	data16 jmpq \*\(%rax\)
 [ 	]*[a-f0-9]+:	e8 00 00 00 00       	callq  0x1f	1b: R_X86_64_PC32	\*ABS\*\+0x10003c
 [ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   0x24	20: R_X86_64_PC32	\*ABS\*\+0x10003c
-[ 	]*[a-f0-9]+:	66 e8 00 00 00 00    	data16 callq 0x2a	26: R_X86_64_PC32	foo-0x4
-[ 	]*[a-f0-9]+:	66 e9 00 00 00 00    	data16 jmpq 0x30	2c: R_X86_64_PC32	foo-0x4
-[ 	]*[a-f0-9]+:	66 0f 82 00 00 00 00 	data16 jb 0x37	33: R_X86_64_PC32	foo-0x4
+[ 	]*[a-f0-9]+:	66 e8 00 00 00 00    	data16 callq 0x2a	26: R_X86_64_PLT32	foo-0x4
+[ 	]*[a-f0-9]+:	66 e9 00 00 00 00    	data16 jmpq 0x30	2c: R_X86_64_PLT32	foo-0x4
+[ 	]*[a-f0-9]+:	66 0f 82 00 00 00 00 	data16 jb 0x37	33: R_X86_64_PLT32	foo-0x4
 [ 	]*[a-f0-9]+:	ff d0                	callq  \*%rax
 [ 	]*[a-f0-9]+:	ff d0                	callq  \*%rax
 [ 	]*[a-f0-9]+:	66 ff d0             	data16 callq \*%rax
diff --git a/gas/testsuite/gas/i386/reloc64.d b/gas/testsuite/gas/i386/reloc64.d
index a7fd3d6a3d..4cf884dc7b 100644
--- a/gas/testsuite/gas/i386/reloc64.d
+++ b/gas/testsuite/gas/i386/reloc64.d
@@ -18,7 +18,7 @@ Disassembly of section \.text:
 .*[ 	]+R_X86_64_PC8[ 	]+xtrn\+0x0*1
 .*[ 	]+R_X86_64_PC32[ 	]+xtrn-0x0*4
 .*[ 	]+R_X86_64_PC32[ 	]+xtrn-0x0*4
-.*[ 	]+R_X86_64_PC32[ 	]+xtrn-0x0*4
+.*[ 	]+R_X86_64_PLT32[ 	]+xtrn-0x0*4
 .*[ 	]+R_X86_64_PC8[ 	]+xtrn-0x0*1
 .*[ 	]+R_X86_64_GOT64[ 	]+xtrn
 .*[ 	]+R_X86_64_GOT32[ 	]+xtrn
diff --git a/gas/testsuite/gas/i386/x86-64-jump.d b/gas/testsuite/gas/i386/x86-64-jump.d
index edb34e6aa8..9f7b4b4848 100644
--- a/gas/testsuite/gas/i386/x86-64-jump.d
+++ b/gas/testsuite/gas/i386/x86-64-jump.d
@@ -8,7 +8,7 @@ Disassembly of section .text:
 
 0+ <.text>:
 [ 	]*[a-f0-9]+:	eb fe                	jmp    (0x0|0 <.text>)
-[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   0x7	3: R_X86_64_PC32	xxx-0x4
+[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   0x7	3: R_X86_64_PLT32	xxx-0x4
 [ 	]*[a-f0-9]+:	ff 24 25 00 00 00 00 	jmpq   \*0x0	a: R_X86_64_32S	xxx
 [ 	]*[a-f0-9]+:	ff e7                	jmpq   \*%rdi
 [ 	]*[a-f0-9]+:	ff 27                	jmpq   \*\(%rdi\)
@@ -17,7 +17,7 @@ Disassembly of section .text:
 [ 	]*[a-f0-9]+:	ff 2c 25 00 00 00 00 	ljmp   \*0x0	24: R_X86_64_32S	xxx
 [ 	]*[a-f0-9]+:	66 ff 2c 25 00 00 00 00 	ljmpw  \*0x0	2c: R_X86_64_32S	xxx
 [ 	]*[a-f0-9]+:	e8 cb ff ff ff       	callq  0x0
-[ 	]*[a-f0-9]+:	e8 00 00 00 00       	callq  0x3a	36: R_X86_64_PC32	xxx-0x4
+[ 	]*[a-f0-9]+:	e8 00 00 00 00       	callq  0x3a	36: R_X86_64_PLT32	xxx-0x4
 [ 	]*[a-f0-9]+:	ff 14 25 00 00 00 00 	callq  \*0x0	3d: R_X86_64_32S	xxx
 [ 	]*[a-f0-9]+:	ff d7                	callq  \*%rdi
 [ 	]*[a-f0-9]+:	ff 17                	callq  \*\(%rdi\)
diff --git a/gas/testsuite/gas/i386/x86-64-mpx-branch-1.d b/gas/testsuite/gas/i386/x86-64-mpx-branch-1.d
index c07002911c..d44841e745 100644
--- a/gas/testsuite/gas/i386/x86-64-mpx-branch-1.d
+++ b/gas/testsuite/gas/i386/x86-64-mpx-branch-1.d
@@ -20,9 +20,9 @@ Disassembly of section .text:
 [ 	]*[a-f0-9]+:	f2 e8 00 00 00 00    	bnd callq 24 <foo2>
 
 0+24 <foo2>:
-[ 	]*[a-f0-9]+:	f2 e9 00 00 00 00    	bnd jmpq 2a <foo2\+0x6>	26: R_X86_64_PC32	foo-0x4
-[ 	]*[a-f0-9]+:	f2 0f 82 00 00 00 00 	bnd jb 31 <foo2\+0xd>	2d: R_X86_64_PC32	foo-0x4
-[ 	]*[a-f0-9]+:	f2 e8 00 00 00 00    	bnd callq 37 <foo2\+0x13>	33: R_X86_64_PC32	foo-0x4
+[ 	]*[a-f0-9]+:	f2 e9 00 00 00 00    	bnd jmpq 2a <foo2\+0x6>	26: R_X86_64_PLT32	foo-0x4
+[ 	]*[a-f0-9]+:	f2 0f 82 00 00 00 00 	bnd jb 31 <foo2\+0xd>	2d: R_X86_64_PLT32	foo-0x4
+[ 	]*[a-f0-9]+:	f2 e8 00 00 00 00    	bnd callq 37 <foo2\+0x13>	33: R_X86_64_PLT32	foo-0x4
 [ 	]*[a-f0-9]+:	f2 e9 00 00 00 00    	bnd jmpq 3d <foo2\+0x19>	39: R_X86_64_PLT32	foo-0x4
 [ 	]*[a-f0-9]+:	f2 0f 82 00 00 00 00 	bnd jb 44 <foo2\+0x20>	40: R_X86_64_PLT32	foo-0x4
 [ 	]*[a-f0-9]+:	f2 e8 00 00 00 00    	bnd callq 4a <foo2\+0x26>	46: R_X86_64_PLT32	foo-0x4
diff --git a/gas/testsuite/gas/i386/x86-64-mpx-branch-2.d b/gas/testsuite/gas/i386/x86-64-mpx-branch-2.d
index 5bb6a57c1e..514c34363e 100644
--- a/gas/testsuite/gas/i386/x86-64-mpx-branch-2.d
+++ b/gas/testsuite/gas/i386/x86-64-mpx-branch-2.d
@@ -20,9 +20,9 @@ Disassembly of section .text:
 [ 	]*[a-f0-9]+:	f2 e8 00 00 00 00    	bnd callq 24 <foo2>
 
 0+24 <foo2>:
-[ 	]*[a-f0-9]+:	f2 e9 00 00 00 00    	bnd jmpq 2a <foo2\+0x6>	26: R_X86_64_PC32	foo-0x4
-[ 	]*[a-f0-9]+:	f2 0f 82 00 00 00 00 	bnd jb 31 <foo2\+0xd>	2d: R_X86_64_PC32	foo-0x4
-[ 	]*[a-f0-9]+:	f2 e8 00 00 00 00    	bnd callq 37 <foo2\+0x13>	33: R_X86_64_PC32	foo-0x4
+[ 	]*[a-f0-9]+:	f2 e9 00 00 00 00    	bnd jmpq 2a <foo2\+0x6>	26: R_X86_64_PLT32	foo-0x4
+[ 	]*[a-f0-9]+:	f2 0f 82 00 00 00 00 	bnd jb 31 <foo2\+0xd>	2d: R_X86_64_PLT32	foo-0x4
+[ 	]*[a-f0-9]+:	f2 e8 00 00 00 00    	bnd callq 37 <foo2\+0x13>	33: R_X86_64_PLT32	foo-0x4
 [ 	]*[a-f0-9]+:	f2 e9 00 00 00 00    	bnd jmpq 3d <foo2\+0x19>	39: R_X86_64_PLT32	foo-0x4
 [ 	]*[a-f0-9]+:	f2 0f 82 00 00 00 00 	bnd jb 44 <foo2\+0x20>	40: R_X86_64_PLT32	foo-0x4
 [ 	]*[a-f0-9]+:	f2 e8 00 00 00 00    	bnd callq 4a <foo2\+0x26>	46: R_X86_64_PLT32	foo-0x4
diff --git a/gas/testsuite/gas/i386/x86-64-relax-2.d b/gas/testsuite/gas/i386/x86-64-relax-2.d
index c124102982..a65d4b2132 100644
--- a/gas/testsuite/gas/i386/x86-64-relax-2.d
+++ b/gas/testsuite/gas/i386/x86-64-relax-2.d
@@ -10,9 +10,9 @@ Disassembly of section .text:
 0+ <foo>:
 [ 	]*[a-f0-9]+:	eb 24                	jmp    26 <local>
 [ 	]*[a-f0-9]+:	eb 1e                	jmp    22 <hidden_def>
-[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   9 <foo\+0x9>	5: R_X86_64_PC32	global_def-0x4
+[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   9 <foo\+0x9>	5: R_X86_64_PLT32	global_def-0x4
 [ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   e <foo\+0xe>	a: R_X86_64_PLT32	global_def-0x4
-[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   13 <foo\+0x13>	f: R_X86_64_PC32	weak_def-0x4
+[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   13 <foo\+0x13>	f: R_X86_64_PLT32	weak_def-0x4
 [ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   18 <foo\+0x18>	14: R_X86_64_PC32	weak_hidden_undef-0x4
 [ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   1d <foo\+0x1d>	19: R_X86_64_PC32	weak_hidden_def-0x4
 [ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   22 <hidden_def>	1e: R_X86_64_PC32	hidden_undef-0x4
diff --git a/gas/testsuite/gas/i386/x86-64-relax-3.d b/gas/testsuite/gas/i386/x86-64-relax-3.d
index 98fd28dd11..b87a19ce53 100644
--- a/gas/testsuite/gas/i386/x86-64-relax-3.d
+++ b/gas/testsuite/gas/i386/x86-64-relax-3.d
@@ -11,7 +11,7 @@ Disassembly of section .text:
 [ 	]*[a-f0-9]+:	eb 1b                	jmp    1f <hidden_def>
 [ 	]*[a-f0-9]+:	eb 1b                	jmp    21 <global_def>
 [ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   b <foo\+0xb>	7: R_X86_64_PLT32	global_def-0x4
-[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   10 <foo\+0x10>	c: R_X86_64_PC32	weak_def-0x4
+[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   10 <foo\+0x10>	c: R_X86_64_PLT32	weak_def-0x4
 [ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   15 <foo\+0x15>	11: R_X86_64_PC32	weak_hidden_undef-0x4
 [ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   1a <foo\+0x1a>	16: R_X86_64_PC32	weak_hidden_def-0x4
 [ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   1f <hidden_def>	1b: R_X86_64_PC32	hidden_undef-0x4
diff --git a/ld/testsuite/ld-x86-64/pr22791-1.err b/ld/testsuite/ld-x86-64/pr22791-1.err
new file mode 100644
index 0000000000..5500fa55ce
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22791-1.err
@@ -0,0 +1,2 @@
+.*relocation R_X86_64_PC32 against symbol `foo' can not be used when making a PIE object; recompile with -fPIC
+#...
diff --git a/ld/testsuite/ld-x86-64/pr22791-1a.c b/ld/testsuite/ld-x86-64/pr22791-1a.c
new file mode 100644
index 0000000000..cd0130cacd
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22791-1a.c
@@ -0,0 +1,4 @@
+void
+foo (void)
+{
+}
diff --git a/ld/testsuite/ld-x86-64/pr22791-1b.s b/ld/testsuite/ld-x86-64/pr22791-1b.s
new file mode 100644
index 0000000000..9751db49aa
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22791-1b.s
@@ -0,0 +1,6 @@
+	.text
+	.globl	main
+	.type	main, @function
+main:
+	movl	foo(%rip), %eax
+	.size	main, .-main
diff --git a/ld/testsuite/ld-x86-64/pr22791-2.rd b/ld/testsuite/ld-x86-64/pr22791-2.rd
new file mode 100644
index 0000000000..70deb30d84
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22791-2.rd
@@ -0,0 +1,6 @@
+#failif
+#...
+.*\(TEXTREL\).*
+#...
+[0-9a-f ]+R_X86_64_NONE.*
+#...
diff --git a/ld/testsuite/ld-x86-64/pr22791-2a.c b/ld/testsuite/ld-x86-64/pr22791-2a.c
new file mode 100644
index 0000000000..8b23ec8f2b
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22791-2a.c
@@ -0,0 +1,7 @@
+extern void bar (void);
+
+void
+foo (void)
+{
+  bar ();
+}
diff --git a/ld/testsuite/ld-x86-64/pr22791-2b.c b/ld/testsuite/ld-x86-64/pr22791-2b.c
new file mode 100644
index 0000000000..79ef27c085
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22791-2b.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+void
+bar (void)
+{
+  puts ("PASS");
+}
diff --git a/ld/testsuite/ld-x86-64/pr22791-2c.c b/ld/testsuite/ld-x86-64/pr22791-2c.c
new file mode 100644
index 0000000000..f1cb6b492b
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22791-2c.c
@@ -0,0 +1,8 @@
+extern void foo (void);
+
+int
+main (void)
+{
+  foo ();
+  return 0;
+}
diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp
index af3afcc2c7..8dac1c4dfa 100644
--- a/ld/testsuite/ld-x86-64/x86-64.exp
+++ b/ld/testsuite/ld-x86-64/x86-64.exp
@@ -1152,6 +1152,44 @@ if { [isnative] && [which $CC] != 0 } {
 	     {readelf -lW pr22393-3b.rd}} \
 	    "pr22393-3-static" \
 	] \
+	[list \
+	    "Build pr22791-1.so" \
+	    "-shared" \
+	    "-fPIC" \
+	    { pr22791-1a.c } \
+	    {} \
+	    "pr22791-1.so" \
+	] \
+	[list \
+	    "Build pr22791-1" \
+	    "-pie -Wl,--no-as-needed tmpdir/pr22791-1.so" \
+	    "$NOPIE_CFLAGS" \
+	    { pr22791-1b.s } \
+	    {{error_output "pr22791-1.err"}} \
+	    "pr22791-1" \
+	] \
+	[list \
+	    "Build pr22791-2a.o" \
+	    "" \
+	    "-fno-PIC $NOPIE_CFLAGS" \
+	    { pr22791-2a.c } \
+	] \
+	[list \
+	    "Build pr22791-2.so" \
+	    "-shared tmpdir/pr22791-2a.o" \
+	    "-fPIC" \
+	    { pr22791-2b.c } \
+	    {{readelf -drW pr22791-2.rd}} \
+	    "pr22791-2.so" \
+	] \
+	[list \
+	    "Build pr22791-2" \
+	    "-pie -Wl,--no-as-needed tmpdir/pr22791-2.so" \
+	    "$NOPIE_CFLAGS" \
+	    { pr22791-2c.c } \
+	    {{readelf -drW pr22791-2.rd}} \
+	    "pr22791-2" \
+	] \
     ]
 
     if  {[istarget "x86_64-*-linux*-gnux32"]} {
@@ -1477,6 +1515,15 @@ if { [isnative] && [which $CC] != 0 } {
 	    "pr22393-3-static" \
 	    "pass.out" \
 	] \
+	[list \
+	    "Run pr22791-2" \
+	    "-pie -Wl,--no-as-needed tmpdir/pr22791-2.so" \
+	    "" \
+	    { pr22791-2c.c } \
+	    "pr22791-2" \
+	    "pass.out" \
+	    "$NOPIE_CFLAGS" \
+	] \
     ]
 
     # Run-time tests which require working ifunc attribute support.
H.J. Lu Feb. 8, 2018, 3:56 p.m. | #4
On Tue, Feb 6, 2018 at 6:55 AM, Florian Weimer <fweimer@redhat.com> wrote:
> On 02/06/2018 02:35 PM, H.J. Lu wrote:

>>

>> +/* Is the instruction before OFFSET in CONTENTS a 32bit relative

>> +   branch?  */

>> +

>> +static bfd_boolean

>> +is_32bit_relative_branch (bfd_byte *contents, bfd_vma offset)

>> +{

>> +  /* Opcode            Instruction

>> +     0xe8              call

>> +     0xe9              jump

>> +     0x0f 0x8x         conditional jump */

>> +  return ((offset > 0

>> +          && (contents [offset - 1] == 0xe8

>> +              || contents [offset - 1] == 0xe9))

>> +         || (offset > 1

>> +             && contents [offset - 2] == 0x0f

>> +             && (contents [offset - 1] & 0xf0) == 0x80));

>> +}

>

>

> How is this safe, considering that R_X86_64_PC32 is also used for jump

> tables and the like?

>


You are right.  This function should be removed.  Instead, we should generate
R_X86_64_PLT32 for 32-bit PC-relative branches:

https://groups.google.com/forum/#!topic/x86-64-abi/oJq_dXT9on8

I will check in this patch next week.

-- 
H.J.
From 13162e84cdd57ac1cf1346e4e7770dc559498573 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Tue, 6 Feb 2018 05:23:04 -0800
Subject: [PATCH] x86-64: Generate branch with PLT32 relocation

Since there is no need to prepare for PLT branch on x86-64, generate
R_X86_64_PLT32, instead of R_X86_64_PC32, if possible, which can be
used as a marker for 32-bit PC-relative branches.

To compiler Linux, this patch:

From: "H.J. Lu" <hjl.tools@gmail.com>
Subject: [PATCH] x86: Treat R_X86_64_PLT32 as R_X86_64_PC32

On i386, there are 2 types of PLTs, PIC and non-PIC.  PIE and shared
objects must use PIC PLT.  To use PIC PLT, you need to load
_GLOBAL_OFFSET_TABLE_ into EBX first.  There is no need for that on
x86-64 since x86-64 uses PC-relative PLT.

On x86-64, for 32-bit PC-relative branches, we can generate PLT32
relocation, instead of PC32 relocation, which can also be used as
a marker for 32-bit PC-relative branches.  Linker can always reduce
PLT32 relocation to PC32 if function is defined locally.   Local
functions should use PC32 relocation.  As far as Linux kernel is
concerned, R_X86_64_PLT32 can be treated the same as R_X86_64_PC32
since Linux kernel doesn't use PLT.

is needed.  It is available on hjl/plt32/master branch at

https://github.com/hjl-tools/linux

bfd/

	PR gas/22791
	* elf64-x86-64.c (is_32bit_relative_branch): Removed.
	(elf_x86_64_relocate_section): Check PIC relocations in PIE.
	Remove is_32bit_relative_branch usage.  Disallow PC32 reloc
	against protected function in shared object.

gas/

	PR gas/22791
	* config/tc-i386.c (need_plt32_p): New function.
	(output_jump): Generate BFD_RELOC_X86_64_PLT32 if possible.
	(md_estimate_size_before_relax): Likewise.
	* testsuite/gas/i386/reloc64.d: Updated.
	* testsuite/gas/i386/x86-64-jump.d: Likewise.
	* testsuite/gas/i386/x86-64-mpx-branch-1.d: Likewise.
	* testsuite/gas/i386/x86-64-mpx-branch-2.d: Likewise.
	* testsuite/gas/i386/x86-64-relax-2.d: Likewise.
	* testsuite/gas/i386/x86-64-relax-3.d: Likewise.
	* testsuite/gas/i386/ilp32/reloc64.d: Likewise.
	* testsuite/gas/i386/ilp32/x86-64-branch.d: Likewise.

ld/

	PR gas/22791
	* testsuite/ld-x86-64/mpx1c.rd: Updated.
	* testsuite/ld-x86-64/pr22791-1.err: New file.
	* testsuite/ld-x86-64/pr22791-1a.c: Likewise.
	* testsuite/ld-x86-64/pr22791-1b.s: Likewise.
	* testsuite/ld-x86-64/pr22791-2.rd: Likewise.
	* testsuite/ld-x86-64/pr22791-2a.s: Likewise.
	* testsuite/ld-x86-64/pr22791-2b.c: Likewise.
	* testsuite/ld-x86-64/pr22791-2c.s: Likewise.
	* testsuite/ld-x86-64/x86-64.exp: Run PR ld/22791 tests.
---
 bfd/elf64-x86-64.c                           | 45 ++++++++-----------------
 gas/config/tc-i386.c                         | 49 +++++++++++++++++++++++++++-
 gas/testsuite/gas/i386/ilp32/reloc64.d       |  2 +-
 gas/testsuite/gas/i386/ilp32/x86-64-branch.d |  6 ++--
 gas/testsuite/gas/i386/reloc64.d             |  2 +-
 gas/testsuite/gas/i386/x86-64-jump.d         |  4 +--
 gas/testsuite/gas/i386/x86-64-mpx-branch-1.d |  6 ++--
 gas/testsuite/gas/i386/x86-64-mpx-branch-2.d |  6 ++--
 gas/testsuite/gas/i386/x86-64-relax-2.d      | 10 +++---
 gas/testsuite/gas/i386/x86-64-relax-3.d      |  8 ++---
 ld/testsuite/ld-x86-64/mpx1c.rd              |  2 +-
 ld/testsuite/ld-x86-64/pr22791-1.err         |  2 ++
 ld/testsuite/ld-x86-64/pr22791-1a.c          |  4 +++
 ld/testsuite/ld-x86-64/pr22791-1b.s          |  6 ++++
 ld/testsuite/ld-x86-64/pr22791-2.rd          |  6 ++++
 ld/testsuite/ld-x86-64/pr22791-2a.s          |  8 +++++
 ld/testsuite/ld-x86-64/pr22791-2b.c          |  7 ++++
 ld/testsuite/ld-x86-64/pr22791-2c.s          | 12 +++++++
 ld/testsuite/ld-x86-64/x86-64.exp            | 47 ++++++++++++++++++++++++++
 19 files changed, 176 insertions(+), 56 deletions(-)
 create mode 100644 ld/testsuite/ld-x86-64/pr22791-1.err
 create mode 100644 ld/testsuite/ld-x86-64/pr22791-1a.c
 create mode 100644 ld/testsuite/ld-x86-64/pr22791-1b.s
 create mode 100644 ld/testsuite/ld-x86-64/pr22791-2.rd
 create mode 100644 ld/testsuite/ld-x86-64/pr22791-2a.s
 create mode 100644 ld/testsuite/ld-x86-64/pr22791-2b.c
 create mode 100644 ld/testsuite/ld-x86-64/pr22791-2c.s

diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index aad9b85296..aa6a47121b 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -2307,24 +2307,6 @@ elf_x86_64_tpoff (struct bfd_link_info *info, bfd_vma address)
   return address - static_tls_size - htab->tls_sec->vma;
 }
 
-/* Is the instruction before OFFSET in CONTENTS a 32bit relative
-   branch?  */
-
-static bfd_boolean
-is_32bit_relative_branch (bfd_byte *contents, bfd_vma offset)
-{
-  /* Opcode		Instruction
-     0xe8		call
-     0xe9		jump
-     0x0f 0x8x		conditional jump */
-  return ((offset > 0
-	   && (contents [offset - 1] == 0xe8
-	       || contents [offset - 1] == 0xe9))
-	  || (offset > 1
-	      && contents [offset - 2] == 0x0f
-	      && (contents [offset - 1] & 0xf0) == 0x80));
-}
-
 /* Relocate an x86_64 ELF section.  */
 
 static bfd_boolean
@@ -3023,14 +3005,18 @@ do_ifunc_pointer:
 	case R_X86_64_PC32:
 	case R_X86_64_PC32_BND:
 	  /* Don't complain about -fPIC if the symbol is undefined when
-	     building executable unless it is unresolved weak symbol or
-	     -z nocopyreloc is used.  */
+	     building executable unless it is unresolved weak symbol,
+	     references a dynamic definition in PIE or -z nocopyreloc
+	     is used.  */
 	  if ((input_section->flags & SEC_ALLOC) != 0
 	      && (input_section->flags & SEC_READONLY) != 0
 	      && h != NULL
 	      && ((bfd_link_executable (info)
 		   && ((h->root.type == bfd_link_hash_undefweak
 			&& !resolved_to_zero)
+		       || (bfd_link_pie (info)
+			   && !h->def_regular
+			   && h->def_dynamic)
 		       || ((info->nocopyreloc
 			    || (eh->def_protected
 				&& elf_has_no_copy_on_protected (h->root.u.def.section->owner)))
@@ -3039,26 +3025,21 @@ do_ifunc_pointer:
 		  || bfd_link_dll (info)))
 	    {
 	      bfd_boolean fail = FALSE;
-	      bfd_boolean branch
-		= ((r_type == R_X86_64_PC32
-		    || r_type == R_X86_64_PC32_BND)
-		   && is_32bit_relative_branch (contents, rel->r_offset));
-
 	      if (SYMBOL_REFERENCES_LOCAL_P (info, h))
 		{
 		  /* Symbol is referenced locally.  Make sure it is
-		     defined locally or for a branch.  */
-		  fail = (!(h->def_regular || ELF_COMMON_DEF_P (h))
-			  && !branch);
+		     defined locally.  */
+		  fail = !(h->def_regular || ELF_COMMON_DEF_P (h));
 		}
 	      else if (!(bfd_link_pie (info)
 			 && (h->needs_copy || eh->needs_copy)))
 		{
 		  /* Symbol doesn't need copy reloc and isn't referenced
-		     locally.  We only allow branch to symbol with
-		     non-default visibility. */
-		  fail = (!branch
-			  || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT);
+		     locally.  Address of protected function may not be
+		     reachable at run-time.  */
+		  fail = (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+			  || (ELF_ST_VISIBILITY (h->other) == STV_PROTECTED
+			      && h->type == STT_FUNC));
 		}
 
 	      if (fail)
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index 32a8b31d30..d9ff4103a0 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -7023,12 +7023,46 @@ output_branch (void)
   frag_var (rs_machine_dependent, 5, i.reloc[0], subtype, sym, off, p);
 }
 
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+/* Return TRUE iff PLT32 relocation should be used for branching to
+   symbol S.  */
+
+static bfd_boolean
+need_plt32_p (symbolS *s)
+{
+  /* PLT32 relocation is ELF only.  */
+  if (!IS_ELF)
+    return FALSE;
+
+  /* Since there is no need to prepare for PLT branch on x86-64, we
+     can generate R_X86_64_PLT32, instead of R_X86_64_PC32, which can
+     be used as a marker for 32-bit PC-relative branches.  */
+  if (!object_64bit)
+    return FALSE;
+
+  /* Weak or undefined symbol need PLT32 relocation.  */
+  if (S_IS_WEAK (s) || !S_IS_DEFINED (s))
+    return TRUE;
+
+  /* Non-global symbol doesn't need PLT32 relocation.  */
+  if (! S_IS_EXTERNAL (s))
+    return FALSE;
+
+  /* Other global symbols need PLT32 relocation.  NB: Symbol with
+     non-default visibilities are treated as normal global symbol
+     so that PLT32 relocation can be used as a marker for 32-bit
+     PC-relative branches.  It is useful for linker relaxation.  */
+  return TRUE;
+}
+#endif
+
 static void
 output_jump (void)
 {
   char *p;
   int size;
   fixS *fixP;
+  bfd_reloc_code_real_type jump_reloc = i.reloc[0];
 
   if (i.tm.opcode_modifier.jumpbyte)
     {
@@ -7096,8 +7130,17 @@ output_jump (void)
       abort ();
     }
 
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+  if (size == 4
+      && jump_reloc == NO_RELOC
+      && need_plt32_p (i.op[0].disps->X_add_symbol))
+    jump_reloc = BFD_RELOC_X86_64_PLT32;
+#endif
+
+  jump_reloc = reloc (size, 1, 1, jump_reloc);
+
   fixP = fix_new_exp (frag_now, p - frag_now->fr_literal, size,
-		      i.op[0].disps, 1, reloc (size, 1, 1, i.reloc[0]));
+		      i.op[0].disps, 1, jump_reloc);
 
   /* All jumps handled here are signed, but don't use a signed limit
      check for 32 and 16 bit jumps as we want to allow wrap around at
@@ -9315,6 +9358,10 @@ md_estimate_size_before_relax (fragS *fragP, segT segment)
 	reloc_type = (enum bfd_reloc_code_real) fragP->fr_var;
       else if (size == 2)
 	reloc_type = BFD_RELOC_16_PCREL;
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+      else if (need_plt32_p (fragP->fr_symbol))
+	reloc_type = BFD_RELOC_X86_64_PLT32;
+#endif
       else
 	reloc_type = BFD_RELOC_32_PCREL;
 
diff --git a/gas/testsuite/gas/i386/ilp32/reloc64.d b/gas/testsuite/gas/i386/ilp32/reloc64.d
index 53083f31d2..f6bc628448 100644
--- a/gas/testsuite/gas/i386/ilp32/reloc64.d
+++ b/gas/testsuite/gas/i386/ilp32/reloc64.d
@@ -16,7 +16,7 @@ Disassembly of section \.text:
 .*[ 	]+R_X86_64_PC8[ 	]+xtrn\+0x0*1
 .*[ 	]+R_X86_64_PC32[ 	]+xtrn-0x0*4
 .*[ 	]+R_X86_64_PC32[ 	]+xtrn-0x0*4
-.*[ 	]+R_X86_64_PC32[ 	]+xtrn-0x0*4
+.*[ 	]+R_X86_64_PLT32[ 	]+xtrn-0x0*4
 .*[ 	]+R_X86_64_PC8[ 	]+xtrn-0x0*1
 .*[ 	]+R_X86_64_GOT32[ 	]+xtrn
 .*[ 	]+R_X86_64_GOT32[ 	]+xtrn
diff --git a/gas/testsuite/gas/i386/ilp32/x86-64-branch.d b/gas/testsuite/gas/i386/ilp32/x86-64-branch.d
index 915dbf3f1c..45ab6178b9 100644
--- a/gas/testsuite/gas/i386/ilp32/x86-64-branch.d
+++ b/gas/testsuite/gas/i386/ilp32/x86-64-branch.d
@@ -20,9 +20,9 @@ Disassembly of section .text:
 [ 	]*[a-f0-9]+:	66 ff 20             	data16 jmpq \*\(%rax\)
 [ 	]*[a-f0-9]+:	e8 00 00 00 00       	callq  0x1f	1b: R_X86_64_PC32	\*ABS\*\+0x10003c
 [ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   0x24	20: R_X86_64_PC32	\*ABS\*\+0x10003c
-[ 	]*[a-f0-9]+:	66 e8 00 00 00 00    	data16 callq 0x2a	26: R_X86_64_PC32	foo-0x4
-[ 	]*[a-f0-9]+:	66 e9 00 00 00 00    	data16 jmpq 0x30	2c: R_X86_64_PC32	foo-0x4
-[ 	]*[a-f0-9]+:	66 0f 82 00 00 00 00 	data16 jb 0x37	33: R_X86_64_PC32	foo-0x4
+[ 	]*[a-f0-9]+:	66 e8 00 00 00 00    	data16 callq 0x2a	26: R_X86_64_PLT32	foo-0x4
+[ 	]*[a-f0-9]+:	66 e9 00 00 00 00    	data16 jmpq 0x30	2c: R_X86_64_PLT32	foo-0x4
+[ 	]*[a-f0-9]+:	66 0f 82 00 00 00 00 	data16 jb 0x37	33: R_X86_64_PLT32	foo-0x4
 [ 	]*[a-f0-9]+:	ff d0                	callq  \*%rax
 [ 	]*[a-f0-9]+:	ff d0                	callq  \*%rax
 [ 	]*[a-f0-9]+:	66 ff d0             	data16 callq \*%rax
diff --git a/gas/testsuite/gas/i386/reloc64.d b/gas/testsuite/gas/i386/reloc64.d
index a7fd3d6a3d..4cf884dc7b 100644
--- a/gas/testsuite/gas/i386/reloc64.d
+++ b/gas/testsuite/gas/i386/reloc64.d
@@ -18,7 +18,7 @@ Disassembly of section \.text:
 .*[ 	]+R_X86_64_PC8[ 	]+xtrn\+0x0*1
 .*[ 	]+R_X86_64_PC32[ 	]+xtrn-0x0*4
 .*[ 	]+R_X86_64_PC32[ 	]+xtrn-0x0*4
-.*[ 	]+R_X86_64_PC32[ 	]+xtrn-0x0*4
+.*[ 	]+R_X86_64_PLT32[ 	]+xtrn-0x0*4
 .*[ 	]+R_X86_64_PC8[ 	]+xtrn-0x0*1
 .*[ 	]+R_X86_64_GOT64[ 	]+xtrn
 .*[ 	]+R_X86_64_GOT32[ 	]+xtrn
diff --git a/gas/testsuite/gas/i386/x86-64-jump.d b/gas/testsuite/gas/i386/x86-64-jump.d
index edb34e6aa8..9f7b4b4848 100644
--- a/gas/testsuite/gas/i386/x86-64-jump.d
+++ b/gas/testsuite/gas/i386/x86-64-jump.d
@@ -8,7 +8,7 @@ Disassembly of section .text:
 
 0+ <.text>:
 [ 	]*[a-f0-9]+:	eb fe                	jmp    (0x0|0 <.text>)
-[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   0x7	3: R_X86_64_PC32	xxx-0x4
+[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   0x7	3: R_X86_64_PLT32	xxx-0x4
 [ 	]*[a-f0-9]+:	ff 24 25 00 00 00 00 	jmpq   \*0x0	a: R_X86_64_32S	xxx
 [ 	]*[a-f0-9]+:	ff e7                	jmpq   \*%rdi
 [ 	]*[a-f0-9]+:	ff 27                	jmpq   \*\(%rdi\)
@@ -17,7 +17,7 @@ Disassembly of section .text:
 [ 	]*[a-f0-9]+:	ff 2c 25 00 00 00 00 	ljmp   \*0x0	24: R_X86_64_32S	xxx
 [ 	]*[a-f0-9]+:	66 ff 2c 25 00 00 00 00 	ljmpw  \*0x0	2c: R_X86_64_32S	xxx
 [ 	]*[a-f0-9]+:	e8 cb ff ff ff       	callq  0x0
-[ 	]*[a-f0-9]+:	e8 00 00 00 00       	callq  0x3a	36: R_X86_64_PC32	xxx-0x4
+[ 	]*[a-f0-9]+:	e8 00 00 00 00       	callq  0x3a	36: R_X86_64_PLT32	xxx-0x4
 [ 	]*[a-f0-9]+:	ff 14 25 00 00 00 00 	callq  \*0x0	3d: R_X86_64_32S	xxx
 [ 	]*[a-f0-9]+:	ff d7                	callq  \*%rdi
 [ 	]*[a-f0-9]+:	ff 17                	callq  \*\(%rdi\)
diff --git a/gas/testsuite/gas/i386/x86-64-mpx-branch-1.d b/gas/testsuite/gas/i386/x86-64-mpx-branch-1.d
index c07002911c..d44841e745 100644
--- a/gas/testsuite/gas/i386/x86-64-mpx-branch-1.d
+++ b/gas/testsuite/gas/i386/x86-64-mpx-branch-1.d
@@ -20,9 +20,9 @@ Disassembly of section .text:
 [ 	]*[a-f0-9]+:	f2 e8 00 00 00 00    	bnd callq 24 <foo2>
 
 0+24 <foo2>:
-[ 	]*[a-f0-9]+:	f2 e9 00 00 00 00    	bnd jmpq 2a <foo2\+0x6>	26: R_X86_64_PC32	foo-0x4
-[ 	]*[a-f0-9]+:	f2 0f 82 00 00 00 00 	bnd jb 31 <foo2\+0xd>	2d: R_X86_64_PC32	foo-0x4
-[ 	]*[a-f0-9]+:	f2 e8 00 00 00 00    	bnd callq 37 <foo2\+0x13>	33: R_X86_64_PC32	foo-0x4
+[ 	]*[a-f0-9]+:	f2 e9 00 00 00 00    	bnd jmpq 2a <foo2\+0x6>	26: R_X86_64_PLT32	foo-0x4
+[ 	]*[a-f0-9]+:	f2 0f 82 00 00 00 00 	bnd jb 31 <foo2\+0xd>	2d: R_X86_64_PLT32	foo-0x4
+[ 	]*[a-f0-9]+:	f2 e8 00 00 00 00    	bnd callq 37 <foo2\+0x13>	33: R_X86_64_PLT32	foo-0x4
 [ 	]*[a-f0-9]+:	f2 e9 00 00 00 00    	bnd jmpq 3d <foo2\+0x19>	39: R_X86_64_PLT32	foo-0x4
 [ 	]*[a-f0-9]+:	f2 0f 82 00 00 00 00 	bnd jb 44 <foo2\+0x20>	40: R_X86_64_PLT32	foo-0x4
 [ 	]*[a-f0-9]+:	f2 e8 00 00 00 00    	bnd callq 4a <foo2\+0x26>	46: R_X86_64_PLT32	foo-0x4
diff --git a/gas/testsuite/gas/i386/x86-64-mpx-branch-2.d b/gas/testsuite/gas/i386/x86-64-mpx-branch-2.d
index 5bb6a57c1e..514c34363e 100644
--- a/gas/testsuite/gas/i386/x86-64-mpx-branch-2.d
+++ b/gas/testsuite/gas/i386/x86-64-mpx-branch-2.d
@@ -20,9 +20,9 @@ Disassembly of section .text:
 [ 	]*[a-f0-9]+:	f2 e8 00 00 00 00    	bnd callq 24 <foo2>
 
 0+24 <foo2>:
-[ 	]*[a-f0-9]+:	f2 e9 00 00 00 00    	bnd jmpq 2a <foo2\+0x6>	26: R_X86_64_PC32	foo-0x4
-[ 	]*[a-f0-9]+:	f2 0f 82 00 00 00 00 	bnd jb 31 <foo2\+0xd>	2d: R_X86_64_PC32	foo-0x4
-[ 	]*[a-f0-9]+:	f2 e8 00 00 00 00    	bnd callq 37 <foo2\+0x13>	33: R_X86_64_PC32	foo-0x4
+[ 	]*[a-f0-9]+:	f2 e9 00 00 00 00    	bnd jmpq 2a <foo2\+0x6>	26: R_X86_64_PLT32	foo-0x4
+[ 	]*[a-f0-9]+:	f2 0f 82 00 00 00 00 	bnd jb 31 <foo2\+0xd>	2d: R_X86_64_PLT32	foo-0x4
+[ 	]*[a-f0-9]+:	f2 e8 00 00 00 00    	bnd callq 37 <foo2\+0x13>	33: R_X86_64_PLT32	foo-0x4
 [ 	]*[a-f0-9]+:	f2 e9 00 00 00 00    	bnd jmpq 3d <foo2\+0x19>	39: R_X86_64_PLT32	foo-0x4
 [ 	]*[a-f0-9]+:	f2 0f 82 00 00 00 00 	bnd jb 44 <foo2\+0x20>	40: R_X86_64_PLT32	foo-0x4
 [ 	]*[a-f0-9]+:	f2 e8 00 00 00 00    	bnd callq 4a <foo2\+0x26>	46: R_X86_64_PLT32	foo-0x4
diff --git a/gas/testsuite/gas/i386/x86-64-relax-2.d b/gas/testsuite/gas/i386/x86-64-relax-2.d
index c124102982..c9eba8452a 100644
--- a/gas/testsuite/gas/i386/x86-64-relax-2.d
+++ b/gas/testsuite/gas/i386/x86-64-relax-2.d
@@ -10,12 +10,12 @@ Disassembly of section .text:
 0+ <foo>:
 [ 	]*[a-f0-9]+:	eb 24                	jmp    26 <local>
 [ 	]*[a-f0-9]+:	eb 1e                	jmp    22 <hidden_def>
-[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   9 <foo\+0x9>	5: R_X86_64_PC32	global_def-0x4
+[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   9 <foo\+0x9>	5: R_X86_64_PLT32	global_def-0x4
 [ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   e <foo\+0xe>	a: R_X86_64_PLT32	global_def-0x4
-[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   13 <foo\+0x13>	f: R_X86_64_PC32	weak_def-0x4
-[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   18 <foo\+0x18>	14: R_X86_64_PC32	weak_hidden_undef-0x4
-[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   1d <foo\+0x1d>	19: R_X86_64_PC32	weak_hidden_def-0x4
-[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   22 <hidden_def>	1e: R_X86_64_PC32	hidden_undef-0x4
+[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   13 <foo\+0x13>	f: R_X86_64_PLT32	weak_def-0x4
+[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   18 <foo\+0x18>	14: R_X86_64_PLT32	weak_hidden_undef-0x4
+[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   1d <foo\+0x1d>	19: R_X86_64_PLT32	weak_hidden_def-0x4
+[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   22 <hidden_def>	1e: R_X86_64_PLT32	hidden_undef-0x4
 
 0+22 <hidden_def>:
 [ 	]*[a-f0-9]+:	c3                   	retq   
diff --git a/gas/testsuite/gas/i386/x86-64-relax-3.d b/gas/testsuite/gas/i386/x86-64-relax-3.d
index 98fd28dd11..28ab5dd3f7 100644
--- a/gas/testsuite/gas/i386/x86-64-relax-3.d
+++ b/gas/testsuite/gas/i386/x86-64-relax-3.d
@@ -11,10 +11,10 @@ Disassembly of section .text:
 [ 	]*[a-f0-9]+:	eb 1b                	jmp    1f <hidden_def>
 [ 	]*[a-f0-9]+:	eb 1b                	jmp    21 <global_def>
 [ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   b <foo\+0xb>	7: R_X86_64_PLT32	global_def-0x4
-[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   10 <foo\+0x10>	c: R_X86_64_PC32	weak_def-0x4
-[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   15 <foo\+0x15>	11: R_X86_64_PC32	weak_hidden_undef-0x4
-[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   1a <foo\+0x1a>	16: R_X86_64_PC32	weak_hidden_def-0x4
-[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   1f <hidden_def>	1b: R_X86_64_PC32	hidden_undef-0x4
+[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   10 <foo\+0x10>	c: R_X86_64_PLT32	weak_def-0x4
+[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   15 <foo\+0x15>	11: R_X86_64_PLT32	weak_hidden_undef-0x4
+[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   1a <foo\+0x1a>	16: R_X86_64_PLT32	weak_hidden_def-0x4
+[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   1f <hidden_def>	1b: R_X86_64_PLT32	hidden_undef-0x4
 
 0+1f <hidden_def>:
 [ 	]*[a-f0-9]+:	c3                   	retq   
diff --git a/ld/testsuite/ld-x86-64/mpx1c.rd b/ld/testsuite/ld-x86-64/mpx1c.rd
index d3b292cbdc..d66524c883 100644
--- a/ld/testsuite/ld-x86-64/mpx1c.rd
+++ b/ld/testsuite/ld-x86-64/mpx1c.rd
@@ -1,3 +1,3 @@
 #...
-[0-9a-f ]+R_X86_64_PC32 +0+ +.*
+[0-9a-f ]+R_X86_64_PLT32 +0+ +.*
 #...
diff --git a/ld/testsuite/ld-x86-64/pr22791-1.err b/ld/testsuite/ld-x86-64/pr22791-1.err
new file mode 100644
index 0000000000..5500fa55ce
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22791-1.err
@@ -0,0 +1,2 @@
+.*relocation R_X86_64_PC32 against symbol `foo' can not be used when making a PIE object; recompile with -fPIC
+#...
diff --git a/ld/testsuite/ld-x86-64/pr22791-1a.c b/ld/testsuite/ld-x86-64/pr22791-1a.c
new file mode 100644
index 0000000000..cd0130cacd
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22791-1a.c
@@ -0,0 +1,4 @@
+void
+foo (void)
+{
+}
diff --git a/ld/testsuite/ld-x86-64/pr22791-1b.s b/ld/testsuite/ld-x86-64/pr22791-1b.s
new file mode 100644
index 0000000000..9751db49aa
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22791-1b.s
@@ -0,0 +1,6 @@
+	.text
+	.globl	main
+	.type	main, @function
+main:
+	movl	foo(%rip), %eax
+	.size	main, .-main
diff --git a/ld/testsuite/ld-x86-64/pr22791-2.rd b/ld/testsuite/ld-x86-64/pr22791-2.rd
new file mode 100644
index 0000000000..70deb30d84
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22791-2.rd
@@ -0,0 +1,6 @@
+#failif
+#...
+.*\(TEXTREL\).*
+#...
+[0-9a-f ]+R_X86_64_NONE.*
+#...
diff --git a/ld/testsuite/ld-x86-64/pr22791-2a.s b/ld/testsuite/ld-x86-64/pr22791-2a.s
new file mode 100644
index 0000000000..0a855024d7
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22791-2a.s
@@ -0,0 +1,8 @@
+	.text
+	.p2align 4,,15
+	.globl	foo
+	.type	foo, @function
+foo:
+	jmp	bar
+	.size	foo, .-foo
+	.section	.note.GNU-stack,"",@progbits
diff --git a/ld/testsuite/ld-x86-64/pr22791-2b.c b/ld/testsuite/ld-x86-64/pr22791-2b.c
new file mode 100644
index 0000000000..79ef27c085
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22791-2b.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+void
+bar (void)
+{
+  puts ("PASS");
+}
diff --git a/ld/testsuite/ld-x86-64/pr22791-2c.s b/ld/testsuite/ld-x86-64/pr22791-2c.s
new file mode 100644
index 0000000000..1460d1b828
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22791-2c.s
@@ -0,0 +1,12 @@
+	.text
+	.p2align 4,,15
+	.globl	main
+	.type	main, @function
+main:
+	subq	$8, %rsp
+	call	foo
+	xorl	%eax, %eax
+	addq	$8, %rsp
+	ret
+	.size	main, .-main
+	.section	.note.GNU-stack,"",@progbits
diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp
index af3afcc2c7..a649de87cd 100644
--- a/ld/testsuite/ld-x86-64/x86-64.exp
+++ b/ld/testsuite/ld-x86-64/x86-64.exp
@@ -1152,6 +1152,44 @@ if { [isnative] && [which $CC] != 0 } {
 	     {readelf -lW pr22393-3b.rd}} \
 	    "pr22393-3-static" \
 	] \
+	[list \
+	    "Build pr22791-1.so" \
+	    "-shared" \
+	    "-fPIC" \
+	    { pr22791-1a.c } \
+	    {} \
+	    "pr22791-1.so" \
+	] \
+	[list \
+	    "Build pr22791-1" \
+	    "-pie -Wl,--no-as-needed tmpdir/pr22791-1.so" \
+	    "$NOPIE_CFLAGS" \
+	    { pr22791-1b.s } \
+	    {{error_output "pr22791-1.err"}} \
+	    "pr22791-1" \
+	] \
+	[list \
+	    "Build pr22791-2a.o" \
+	    "" \
+	    "$NOPIE_CFLAGS" \
+	    { pr22791-2a.s } \
+	] \
+	[list \
+	    "Build pr22791-2.so" \
+	    "-shared tmpdir/pr22791-2a.o" \
+	    "-fPIC" \
+	    { pr22791-2b.c } \
+	    {{readelf -drW pr22791-2.rd}} \
+	    "pr22791-2.so" \
+	] \
+	[list \
+	    "Build pr22791-2" \
+	    "-pie -Wl,--no-as-needed tmpdir/pr22791-2.so" \
+	    "$NOPIE_CFLAGS" \
+	    { pr22791-2c.s } \
+	    {{readelf -drW pr22791-2.rd}} \
+	    "pr22791-2" \
+	] \
     ]
 
     if  {[istarget "x86_64-*-linux*-gnux32"]} {
@@ -1477,6 +1515,15 @@ if { [isnative] && [which $CC] != 0 } {
 	    "pr22393-3-static" \
 	    "pass.out" \
 	] \
+	[list \
+	    "Run pr22791-2" \
+	    "-pie -Wl,--no-as-needed tmpdir/pr22791-2.so" \
+	    "" \
+	    { pr22791-2c.s } \
+	    "pr22791-2" \
+	    "pass.out" \
+	    "$NOPIE_CFLAGS" \
+	] \
     ]
 
     # Run-time tests which require working ifunc attribute support.
Florian Weimer Feb. 9, 2018, 2:57 p.m. | #5
On 02/08/2018 04:56 PM, H.J. Lu wrote:
> Since there is no need to prepare for PLT branch on x86-64, generate

> R_X86_64_PLT32, instead of R_X86_64_PC32, if possible, which can be

> used as a marker for 32-bit PC-relative branches.

> 

> To compiler Linux, this patch:

> 

> From: "H.J. Lu"<hjl.tools@gmail.com>

> Subject: [PATCH] x86: Treat R_X86_64_PLT32 as R_X86_64_PC32

> 

> On i386, there are 2 types of PLTs, PIC and non-PIC.  PIE and shared


The commit message text seems garbled.

Thanks,
Florian
H.J. Lu Feb. 9, 2018, 3:21 p.m. | #6
On Fri, Feb 9, 2018 at 6:57 AM, Florian Weimer <fweimer@redhat.com> wrote:
> On 02/08/2018 04:56 PM, H.J. Lu wrote:

>>

>> Since there is no need to prepare for PLT branch on x86-64, generate

>> R_X86_64_PLT32, instead of R_X86_64_PC32, if possible, which can be

>> used as a marker for 32-bit PC-relative branches.

>>

>> To compiler Linux, this patch:

>>

>> From: "H.J. Lu"<hjl.tools@gmail.com>

>> Subject: [PATCH] x86: Treat R_X86_64_PLT32 as R_X86_64_PC32

>>

>> On i386, there are 2 types of PLTs, PIC and non-PIC.  PIE and shared

>

>

> The commit message text seems garbled.

>


Looks normal to me:

https://sourceware.org/ml/binutils/2018-02/msg00085.html

-- 
H.J.
Florian Weimer Feb. 9, 2018, 4:38 p.m. | #7
On 02/09/2018 04:21 PM, H.J. Lu wrote:
> Looks normal to me:

> 

> https://sourceware.org/ml/binutils/2018-02/msg00085.html


Ah, lack of indentation and “To compiler Linux” confused me.

(I have not reviewed the patch.)

Thanks,
Florian
H.J. Lu Feb. 9, 2018, 4:41 p.m. | #8
On Fri, Feb 9, 2018 at 8:38 AM, Florian Weimer <fweimer@redhat.com> wrote:
> On 02/09/2018 04:21 PM, H.J. Lu wrote:

>>

>> Looks normal to me:

>>

>> https://sourceware.org/ml/binutils/2018-02/msg00085.html

>

>

> Ah, lack of indentation and “To compiler Linux” confused me.

>


Oops.  It should read:

    To compile Linux kernel, this patch:

    From: "H.J. Lu" <hjl.tools@gmail.com>

    Subject: [PATCH] x86: Treat R_X86_64_PLT32 as R_X86_64_PC32


-- 
H.J.
H.J. Lu Feb. 13, 2018, 3:20 p.m. | #9
On Fri, Feb 9, 2018 at 8:41 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Fri, Feb 9, 2018 at 8:38 AM, Florian Weimer <fweimer@redhat.com> wrote:

>> On 02/09/2018 04:21 PM, H.J. Lu wrote:

>>>

>>> Looks normal to me:

>>>

>>> https://sourceware.org/ml/binutils/2018-02/msg00085.html

>>

>>

>> Ah, lack of indentation and “To compiler Linux” confused me.

>>

>

> Oops.  It should read:

>

>     To compile Linux kernel, this patch:

>

>     From: "H.J. Lu" <hjl.tools@gmail.com>

>     Subject: [PATCH] x86: Treat R_X86_64_PLT32 as R_X86_64_PC32

>


This is what I am checking in.


-- 
H.J.
From 38db6da9959a8d6c2a4a736f10236ca016214e22 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Tue, 6 Feb 2018 05:23:04 -0800
Subject: [PATCH] x86-64: Generate branch with PLT32 relocation

Since there is no need to prepare for PLT branch on x86-64, generate
R_X86_64_PLT32, instead of R_X86_64_PC32, if possible, which can be
used as a marker for 32-bit PC-relative branches.

To compile Linux kernel, this patch:

From: "H.J. Lu" <hjl.tools@gmail.com>
Subject: [PATCH] x86: Treat R_X86_64_PLT32 as R_X86_64_PC32

On i386, there are 2 types of PLTs, PIC and non-PIC.  PIE and shared
objects must use PIC PLT.  To use PIC PLT, you need to load
_GLOBAL_OFFSET_TABLE_ into EBX first.  There is no need for that on
x86-64 since x86-64 uses PC-relative PLT.

On x86-64, for 32-bit PC-relative branches, we can generate PLT32
relocation, instead of PC32 relocation, which can also be used as
a marker for 32-bit PC-relative branches.  Linker can always reduce
PLT32 relocation to PC32 if function is defined locally.   Local
functions should use PC32 relocation.  As far as Linux kernel is
concerned, R_X86_64_PLT32 can be treated the same as R_X86_64_PC32
since Linux kernel doesn't use PLT.

is needed.  It is available on hjl/plt32/master branch at

https://github.com/hjl-tools/linux

bfd/

	PR gas/22791
	* elf64-x86-64.c (is_32bit_relative_branch): Removed.
	(elf_x86_64_relocate_section): Check PIC relocations in PIE.
	Remove is_32bit_relative_branch usage.  Disallow PC32 reloc
	against protected function in shared object.

gas/

	PR gas/22791
	* config/tc-i386.c (need_plt32_p): New function.
	(output_jump): Generate BFD_RELOC_X86_64_PLT32 if possible.
	(md_estimate_size_before_relax): Likewise.
	* testsuite/gas/i386/reloc64.d: Updated.
	* testsuite/gas/i386/x86-64-jump.d: Likewise.
	* testsuite/gas/i386/x86-64-mpx-branch-1.d: Likewise.
	* testsuite/gas/i386/x86-64-mpx-branch-2.d: Likewise.
	* testsuite/gas/i386/x86-64-relax-2.d: Likewise.
	* testsuite/gas/i386/x86-64-relax-3.d: Likewise.
	* testsuite/gas/i386/ilp32/reloc64.d: Likewise.
	* testsuite/gas/i386/ilp32/x86-64-branch.d: Likewise.

ld/

	PR gas/22791
	* testsuite/ld-x86-64/mpx1c.rd: Updated.
	* testsuite/ld-x86-64/pr22791-1.err: New file.
	* testsuite/ld-x86-64/pr22791-1a.c: Likewise.
	* testsuite/ld-x86-64/pr22791-1b.s: Likewise.
	* testsuite/ld-x86-64/pr22791-2.rd: Likewise.
	* testsuite/ld-x86-64/pr22791-2a.s: Likewise.
	* testsuite/ld-x86-64/pr22791-2b.c: Likewise.
	* testsuite/ld-x86-64/pr22791-2c.s: Likewise.
	* testsuite/ld-x86-64/x86-64.exp: Run PR ld/22791 tests.
---
 bfd/elf64-x86-64.c                           | 45 ++++++++-----------------
 gas/config/tc-i386.c                         | 49 +++++++++++++++++++++++++++-
 gas/testsuite/gas/i386/ilp32/reloc64.d       |  2 +-
 gas/testsuite/gas/i386/ilp32/x86-64-branch.d |  6 ++--
 gas/testsuite/gas/i386/reloc64.d             |  2 +-
 gas/testsuite/gas/i386/x86-64-jump.d         |  4 +--
 gas/testsuite/gas/i386/x86-64-mpx-branch-1.d |  6 ++--
 gas/testsuite/gas/i386/x86-64-mpx-branch-2.d |  6 ++--
 gas/testsuite/gas/i386/x86-64-relax-2.d      | 10 +++---
 gas/testsuite/gas/i386/x86-64-relax-3.d      |  8 ++---
 ld/testsuite/ld-x86-64/mpx1c.rd              |  2 +-
 ld/testsuite/ld-x86-64/pr22791-1.err         |  2 ++
 ld/testsuite/ld-x86-64/pr22791-1a.c          |  4 +++
 ld/testsuite/ld-x86-64/pr22791-1b.s          |  6 ++++
 ld/testsuite/ld-x86-64/pr22791-2.rd          |  6 ++++
 ld/testsuite/ld-x86-64/pr22791-2a.s          |  8 +++++
 ld/testsuite/ld-x86-64/pr22791-2b.c          |  7 ++++
 ld/testsuite/ld-x86-64/pr22791-2c.s          | 12 +++++++
 ld/testsuite/ld-x86-64/x86-64.exp            | 47 ++++++++++++++++++++++++++
 19 files changed, 176 insertions(+), 56 deletions(-)
 create mode 100644 ld/testsuite/ld-x86-64/pr22791-1.err
 create mode 100644 ld/testsuite/ld-x86-64/pr22791-1a.c
 create mode 100644 ld/testsuite/ld-x86-64/pr22791-1b.s
 create mode 100644 ld/testsuite/ld-x86-64/pr22791-2.rd
 create mode 100644 ld/testsuite/ld-x86-64/pr22791-2a.s
 create mode 100644 ld/testsuite/ld-x86-64/pr22791-2b.c
 create mode 100644 ld/testsuite/ld-x86-64/pr22791-2c.s

diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index ad66840eac..0e4bb2e4a5 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -2307,24 +2307,6 @@ elf_x86_64_tpoff (struct bfd_link_info *info, bfd_vma address)
   return address - static_tls_size - htab->tls_sec->vma;
 }
 
-/* Is the instruction before OFFSET in CONTENTS a 32bit relative
-   branch?  */
-
-static bfd_boolean
-is_32bit_relative_branch (bfd_byte *contents, bfd_vma offset)
-{
-  /* Opcode		Instruction
-     0xe8		call
-     0xe9		jump
-     0x0f 0x8x		conditional jump */
-  return ((offset > 0
-	   && (contents [offset - 1] == 0xe8
-	       || contents [offset - 1] == 0xe9))
-	  || (offset > 1
-	      && contents [offset - 2] == 0x0f
-	      && (contents [offset - 1] & 0xf0) == 0x80));
-}
-
 /* Relocate an x86_64 ELF section.  */
 
 static bfd_boolean
@@ -3023,14 +3005,18 @@ do_ifunc_pointer:
 	case R_X86_64_PC32:
 	case R_X86_64_PC32_BND:
 	  /* Don't complain about -fPIC if the symbol is undefined when
-	     building executable unless it is unresolved weak symbol or
-	     -z nocopyreloc is used.  */
+	     building executable unless it is unresolved weak symbol,
+	     references a dynamic definition in PIE or -z nocopyreloc
+	     is used.  */
 	  if ((input_section->flags & SEC_ALLOC) != 0
 	      && (input_section->flags & SEC_READONLY) != 0
 	      && h != NULL
 	      && ((bfd_link_executable (info)
 		   && ((h->root.type == bfd_link_hash_undefweak
 			&& !resolved_to_zero)
+		       || (bfd_link_pie (info)
+			   && !h->def_regular
+			   && h->def_dynamic)
 		       || ((info->nocopyreloc
 			    || (eh->def_protected
 				&& elf_has_no_copy_on_protected (h->root.u.def.section->owner)))
@@ -3039,26 +3025,21 @@ do_ifunc_pointer:
 		  || bfd_link_dll (info)))
 	    {
 	      bfd_boolean fail = FALSE;
-	      bfd_boolean branch
-		= ((r_type == R_X86_64_PC32
-		    || r_type == R_X86_64_PC32_BND)
-		   && is_32bit_relative_branch (contents, rel->r_offset));
-
 	      if (SYMBOL_REFERENCES_LOCAL_P (info, h))
 		{
 		  /* Symbol is referenced locally.  Make sure it is
-		     defined locally or for a branch.  */
-		  fail = (!(h->def_regular || ELF_COMMON_DEF_P (h))
-			  && !branch);
+		     defined locally.  */
+		  fail = !(h->def_regular || ELF_COMMON_DEF_P (h));
 		}
 	      else if (!(bfd_link_pie (info)
 			 && (h->needs_copy || eh->needs_copy)))
 		{
 		  /* Symbol doesn't need copy reloc and isn't referenced
-		     locally.  We only allow branch to symbol with
-		     non-default visibility. */
-		  fail = (!branch
-			  || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT);
+		     locally.  Address of protected function may not be
+		     reachable at run-time.  */
+		  fail = (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+			  || (ELF_ST_VISIBILITY (h->other) == STV_PROTECTED
+			      && h->type == STT_FUNC));
 		}
 
 	      if (fail)
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index 552c1b81a5..1a5be1bcda 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -7023,12 +7023,46 @@ output_branch (void)
   frag_var (rs_machine_dependent, 5, i.reloc[0], subtype, sym, off, p);
 }
 
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+/* Return TRUE iff PLT32 relocation should be used for branching to
+   symbol S.  */
+
+static bfd_boolean
+need_plt32_p (symbolS *s)
+{
+  /* PLT32 relocation is ELF only.  */
+  if (!IS_ELF)
+    return FALSE;
+
+  /* Since there is no need to prepare for PLT branch on x86-64, we
+     can generate R_X86_64_PLT32, instead of R_X86_64_PC32, which can
+     be used as a marker for 32-bit PC-relative branches.  */
+  if (!object_64bit)
+    return FALSE;
+
+  /* Weak or undefined symbol need PLT32 relocation.  */
+  if (S_IS_WEAK (s) || !S_IS_DEFINED (s))
+    return TRUE;
+
+  /* Non-global symbol doesn't need PLT32 relocation.  */
+  if (! S_IS_EXTERNAL (s))
+    return FALSE;
+
+  /* Other global symbols need PLT32 relocation.  NB: Symbol with
+     non-default visibilities are treated as normal global symbol
+     so that PLT32 relocation can be used as a marker for 32-bit
+     PC-relative branches.  It is useful for linker relaxation.  */
+  return TRUE;
+}
+#endif
+
 static void
 output_jump (void)
 {
   char *p;
   int size;
   fixS *fixP;
+  bfd_reloc_code_real_type jump_reloc = i.reloc[0];
 
   if (i.tm.opcode_modifier.jumpbyte)
     {
@@ -7096,8 +7130,17 @@ output_jump (void)
       abort ();
     }
 
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+  if (size == 4
+      && jump_reloc == NO_RELOC
+      && need_plt32_p (i.op[0].disps->X_add_symbol))
+    jump_reloc = BFD_RELOC_X86_64_PLT32;
+#endif
+
+  jump_reloc = reloc (size, 1, 1, jump_reloc);
+
   fixP = fix_new_exp (frag_now, p - frag_now->fr_literal, size,
-		      i.op[0].disps, 1, reloc (size, 1, 1, i.reloc[0]));
+		      i.op[0].disps, 1, jump_reloc);
 
   /* All jumps handled here are signed, but don't use a signed limit
      check for 32 and 16 bit jumps as we want to allow wrap around at
@@ -9315,6 +9358,10 @@ md_estimate_size_before_relax (fragS *fragP, segT segment)
 	reloc_type = (enum bfd_reloc_code_real) fragP->fr_var;
       else if (size == 2)
 	reloc_type = BFD_RELOC_16_PCREL;
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+      else if (need_plt32_p (fragP->fr_symbol))
+	reloc_type = BFD_RELOC_X86_64_PLT32;
+#endif
       else
 	reloc_type = BFD_RELOC_32_PCREL;
 
diff --git a/gas/testsuite/gas/i386/ilp32/reloc64.d b/gas/testsuite/gas/i386/ilp32/reloc64.d
index 53083f31d2..f6bc628448 100644
--- a/gas/testsuite/gas/i386/ilp32/reloc64.d
+++ b/gas/testsuite/gas/i386/ilp32/reloc64.d
@@ -16,7 +16,7 @@ Disassembly of section \.text:
 .*[ 	]+R_X86_64_PC8[ 	]+xtrn\+0x0*1
 .*[ 	]+R_X86_64_PC32[ 	]+xtrn-0x0*4
 .*[ 	]+R_X86_64_PC32[ 	]+xtrn-0x0*4
-.*[ 	]+R_X86_64_PC32[ 	]+xtrn-0x0*4
+.*[ 	]+R_X86_64_PLT32[ 	]+xtrn-0x0*4
 .*[ 	]+R_X86_64_PC8[ 	]+xtrn-0x0*1
 .*[ 	]+R_X86_64_GOT32[ 	]+xtrn
 .*[ 	]+R_X86_64_GOT32[ 	]+xtrn
diff --git a/gas/testsuite/gas/i386/ilp32/x86-64-branch.d b/gas/testsuite/gas/i386/ilp32/x86-64-branch.d
index 915dbf3f1c..45ab6178b9 100644
--- a/gas/testsuite/gas/i386/ilp32/x86-64-branch.d
+++ b/gas/testsuite/gas/i386/ilp32/x86-64-branch.d
@@ -20,9 +20,9 @@ Disassembly of section .text:
 [ 	]*[a-f0-9]+:	66 ff 20             	data16 jmpq \*\(%rax\)
 [ 	]*[a-f0-9]+:	e8 00 00 00 00       	callq  0x1f	1b: R_X86_64_PC32	\*ABS\*\+0x10003c
 [ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   0x24	20: R_X86_64_PC32	\*ABS\*\+0x10003c
-[ 	]*[a-f0-9]+:	66 e8 00 00 00 00    	data16 callq 0x2a	26: R_X86_64_PC32	foo-0x4
-[ 	]*[a-f0-9]+:	66 e9 00 00 00 00    	data16 jmpq 0x30	2c: R_X86_64_PC32	foo-0x4
-[ 	]*[a-f0-9]+:	66 0f 82 00 00 00 00 	data16 jb 0x37	33: R_X86_64_PC32	foo-0x4
+[ 	]*[a-f0-9]+:	66 e8 00 00 00 00    	data16 callq 0x2a	26: R_X86_64_PLT32	foo-0x4
+[ 	]*[a-f0-9]+:	66 e9 00 00 00 00    	data16 jmpq 0x30	2c: R_X86_64_PLT32	foo-0x4
+[ 	]*[a-f0-9]+:	66 0f 82 00 00 00 00 	data16 jb 0x37	33: R_X86_64_PLT32	foo-0x4
 [ 	]*[a-f0-9]+:	ff d0                	callq  \*%rax
 [ 	]*[a-f0-9]+:	ff d0                	callq  \*%rax
 [ 	]*[a-f0-9]+:	66 ff d0             	data16 callq \*%rax
diff --git a/gas/testsuite/gas/i386/reloc64.d b/gas/testsuite/gas/i386/reloc64.d
index a7fd3d6a3d..4cf884dc7b 100644
--- a/gas/testsuite/gas/i386/reloc64.d
+++ b/gas/testsuite/gas/i386/reloc64.d
@@ -18,7 +18,7 @@ Disassembly of section \.text:
 .*[ 	]+R_X86_64_PC8[ 	]+xtrn\+0x0*1
 .*[ 	]+R_X86_64_PC32[ 	]+xtrn-0x0*4
 .*[ 	]+R_X86_64_PC32[ 	]+xtrn-0x0*4
-.*[ 	]+R_X86_64_PC32[ 	]+xtrn-0x0*4
+.*[ 	]+R_X86_64_PLT32[ 	]+xtrn-0x0*4
 .*[ 	]+R_X86_64_PC8[ 	]+xtrn-0x0*1
 .*[ 	]+R_X86_64_GOT64[ 	]+xtrn
 .*[ 	]+R_X86_64_GOT32[ 	]+xtrn
diff --git a/gas/testsuite/gas/i386/x86-64-jump.d b/gas/testsuite/gas/i386/x86-64-jump.d
index edb34e6aa8..9f7b4b4848 100644
--- a/gas/testsuite/gas/i386/x86-64-jump.d
+++ b/gas/testsuite/gas/i386/x86-64-jump.d
@@ -8,7 +8,7 @@ Disassembly of section .text:
 
 0+ <.text>:
 [ 	]*[a-f0-9]+:	eb fe                	jmp    (0x0|0 <.text>)
-[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   0x7	3: R_X86_64_PC32	xxx-0x4
+[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   0x7	3: R_X86_64_PLT32	xxx-0x4
 [ 	]*[a-f0-9]+:	ff 24 25 00 00 00 00 	jmpq   \*0x0	a: R_X86_64_32S	xxx
 [ 	]*[a-f0-9]+:	ff e7                	jmpq   \*%rdi
 [ 	]*[a-f0-9]+:	ff 27                	jmpq   \*\(%rdi\)
@@ -17,7 +17,7 @@ Disassembly of section .text:
 [ 	]*[a-f0-9]+:	ff 2c 25 00 00 00 00 	ljmp   \*0x0	24: R_X86_64_32S	xxx
 [ 	]*[a-f0-9]+:	66 ff 2c 25 00 00 00 00 	ljmpw  \*0x0	2c: R_X86_64_32S	xxx
 [ 	]*[a-f0-9]+:	e8 cb ff ff ff       	callq  0x0
-[ 	]*[a-f0-9]+:	e8 00 00 00 00       	callq  0x3a	36: R_X86_64_PC32	xxx-0x4
+[ 	]*[a-f0-9]+:	e8 00 00 00 00       	callq  0x3a	36: R_X86_64_PLT32	xxx-0x4
 [ 	]*[a-f0-9]+:	ff 14 25 00 00 00 00 	callq  \*0x0	3d: R_X86_64_32S	xxx
 [ 	]*[a-f0-9]+:	ff d7                	callq  \*%rdi
 [ 	]*[a-f0-9]+:	ff 17                	callq  \*\(%rdi\)
diff --git a/gas/testsuite/gas/i386/x86-64-mpx-branch-1.d b/gas/testsuite/gas/i386/x86-64-mpx-branch-1.d
index c07002911c..d44841e745 100644
--- a/gas/testsuite/gas/i386/x86-64-mpx-branch-1.d
+++ b/gas/testsuite/gas/i386/x86-64-mpx-branch-1.d
@@ -20,9 +20,9 @@ Disassembly of section .text:
 [ 	]*[a-f0-9]+:	f2 e8 00 00 00 00    	bnd callq 24 <foo2>
 
 0+24 <foo2>:
-[ 	]*[a-f0-9]+:	f2 e9 00 00 00 00    	bnd jmpq 2a <foo2\+0x6>	26: R_X86_64_PC32	foo-0x4
-[ 	]*[a-f0-9]+:	f2 0f 82 00 00 00 00 	bnd jb 31 <foo2\+0xd>	2d: R_X86_64_PC32	foo-0x4
-[ 	]*[a-f0-9]+:	f2 e8 00 00 00 00    	bnd callq 37 <foo2\+0x13>	33: R_X86_64_PC32	foo-0x4
+[ 	]*[a-f0-9]+:	f2 e9 00 00 00 00    	bnd jmpq 2a <foo2\+0x6>	26: R_X86_64_PLT32	foo-0x4
+[ 	]*[a-f0-9]+:	f2 0f 82 00 00 00 00 	bnd jb 31 <foo2\+0xd>	2d: R_X86_64_PLT32	foo-0x4
+[ 	]*[a-f0-9]+:	f2 e8 00 00 00 00    	bnd callq 37 <foo2\+0x13>	33: R_X86_64_PLT32	foo-0x4
 [ 	]*[a-f0-9]+:	f2 e9 00 00 00 00    	bnd jmpq 3d <foo2\+0x19>	39: R_X86_64_PLT32	foo-0x4
 [ 	]*[a-f0-9]+:	f2 0f 82 00 00 00 00 	bnd jb 44 <foo2\+0x20>	40: R_X86_64_PLT32	foo-0x4
 [ 	]*[a-f0-9]+:	f2 e8 00 00 00 00    	bnd callq 4a <foo2\+0x26>	46: R_X86_64_PLT32	foo-0x4
diff --git a/gas/testsuite/gas/i386/x86-64-mpx-branch-2.d b/gas/testsuite/gas/i386/x86-64-mpx-branch-2.d
index 5bb6a57c1e..514c34363e 100644
--- a/gas/testsuite/gas/i386/x86-64-mpx-branch-2.d
+++ b/gas/testsuite/gas/i386/x86-64-mpx-branch-2.d
@@ -20,9 +20,9 @@ Disassembly of section .text:
 [ 	]*[a-f0-9]+:	f2 e8 00 00 00 00    	bnd callq 24 <foo2>
 
 0+24 <foo2>:
-[ 	]*[a-f0-9]+:	f2 e9 00 00 00 00    	bnd jmpq 2a <foo2\+0x6>	26: R_X86_64_PC32	foo-0x4
-[ 	]*[a-f0-9]+:	f2 0f 82 00 00 00 00 	bnd jb 31 <foo2\+0xd>	2d: R_X86_64_PC32	foo-0x4
-[ 	]*[a-f0-9]+:	f2 e8 00 00 00 00    	bnd callq 37 <foo2\+0x13>	33: R_X86_64_PC32	foo-0x4
+[ 	]*[a-f0-9]+:	f2 e9 00 00 00 00    	bnd jmpq 2a <foo2\+0x6>	26: R_X86_64_PLT32	foo-0x4
+[ 	]*[a-f0-9]+:	f2 0f 82 00 00 00 00 	bnd jb 31 <foo2\+0xd>	2d: R_X86_64_PLT32	foo-0x4
+[ 	]*[a-f0-9]+:	f2 e8 00 00 00 00    	bnd callq 37 <foo2\+0x13>	33: R_X86_64_PLT32	foo-0x4
 [ 	]*[a-f0-9]+:	f2 e9 00 00 00 00    	bnd jmpq 3d <foo2\+0x19>	39: R_X86_64_PLT32	foo-0x4
 [ 	]*[a-f0-9]+:	f2 0f 82 00 00 00 00 	bnd jb 44 <foo2\+0x20>	40: R_X86_64_PLT32	foo-0x4
 [ 	]*[a-f0-9]+:	f2 e8 00 00 00 00    	bnd callq 4a <foo2\+0x26>	46: R_X86_64_PLT32	foo-0x4
diff --git a/gas/testsuite/gas/i386/x86-64-relax-2.d b/gas/testsuite/gas/i386/x86-64-relax-2.d
index c124102982..c9eba8452a 100644
--- a/gas/testsuite/gas/i386/x86-64-relax-2.d
+++ b/gas/testsuite/gas/i386/x86-64-relax-2.d
@@ -10,12 +10,12 @@ Disassembly of section .text:
 0+ <foo>:
 [ 	]*[a-f0-9]+:	eb 24                	jmp    26 <local>
 [ 	]*[a-f0-9]+:	eb 1e                	jmp    22 <hidden_def>
-[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   9 <foo\+0x9>	5: R_X86_64_PC32	global_def-0x4
+[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   9 <foo\+0x9>	5: R_X86_64_PLT32	global_def-0x4
 [ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   e <foo\+0xe>	a: R_X86_64_PLT32	global_def-0x4
-[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   13 <foo\+0x13>	f: R_X86_64_PC32	weak_def-0x4
-[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   18 <foo\+0x18>	14: R_X86_64_PC32	weak_hidden_undef-0x4
-[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   1d <foo\+0x1d>	19: R_X86_64_PC32	weak_hidden_def-0x4
-[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   22 <hidden_def>	1e: R_X86_64_PC32	hidden_undef-0x4
+[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   13 <foo\+0x13>	f: R_X86_64_PLT32	weak_def-0x4
+[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   18 <foo\+0x18>	14: R_X86_64_PLT32	weak_hidden_undef-0x4
+[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   1d <foo\+0x1d>	19: R_X86_64_PLT32	weak_hidden_def-0x4
+[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   22 <hidden_def>	1e: R_X86_64_PLT32	hidden_undef-0x4
 
 0+22 <hidden_def>:
 [ 	]*[a-f0-9]+:	c3                   	retq   
diff --git a/gas/testsuite/gas/i386/x86-64-relax-3.d b/gas/testsuite/gas/i386/x86-64-relax-3.d
index 98fd28dd11..28ab5dd3f7 100644
--- a/gas/testsuite/gas/i386/x86-64-relax-3.d
+++ b/gas/testsuite/gas/i386/x86-64-relax-3.d
@@ -11,10 +11,10 @@ Disassembly of section .text:
 [ 	]*[a-f0-9]+:	eb 1b                	jmp    1f <hidden_def>
 [ 	]*[a-f0-9]+:	eb 1b                	jmp    21 <global_def>
 [ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   b <foo\+0xb>	7: R_X86_64_PLT32	global_def-0x4
-[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   10 <foo\+0x10>	c: R_X86_64_PC32	weak_def-0x4
-[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   15 <foo\+0x15>	11: R_X86_64_PC32	weak_hidden_undef-0x4
-[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   1a <foo\+0x1a>	16: R_X86_64_PC32	weak_hidden_def-0x4
-[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   1f <hidden_def>	1b: R_X86_64_PC32	hidden_undef-0x4
+[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   10 <foo\+0x10>	c: R_X86_64_PLT32	weak_def-0x4
+[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   15 <foo\+0x15>	11: R_X86_64_PLT32	weak_hidden_undef-0x4
+[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   1a <foo\+0x1a>	16: R_X86_64_PLT32	weak_hidden_def-0x4
+[ 	]*[a-f0-9]+:	e9 00 00 00 00       	jmpq   1f <hidden_def>	1b: R_X86_64_PLT32	hidden_undef-0x4
 
 0+1f <hidden_def>:
 [ 	]*[a-f0-9]+:	c3                   	retq   
diff --git a/ld/testsuite/ld-x86-64/mpx1c.rd b/ld/testsuite/ld-x86-64/mpx1c.rd
index d3b292cbdc..d66524c883 100644
--- a/ld/testsuite/ld-x86-64/mpx1c.rd
+++ b/ld/testsuite/ld-x86-64/mpx1c.rd
@@ -1,3 +1,3 @@
 #...
-[0-9a-f ]+R_X86_64_PC32 +0+ +.*
+[0-9a-f ]+R_X86_64_PLT32 +0+ +.*
 #...
diff --git a/ld/testsuite/ld-x86-64/pr22791-1.err b/ld/testsuite/ld-x86-64/pr22791-1.err
new file mode 100644
index 0000000000..5500fa55ce
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22791-1.err
@@ -0,0 +1,2 @@
+.*relocation R_X86_64_PC32 against symbol `foo' can not be used when making a PIE object; recompile with -fPIC
+#...
diff --git a/ld/testsuite/ld-x86-64/pr22791-1a.c b/ld/testsuite/ld-x86-64/pr22791-1a.c
new file mode 100644
index 0000000000..cd0130cacd
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22791-1a.c
@@ -0,0 +1,4 @@
+void
+foo (void)
+{
+}
diff --git a/ld/testsuite/ld-x86-64/pr22791-1b.s b/ld/testsuite/ld-x86-64/pr22791-1b.s
new file mode 100644
index 0000000000..9751db49aa
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22791-1b.s
@@ -0,0 +1,6 @@
+	.text
+	.globl	main
+	.type	main, @function
+main:
+	movl	foo(%rip), %eax
+	.size	main, .-main
diff --git a/ld/testsuite/ld-x86-64/pr22791-2.rd b/ld/testsuite/ld-x86-64/pr22791-2.rd
new file mode 100644
index 0000000000..70deb30d84
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22791-2.rd
@@ -0,0 +1,6 @@
+#failif
+#...
+.*\(TEXTREL\).*
+#...
+[0-9a-f ]+R_X86_64_NONE.*
+#...
diff --git a/ld/testsuite/ld-x86-64/pr22791-2a.s b/ld/testsuite/ld-x86-64/pr22791-2a.s
new file mode 100644
index 0000000000..0a855024d7
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22791-2a.s
@@ -0,0 +1,8 @@
+	.text
+	.p2align 4,,15
+	.globl	foo
+	.type	foo, @function
+foo:
+	jmp	bar
+	.size	foo, .-foo
+	.section	.note.GNU-stack,"",@progbits
diff --git a/ld/testsuite/ld-x86-64/pr22791-2b.c b/ld/testsuite/ld-x86-64/pr22791-2b.c
new file mode 100644
index 0000000000..79ef27c085
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22791-2b.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+void
+bar (void)
+{
+  puts ("PASS");
+}
diff --git a/ld/testsuite/ld-x86-64/pr22791-2c.s b/ld/testsuite/ld-x86-64/pr22791-2c.s
new file mode 100644
index 0000000000..1460d1b828
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22791-2c.s
@@ -0,0 +1,12 @@
+	.text
+	.p2align 4,,15
+	.globl	main
+	.type	main, @function
+main:
+	subq	$8, %rsp
+	call	foo
+	xorl	%eax, %eax
+	addq	$8, %rsp
+	ret
+	.size	main, .-main
+	.section	.note.GNU-stack,"",@progbits
diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp
index af3afcc2c7..a649de87cd 100644
--- a/ld/testsuite/ld-x86-64/x86-64.exp
+++ b/ld/testsuite/ld-x86-64/x86-64.exp
@@ -1152,6 +1152,44 @@ if { [isnative] && [which $CC] != 0 } {
 	     {readelf -lW pr22393-3b.rd}} \
 	    "pr22393-3-static" \
 	] \
+	[list \
+	    "Build pr22791-1.so" \
+	    "-shared" \
+	    "-fPIC" \
+	    { pr22791-1a.c } \
+	    {} \
+	    "pr22791-1.so" \
+	] \
+	[list \
+	    "Build pr22791-1" \
+	    "-pie -Wl,--no-as-needed tmpdir/pr22791-1.so" \
+	    "$NOPIE_CFLAGS" \
+	    { pr22791-1b.s } \
+	    {{error_output "pr22791-1.err"}} \
+	    "pr22791-1" \
+	] \
+	[list \
+	    "Build pr22791-2a.o" \
+	    "" \
+	    "$NOPIE_CFLAGS" \
+	    { pr22791-2a.s } \
+	] \
+	[list \
+	    "Build pr22791-2.so" \
+	    "-shared tmpdir/pr22791-2a.o" \
+	    "-fPIC" \
+	    { pr22791-2b.c } \
+	    {{readelf -drW pr22791-2.rd}} \
+	    "pr22791-2.so" \
+	] \
+	[list \
+	    "Build pr22791-2" \
+	    "-pie -Wl,--no-as-needed tmpdir/pr22791-2.so" \
+	    "$NOPIE_CFLAGS" \
+	    { pr22791-2c.s } \
+	    {{readelf -drW pr22791-2.rd}} \
+	    "pr22791-2" \
+	] \
     ]
 
     if  {[istarget "x86_64-*-linux*-gnux32"]} {
@@ -1477,6 +1515,15 @@ if { [isnative] && [which $CC] != 0 } {
 	    "pr22393-3-static" \
 	    "pass.out" \
 	] \
+	[list \
+	    "Run pr22791-2" \
+	    "-pie -Wl,--no-as-needed tmpdir/pr22791-2.so" \
+	    "" \
+	    { pr22791-2c.s } \
+	    "pr22791-2" \
+	    "pass.out" \
+	    "$NOPIE_CFLAGS" \
+	] \
     ]
 
     # Run-time tests which require working ifunc attribute support.

Patch

diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index aad9b85296..ddd6fead4c 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -1747,6 +1747,24 @@  rewrite_modrm_rex:
   return TRUE;
 }
 
+/* Is the instruction before OFFSET in CONTENTS a 32bit relative
+   branch?  */
+
+static bfd_boolean
+is_32bit_relative_branch (bfd_byte *contents, bfd_vma offset)
+{
+  /* Opcode		Instruction
+     0xe8		call
+     0xe9		jump
+     0x0f 0x8x		conditional jump */
+  return ((offset > 0
+	   && (contents [offset - 1] == 0xe8
+	       || contents [offset - 1] == 0xe9))
+	  || (offset > 1
+	      && contents [offset - 2] == 0x0f
+	      && (contents [offset - 1] & 0xf0) == 0x80));
+}
+
 /* Look through the relocs for a section during the first phase, and
    calculate needed space in the global offset table, procedure
    linkage table, and dynamic reloc sections.  */
@@ -2068,6 +2086,7 @@  elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
 	  if (h == NULL)
 	    continue;
 
+need_plt:
 	  eh->zero_undefweak &= 0x2;
 	  h->needs_plt = 1;
 	  h->plt.refcount = 1;
@@ -2088,6 +2107,16 @@  elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
 	  size_reloc = TRUE;
 	  goto do_size;
 
+	case R_X86_64_PC32:
+	case R_X86_64_PC32_BND:
+	  /* NB: Treat PC32 relocation with branch as PLT32 since there
+	     is no need to prepare for PLT branch on x86-64.   */
+	  if (bfd_link_pic (info)
+	      && h != NULL
+	      && is_32bit_relative_branch (contents, rel->r_offset))
+	    goto need_plt;
+	  goto pointer;
+
 	case R_X86_64_32:
 	  if (!ABI_64_P (abfd))
 	    goto pointer;
@@ -2113,8 +2142,6 @@  elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
 	case R_X86_64_PC8:
 	case R_X86_64_PC16:
-	case R_X86_64_PC32:
-	case R_X86_64_PC32_BND:
 	case R_X86_64_PC64:
 	case R_X86_64_64:
 pointer:
@@ -2307,24 +2334,6 @@  elf_x86_64_tpoff (struct bfd_link_info *info, bfd_vma address)
   return address - static_tls_size - htab->tls_sec->vma;
 }
 
-/* Is the instruction before OFFSET in CONTENTS a 32bit relative
-   branch?  */
-
-static bfd_boolean
-is_32bit_relative_branch (bfd_byte *contents, bfd_vma offset)
-{
-  /* Opcode		Instruction
-     0xe8		call
-     0xe9		jump
-     0x0f 0x8x		conditional jump */
-  return ((offset > 0
-	   && (contents [offset - 1] == 0xe8
-	       || contents [offset - 1] == 0xe9))
-	  || (offset > 1
-	      && contents [offset - 2] == 0x0f
-	      && (contents [offset - 1] & 0xf0) == 0x80));
-}
-
 /* Relocate an x86_64 ELF section.  */
 
 static bfd_boolean
@@ -2986,6 +2995,7 @@  do_ifunc_pointer:
 	      break;
 	    }
 
+call_via_plt:
 	  if (h->plt.offset != (bfd_vma) -1)
 	    {
 	      if (htab->plt_second != NULL)
@@ -3023,14 +3033,18 @@  do_ifunc_pointer:
 	case R_X86_64_PC32:
 	case R_X86_64_PC32_BND:
 	  /* Don't complain about -fPIC if the symbol is undefined when
-	     building executable unless it is unresolved weak symbol or
-	     -z nocopyreloc is used.  */
+	     building executable unless it is unresolved weak symbol,
+	     references a dynamic definition in PIE or -z nocopyreloc
+	     is used.  */
 	  if ((input_section->flags & SEC_ALLOC) != 0
 	      && (input_section->flags & SEC_READONLY) != 0
 	      && h != NULL
 	      && ((bfd_link_executable (info)
 		   && ((h->root.type == bfd_link_hash_undefweak
 			&& !resolved_to_zero)
+		       || (bfd_link_pie (info)
+			   && !h->def_regular
+			   && h->def_dynamic)
 		       || ((info->nocopyreloc
 			    || (eh->def_protected
 				&& elf_has_no_copy_on_protected (h->root.u.def.section->owner)))
@@ -3044,7 +3058,14 @@  do_ifunc_pointer:
 		    || r_type == R_X86_64_PC32_BND)
 		   && is_32bit_relative_branch (contents, rel->r_offset));
 
-	      if (SYMBOL_REFERENCES_LOCAL_P (info, h))
+	      /* NB: We can use PLT for PC32 branch since there is no
+		 need to prepare for PLT branch on x86-64.   */
+	      if (branch
+		  && htab->elf.splt != NULL
+		  && (h->plt.offset != (bfd_vma) -1
+		      || eh->plt_got.offset != (bfd_vma) -1))
+		goto call_via_plt;
+	      else if (SYMBOL_REFERENCES_LOCAL_P (info, h))
 		{
 		  /* Symbol is referenced locally.  Make sure it is
 		     defined locally or for a branch.  */
diff --git a/ld/testsuite/ld-x86-64/pr22791-1.err b/ld/testsuite/ld-x86-64/pr22791-1.err
new file mode 100644
index 0000000000..5500fa55ce
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22791-1.err
@@ -0,0 +1,2 @@ 
+.*relocation R_X86_64_PC32 against symbol `foo' can not be used when making a PIE object; recompile with -fPIC
+#...
diff --git a/ld/testsuite/ld-x86-64/pr22791-1a.c b/ld/testsuite/ld-x86-64/pr22791-1a.c
new file mode 100644
index 0000000000..cd0130cacd
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22791-1a.c
@@ -0,0 +1,4 @@ 
+void
+foo (void)
+{
+}
diff --git a/ld/testsuite/ld-x86-64/pr22791-1b.s b/ld/testsuite/ld-x86-64/pr22791-1b.s
new file mode 100644
index 0000000000..9751db49aa
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22791-1b.s
@@ -0,0 +1,6 @@ 
+	.text
+	.globl	main
+	.type	main, @function
+main:
+	movl	foo(%rip), %eax
+	.size	main, .-main
diff --git a/ld/testsuite/ld-x86-64/pr22791-2.rd b/ld/testsuite/ld-x86-64/pr22791-2.rd
new file mode 100644
index 0000000000..70deb30d84
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22791-2.rd
@@ -0,0 +1,6 @@ 
+#failif
+#...
+.*\(TEXTREL\).*
+#...
+[0-9a-f ]+R_X86_64_NONE.*
+#...
diff --git a/ld/testsuite/ld-x86-64/pr22791-2a.c b/ld/testsuite/ld-x86-64/pr22791-2a.c
new file mode 100644
index 0000000000..8b23ec8f2b
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22791-2a.c
@@ -0,0 +1,7 @@ 
+extern void bar (void);
+
+void
+foo (void)
+{
+  bar ();
+}
diff --git a/ld/testsuite/ld-x86-64/pr22791-2b.c b/ld/testsuite/ld-x86-64/pr22791-2b.c
new file mode 100644
index 0000000000..79ef27c085
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22791-2b.c
@@ -0,0 +1,7 @@ 
+#include <stdio.h>
+
+void
+bar (void)
+{
+  puts ("PASS");
+}
diff --git a/ld/testsuite/ld-x86-64/pr22791-2c.c b/ld/testsuite/ld-x86-64/pr22791-2c.c
new file mode 100644
index 0000000000..f1cb6b492b
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22791-2c.c
@@ -0,0 +1,8 @@ 
+extern void foo (void);
+
+int
+main (void)
+{
+  foo ();
+  return 0;
+}
diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp
index af3afcc2c7..8dac1c4dfa 100644
--- a/ld/testsuite/ld-x86-64/x86-64.exp
+++ b/ld/testsuite/ld-x86-64/x86-64.exp
@@ -1152,6 +1152,44 @@  if { [isnative] && [which $CC] != 0 } {
 	     {readelf -lW pr22393-3b.rd}} \
 	    "pr22393-3-static" \
 	] \
+	[list \
+	    "Build pr22791-1.so" \
+	    "-shared" \
+	    "-fPIC" \
+	    { pr22791-1a.c } \
+	    {} \
+	    "pr22791-1.so" \
+	] \
+	[list \
+	    "Build pr22791-1" \
+	    "-pie -Wl,--no-as-needed tmpdir/pr22791-1.so" \
+	    "$NOPIE_CFLAGS" \
+	    { pr22791-1b.s } \
+	    {{error_output "pr22791-1.err"}} \
+	    "pr22791-1" \
+	] \
+	[list \
+	    "Build pr22791-2a.o" \
+	    "" \
+	    "-fno-PIC $NOPIE_CFLAGS" \
+	    { pr22791-2a.c } \
+	] \
+	[list \
+	    "Build pr22791-2.so" \
+	    "-shared tmpdir/pr22791-2a.o" \
+	    "-fPIC" \
+	    { pr22791-2b.c } \
+	    {{readelf -drW pr22791-2.rd}} \
+	    "pr22791-2.so" \
+	] \
+	[list \
+	    "Build pr22791-2" \
+	    "-pie -Wl,--no-as-needed tmpdir/pr22791-2.so" \
+	    "$NOPIE_CFLAGS" \
+	    { pr22791-2c.c } \
+	    {{readelf -drW pr22791-2.rd}} \
+	    "pr22791-2" \
+	] \
     ]
 
     if  {[istarget "x86_64-*-linux*-gnux32"]} {
@@ -1477,6 +1515,15 @@  if { [isnative] && [which $CC] != 0 } {
 	    "pr22393-3-static" \
 	    "pass.out" \
 	] \
+	[list \
+	    "Run pr22791-2" \
+	    "-pie -Wl,--no-as-needed tmpdir/pr22791-2.so" \
+	    "" \
+	    { pr22791-2c.c } \
+	    "pr22791-2" \
+	    "pass.out" \
+	    "$NOPIE_CFLAGS" \
+	] \
     ]
 
     # Run-time tests which require working ifunc attribute support.