[binutils-gdb] x86: Generate PLT32 relocation for ".long foo@PLT - .L4"

"H.J. Lu via Binutils-cvs" <[email protected]> Wed, 29 Jul 2026 21:44:35 +0000 (GMT)
Newsgroups gmane.comp.gnu.binutils.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3D53902b30c66a=
d5edc95db93e8d5c1cb3c29d684d

commit 53902b30c66ad5edc95db93e8d5c1cb3c29d684d
Author: H.J. Lu <[email protected]>
Date:   Fri Jul 24 07:01:35 2026 +0800

    x86: Generate PLT32 relocation for ".long foo@PLT - .L4"
   =20
    LLVM assembler supports directives like ".long foo@PLT - .L4" for i386
    and x86-64.  Implement the same feature to generate PLT32 relocation
    for directives like ".long foo@PLT - .L4" so that PLT entries are used
    to resolve the PC32 relocation against function symbols.
   =20
    bfd/
   =20
            PR gas/34423
            * elf32-i386.c (elf_i386_reloc_type_lookup): Handle
            BFD_RELOC_386_PC32_TO_PLT32.
            * elf64-x86-64.c (x86_64_reloc_map): Add
            BFD_RELOC_X86_64_PC32_TO_PLT32.
            * reloc.c (bfd_reloc_code_real): Add BFD_RELOC_386_PC32_TO_PLT32
            and BFD_RELOC_X86_64_PC32_TO_PLT32.
            * bfd-in2.h: Regenerated.
            * libbfd.h: Likewise.
   =20
    gas/
   =20
            PR gas/34423
            * config/tc-i386.c (x86_cons): Return
            BFD_RELOC_X86_64_PC32_TO_PLT32 or BFD_RELOC_386_PC32_TO_PLT32
            for directives like ".long foo@PLT - .L4".
            (md_apply_fix): Compute addend for BFD_RELOC_386_PC32_TO_PLT32.
            (tc_gen_reloc): Handle BFD_RELOC_X86_64_PC32_TO_PLT32 and
            BFD_RELOC_386_PC32_TO_PLT32.  Compute addend like
            BFD_RELOC_32_PCREL for BFD_RELOC_X86_64_PC32_TO_PLT32.
            * testsuite/gas/i386/i386.exp: Run plt test.
            * testsuite/gas/i386/ilp32/reloc64.l: Updated.
            * testsuite/gas/i386/ilp32/reloc64.s: Replace ".long xtrn@plt -=
 ."
            with ".long xtrn@plt - _start".
            * testsuite/gas/i386/ilp32/x86-64-jump-table.d: New file.
            * testsuite/gas/i386/plt.d: Likewise.
            * testsuite/gas/i386/plt.s: Likewise.
            * testsuite/gas/i386/reloc32.l: Updated.
            * testsuite/gas/i386/reloc32.s: Replace ".long xtrn@plt - ."
            with ".long xtrn@plt - _start".
            * testsuite/gas/i386/reloc64.l: Updated.
            * testsuite/gas/i386/reloc64.s: Replace ".long xtrn@plt - ." wi=
th
            ".long xtrn@plt - ptr".
            * testsuite/gas/i386/x86-64-jump-table.d: New file.
            * testsuite/gas/i386/x86-64-jump-table.d: Likewise.
            * testsuite/gas/i386/x86-64-jump-table.s: Likewise.
            * testsuite/gas/i386/x86-64.exp: Run x86-64-jump-table.
   =20
    ld/
   =20
            PR gas/34423
            * testsuite/ld-x86-64/pr34423.c: New file.
            * testsuite/ld-x86-64/x86-64-jump-table.s: Likewise.
            * testsuite/ld-x86-64/x86-64.exp: Run gas/34423 tests.
   =20
    Signed-off-by: H.J. Lu <[email protected]>

Diff:
---
 bfd/bfd-in2.h                                    |  2 ++
 bfd/elf32-i386.c                                 |  4 +++
 bfd/elf64-x86-64.c                               |  1 +
 bfd/libbfd.h                                     |  2 ++
 bfd/reloc.c                                      |  4 +++
 gas/config/tc-i386.c                             | 33 ++++++++++++++---
 gas/testsuite/gas/i386/i386.exp                  |  2 ++
 gas/testsuite/gas/i386/ilp32/reloc64.l           |  3 +-
 gas/testsuite/gas/i386/ilp32/reloc64.s           |  2 +-
 gas/testsuite/gas/i386/ilp32/x86-64-jump-table.d |  4 +++
 gas/testsuite/gas/i386/plt.d                     | 14 ++++++++
 gas/testsuite/gas/i386/plt.s                     |  7 ++++
 gas/testsuite/gas/i386/reloc32.l                 |  4 +--
 gas/testsuite/gas/i386/reloc32.s                 |  2 +-
 gas/testsuite/gas/i386/reloc64.l                 |  3 +-
 gas/testsuite/gas/i386/reloc64.s                 |  2 +-
 gas/testsuite/gas/i386/x86-64-jump-table.d       | 29 +++++++++++++++
 gas/testsuite/gas/i386/x86-64-jump-table.s       | 31 ++++++++++++++++
 gas/testsuite/gas/i386/x86-64.exp                |  2 ++
 ld/testsuite/ld-x86-64/pr34423.c                 | 46 ++++++++++++++++++++=
++++
 ld/testsuite/ld-x86-64/x86-64-jump-table.s       | 30 ++++++++++++++++
 ld/testsuite/ld-x86-64/x86-64.exp                | 16 +++++++++
 22 files changed, 230 insertions(+), 13 deletions(-)

diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index e49d67316f3..e55bde7b129 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -3899,6 +3899,7 @@ enum bfd_reloc_code_real
   /* i386/elf relocations.  */
   BFD_RELOC_386_GOT32,
   BFD_RELOC_386_PLT32,
+  BFD_RELOC_386_PC32_TO_PLT32,
   BFD_RELOC_386_TLS_TPOFF,
   BFD_RELOC_386_TLS_IE,
   BFD_RELOC_386_TLS_GOTIE,
@@ -3937,6 +3938,7 @@ enum bfd_reloc_code_real
   BFD_RELOC_X86_64_TLSDESC,
   BFD_RELOC_X86_64_PC32_BND,
   BFD_RELOC_X86_64_PLT32_BND,
+  BFD_RELOC_X86_64_PC32_TO_PLT32,
   BFD_RELOC_X86_64_GOTPCRELX,
   BFD_RELOC_X86_64_REX_GOTPCRELX,
   BFD_RELOC_X86_64_CODE_4_GOTPCRELX,
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index 954803fcc3f..ae9276cff06 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -331,6 +331,10 @@ elf_i386_reloc_type_lookup (bfd *abfd,
       TRACE ("BFD_RELOC_386_GOT32X");
       return &elf_howto_table[R_386_GOT32X - R_386_tls_offset];
=20
+    case BFD_RELOC_386_PC32_TO_PLT32:
+      TRACE ("BFD_RELOC_X86_PC32_TO_PLT32");
+      return &elf_howto_table[R_386_PLT32];
+
     case BFD_RELOC_VTABLE_INHERIT:
       TRACE ("BFD_RELOC_VTABLE_INHERIT");
       return &elf_howto_table[R_386_GNU_VTINHERIT - R_386_vt_offset];
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index 575995d4957..ade6613b62a 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -281,6 +281,7 @@ static const struct elf_reloc_map x86_64_reloc_map[] =3D
   { BFD_RELOC_X86_64_CODE_6_GOTPCRELX, R_X86_64_CODE_6_GOTPCRELX, },
   { BFD_RELOC_X86_64_CODE_6_GOTTPOFF, R_X86_64_CODE_6_GOTTPOFF, },
   { BFD_RELOC_X86_64_CODE_6_GOTPC32_TLSDESC, R_X86_64_CODE_6_GOTPC32_TLSDE=
SC, },
+  { BFD_RELOC_X86_64_PC32_TO_PLT32, R_X86_64_PLT32, },
   { BFD_RELOC_VTABLE_INHERIT,	R_X86_64_GNU_VTINHERIT, },
   { BFD_RELOC_VTABLE_ENTRY,	R_X86_64_GNU_VTENTRY, },
 };
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index 27bc0875cf6..6e737e468df 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -1430,6 +1430,7 @@ static const char *const bfd_reloc_code_real_names[] =
=3D { "@@uninitialized@@",
   "BFD_RELOC_MN10300_TLS_TPOFF",
   "BFD_RELOC_386_GOT32",
   "BFD_RELOC_386_PLT32",
+  "BFD_RELOC_386_PC32_TO_PLT32",
   "BFD_RELOC_386_TLS_TPOFF",
   "BFD_RELOC_386_TLS_IE",
   "BFD_RELOC_386_TLS_GOTIE",
@@ -1466,6 +1467,7 @@ static const char *const bfd_reloc_code_real_names[] =
=3D { "@@uninitialized@@",
   "BFD_RELOC_X86_64_TLSDESC",
   "BFD_RELOC_X86_64_PC32_BND",
   "BFD_RELOC_X86_64_PLT32_BND",
+  "BFD_RELOC_X86_64_PC32_TO_PLT32",
   "BFD_RELOC_X86_64_GOTPCRELX",
   "BFD_RELOC_X86_64_REX_GOTPCRELX",
   "BFD_RELOC_X86_64_CODE_4_GOTPCRELX",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index 6b9e00da5d6..29288f8099d 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -2319,6 +2319,8 @@ ENUM
   BFD_RELOC_386_GOT32
 ENUMX
   BFD_RELOC_386_PLT32
+ENUMX
+  BFD_RELOC_386_PC32_TO_PLT32
 ENUMX
   BFD_RELOC_386_TLS_TPOFF
 ENUMX
@@ -2394,6 +2396,8 @@ ENUMX
   BFD_RELOC_X86_64_PC32_BND
 ENUMX
   BFD_RELOC_X86_64_PLT32_BND
+ENUMX
+  BFD_RELOC_X86_64_PC32_TO_PLT32
 ENUMX
   BFD_RELOC_X86_64_GOTPCRELX
 ENUMX
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index d1ef80ce6d1..67badd29298 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -13553,10 +13553,20 @@ x86_cons (expressionS *exp, int size)
 		    || got_reloc =3D=3D BFD_RELOC_32_PLT_PCREL)
 		   && exp->X_op !=3D O_symbol)
 	    {
-	      char c =3D *input_line_pointer;
-	      *input_line_pointer =3D 0;
-	      as_bad (_("invalid PLT expression `%s'"), save);
-	      *input_line_pointer =3D c;
+	    /* Allow directives like ".long foo@PLT - .L4".
+	       BFD_RELOC_X86_64_PC32_TO_PLT32 has an explicit addend and
+	       BFD_RELOC_386_PC32_TO_PLT32 has an implicit addend.  */
+	      if (size =3D=3D 4 && exp->X_op =3D=3D O_subtract)
+		got_reloc =3D (object_64bit
+			     ? BFD_RELOC_X86_64_PC32_TO_PLT32
+			     : BFD_RELOC_386_PC32_TO_PLT32);
+	      else
+		{
+		  char c =3D *input_line_pointer;
+		  *input_line_pointer =3D 0;
+		  as_bad (_("invalid PLT expression `%s'"), save);
+		  *input_line_pointer =3D c;
+		}
 	    }
 	}
     }
@@ -16781,6 +16791,12 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg A=
TTRIBUTE_UNUSED)
 	  value =3D -4;
 	break;
=20
+      case BFD_RELOC_386_PC32_TO_PLT32:
+	/* Set the implicit addend.  */
+	value =3D (seg->vma - fixP->fx_size + fixP->fx_addnumber
+		 + md_pcrel_from (fixP));
+	break;
+
       case BFD_RELOC_386_TLS_GD:
       case BFD_RELOC_386_TLS_LDM:
       case BFD_RELOC_386_TLS_IE_32:
@@ -18586,6 +18602,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, f=
ixS *fixp)
     case BFD_RELOC_386_TLS_LE:
     case BFD_RELOC_386_TLS_GOTDESC:
     case BFD_RELOC_386_TLS_DESC_CALL:
+    case BFD_RELOC_386_PC32_TO_PLT32:
     case BFD_RELOC_X86_64_TLSGD:
     case BFD_RELOC_X86_64_TLSLD:
     case BFD_RELOC_X86_64_DTPOFF32:
@@ -18608,6 +18625,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, f=
ixS *fixp)
     case BFD_RELOC_X86_64_CODE_5_GOTPC32_TLSDESC:
     case BFD_RELOC_X86_64_CODE_6_GOTPC32_TLSDESC:
     case BFD_RELOC_X86_64_TLSDESC_CALL:
+    case BFD_RELOC_X86_64_PC32_TO_PLT32:
     case BFD_RELOC_RVA:
     case BFD_RELOC_VTABLE_ENTRY:
     case BFD_RELOC_VTABLE_INHERIT:
@@ -18751,6 +18769,13 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, =
fixS *fixp)
 	  case BFD_RELOC_X86_64_TLSDESC_CALL:
 	    rel->addend =3D fixp->fx_offset - fixp->fx_size;
 	    break;
+	  case BFD_RELOC_X86_64_PC32_TO_PLT32:
+	    /* This came from a directive like ".long foo@PLT - .L4".
+	       Generate R_X86_64_PLT32 with addend computed like
+	       R_X86_64_PC32 so that PLT entry is used to resolve
+	       this PC32 relocation.   */
+	    code =3D BFD_RELOC_32_PLT_PCREL;
+	    /* Fall through.  */
 	  default:
 	    rel->addend =3D (section->vma
 			   - fixp->fx_size
diff --git a/gas/testsuite/gas/i386/i386.exp b/gas/testsuite/gas/i386/i386.=
exp
index e27bca0f69c..22fd3412d53 100644
--- a/gas/testsuite/gas/i386/i386.exp
+++ b/gas/testsuite/gas/i386/i386.exp
@@ -792,6 +792,8 @@ if [gas_32_check] then {
=20
 	run_dump_test "no-got"
=20
+	run_dump_test "plt"
+
 	run_dump_test "gotx-default"
 	run_dump_test "no-gotx-default"
=20
diff --git a/gas/testsuite/gas/i386/ilp32/reloc64.l b/gas/testsuite/gas/i38=
6/ilp32/reloc64.l
index 14a111d763f..08c2702cdb7 100644
--- a/gas/testsuite/gas/i386/ilp32/reloc64.l
+++ b/gas/testsuite/gas/i386/ilp32/reloc64.l
@@ -103,8 +103,6 @@
 .*:176:  Info: .*
 .*:3: Error: .*
 .*:177:  Info: .*
-.*:3: Error: .*
-.*:190:  Info: .*
 .*:193: Error: .* too large for field of 4 bytes at .*
 .*:194: Error: .* too large for field of 4 bytes at .*
 .*:195: Error: .* too large for field of 4 bytes at .*
@@ -113,6 +111,7 @@
 .*:197: Error: .* too large for field of 1 byte at .*
 .*:198: Error: .* too large for field of 2 bytes at .*
 .*:198: Error: .* too large for field of 1 byte at .*
+.*:190: Error: can't resolve xtrn - _start
 .*:201: Error: .* too large for field of 4 bytes at .*
 .*:202: Error: .* too large for field of 2 bytes at .*
 .*:203: Error: .* too large for field of 2 bytes at .*
diff --git a/gas/testsuite/gas/i386/ilp32/reloc64.s b/gas/testsuite/gas/i38=
6/ilp32/reloc64.s
index db2d2acdf5d..a4ccdb29916 100644
--- a/gas/testsuite/gas/i386/ilp32/reloc64.s
+++ b/gas/testsuite/gas/i386/ilp32/reloc64.s
@@ -187,7 +187,7 @@ bad	.byte	xtrn@tpoff
 	.quad	xtrn - 0x80000000
 	.long	xtrn@got - 4
 	.long	xtrn@got + 4
-bad	.long	xtrn@plt - .
+bad	.long	xtrn@plt - _start
=20
 	.text
 bad	add	$x+0x123456789, %rax
diff --git a/gas/testsuite/gas/i386/ilp32/x86-64-jump-table.d b/gas/testsui=
te/gas/i386/ilp32/x86-64-jump-table.d
new file mode 100644
index 00000000000..2cff87d4445
--- /dev/null
+++ b/gas/testsuite/gas/i386/ilp32/x86-64-jump-table.d
@@ -0,0 +1,4 @@
+#source: ../x86-64-jump-table.s
+#readelf: -rsW
+#name: x86-64 (ILP32) PIC jump table
+#dump: ../x86-64-jump-table.d
diff --git a/gas/testsuite/gas/i386/plt.d b/gas/testsuite/gas/i386/plt.d
new file mode 100644
index 00000000000..e4af0d20c87
--- /dev/null
+++ b/gas/testsuite/gas/i386/plt.d
@@ -0,0 +1,14 @@
+#as:
+#readelf: -x .rodata -r
+
+Relocation section '.rel.rodata' at offset 0xd4 contains 4 entries:
+ Offset     Info    Type            Sym.Value  Sym. Name
+0+  00000104 R_386_PLT32       00000000   foo1
+0+4  00000204 R_386_PLT32       00000000   foo2
+0+8  00000304 R_386_PLT32       00000000   foo3
+0+c  00000404 R_386_PLT32       00000000   foo4
+
+Hex dump of section '.rodata':
+ NOTE: This section has relocations against it, but these have NOT been ap=
plied to this dump.
+  0x00000000 00000000 04000000 08000000 0c000000 ................
+#pass
diff --git a/gas/testsuite/gas/i386/plt.s b/gas/testsuite/gas/i386/plt.s
new file mode 100644
index 00000000000..c854c3fe739
--- /dev/null
+++ b/gas/testsuite/gas/i386/plt.s
@@ -0,0 +1,7 @@
+
+	.section .rodata
+.L4:
+        .long	foo1@PLT - .L4
+        .long	foo2@PLT - .L4
+        .long	foo3@PLT - .L4
+        .long	foo4@PLT - .L4
diff --git a/gas/testsuite/gas/i386/reloc32.l b/gas/testsuite/gas/i386/relo=
c32.l
index 71c65212dc9..31c71a0be28 100644
--- a/gas/testsuite/gas/i386/reloc32.l
+++ b/gas/testsuite/gas/i386/reloc32.l
@@ -131,6 +131,6 @@
 .*:160:  Info: .*
 .*:3: Error: .*
 .*:161:  Info: .*
-.*:3: Error: .*
-.*:164:  Info: .*
+.*:56: Error: .*
+.*:164: Error: .*
 #pass
diff --git a/gas/testsuite/gas/i386/reloc32.s b/gas/testsuite/gas/i386/relo=
c32.s
index 5616cd57e3f..0ba69eae4d0 100644
--- a/gas/testsuite/gas/i386/reloc32.s
+++ b/gas/testsuite/gas/i386/reloc32.s
@@ -161,7 +161,7 @@ bad	.byte	xtrn@ntpoff
 bad	.byte	xtrn@tpoff
 	.long	xtrn@got + 4
 	.long	xtrn@got - 4
-bad	.long	xtrn@plt - .
+bad	.long	xtrn@plt - _start
=20
 	.text
 	movl	$ptr@PLT, %eax
diff --git a/gas/testsuite/gas/i386/reloc64.l b/gas/testsuite/gas/i386/relo=
c64.l
index c60c45d139a..d84d9042958 100644
--- a/gas/testsuite/gas/i386/reloc64.l
+++ b/gas/testsuite/gas/i386/reloc64.l
@@ -163,5 +163,4 @@
 .*:219:  Info: .*
 .*:3: Error: .*
 .*:220:  Info: .*
-.*:3: Error: .*
-.*:227:  Info: .*
+.*:227: Error: can't resolve xtrn - ptr
diff --git a/gas/testsuite/gas/i386/reloc64.s b/gas/testsuite/gas/i386/relo=
c64.s
index 5c0f4136a09..f248964813f 100644
--- a/gas/testsuite/gas/i386/reloc64.s
+++ b/gas/testsuite/gas/i386/reloc64.s
@@ -224,7 +224,7 @@ bad	.byte	xtrn@gotplt
 	mov	xtrn(,%ebx), %eax
 	vgatherdps %xmm2, xtrn(,%xmm1), %xmm0
 	addr32 vgatherdps %xmm2, xtrn(,%xmm1), %xmm0
-bad	.long	xtrn@plt - .
+bad	.long	xtrn@plt - ptr
=20
 	.text
 	movabs	$ptr@GOT, %rax
diff --git a/gas/testsuite/gas/i386/x86-64-jump-table.d b/gas/testsuite/gas=
/i386/x86-64-jump-table.d
new file mode 100644
index 00000000000..32c957b6ba6
--- /dev/null
+++ b/gas/testsuite/gas/i386/x86-64-jump-table.d
@@ -0,0 +1,29 @@
+#as:
+#readelf: -rsW
+#name: x86-64 PIC jump table
+#notarget: *-*-solaris*
+
+#...
+Relocation section '.rela.text' at offset 0x[0-9a-f]+ contains 3 entries:
+ +Offset +Info +Type +Sym.* Value +Symbol's Name \+ Addend
+0+8  0+40+2 +R_X86_64_PC32 +0+ +bar0 - 4
+0+f  0+20+2 +R_X86_64_PC32 +0+ +.rodata - 4
+0+20  0+50+4 +R_X86_64_PLT32 +0+ +bar2 - 4
+#...
+Relocation section '.rela.rodata' at offset 0x[0-9a-f]+ contains 5 entries:
+ +Offset +Info +Type +Sym.* Value +Symbol's Name \+ Addend
+0+  0+40+4 +R_X86_64_PLT32 +0+ +bar0 \+ 0
+0+4  0+60+4 +R_X86_64_PLT32 +0+ +bar1 \+ 4
+0+8  0+10+2 +R_X86_64_PC32 +0+ +.text \+ 27
+0+c  0+70+4 +R_X86_64_PLT32 +0+ +bar3 \+ c
+0+10+  0+80+4 +R_X86_64_PLT32 +0+ +bar4 \+ 10
+#...
+ +[0-9]+: 0+ +0 SECTION LOCAL +DEFAULT +1 .text
+ +[0-9]+: 0+ +0 SECTION LOCAL +DEFAULT +5 .rodata
+ +[0-9]+: 0+ +36 FUNC +GLOBAL +DEFAULT +1 foo
+ +[0-9]+: 0+ +0 NOTYPE +GLOBAL DEFAULT +UND bar0
+ +[0-9]+: 0+ +0 NOTYPE +GLOBAL DEFAULT +UND bar2
+ +[0-9]+: 0+ +0 NOTYPE +GLOBAL DEFAULT +UND bar1
+ +[0-9]+: 0+ +0 NOTYPE +GLOBAL DEFAULT +UND bar3
+ +[0-9]+: 0+ +0 NOTYPE +GLOBAL DEFAULT +UND bar4
+#pass
diff --git a/gas/testsuite/gas/i386/x86-64-jump-table.s b/gas/testsuite/gas=
/i386/x86-64-jump-table.s
new file mode 100644
index 00000000000..aefffad8f65
--- /dev/null
+++ b/gas/testsuite/gas/i386/x86-64-jump-table.s
@@ -0,0 +1,31 @@
+# Check R_X86_64_PLT32 relocation in jump table.
+
+        .text
+        .p2align 4
+        .globl	foo
+        .type	foo, @function
+foo:
+	.cfi_startproc
+        cmpl	$4, %edi
+        ja	.L1
+        leaq	bar0(%rip), %rdx
+        leaq	.L4(%rip), %rdx
+        movl	%edi, %edi
+        movslq	(%rdx,%rdi,4), %rax
+        addq	%rdx, %rax
+        jmp	*%rax
+.L1:
+	ret
+.Lbar2:
+	jmp	bar2
+	.cfi_endproc
+        .size	foo, .-foo
+        .section	.rodata
+        .p2align 2
+.L4:
+        .long	[email protected]
+        .long	[email protected]
+        .long	.Lbar2-.L4
+        .long	[email protected]
+        .long	[email protected]
+        .section	.note.GNU-stack,"",@progbits
diff --git a/gas/testsuite/gas/i386/x86-64.exp b/gas/testsuite/gas/i386/x86=
-64.exp
index 58382b55e31..710f749a8dc 100644
--- a/gas/testsuite/gas/i386/x86-64.exp
+++ b/gas/testsuite/gas/i386/x86-64.exp
@@ -778,6 +778,8 @@ if [is_elf_format] then {
     run_dump_test "reloc-section-sym-all"
     run_dump_test "reloc-section-sym-internal"
     run_dump_test "reloc-section-sym-none"
+
+    run_dump_test "x86-64-jump-table"
 }
 run_dump_test pr27198
 run_dump_test pr29483
diff --git a/ld/testsuite/ld-x86-64/pr34423.c b/ld/testsuite/ld-x86-64/pr34=
423.c
new file mode 100644
index 00000000000..fc5a943a54a
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr34423.c
@@ -0,0 +1,46 @@
+#include <stdio.h>
+
+int
+bar0 (void)
+{
+  return 0;
+}
+
+int
+bar1 (void)
+{
+  return 1;
+}
+
+int
+bar2 (void)
+{
+  return 2;
+}
+
+int
+bar3 (void)
+{
+  return 3;
+}
+
+int
+bar4 (void)
+{
+  return 4;
+}
+
+extern int foo (int);
+
+int
+main ()
+{
+  if (foo (1) =3D=3D 1
+      && foo (3) =3D=3D 3
+      && foo (4) =3D=3D 4
+      && foo (2) =3D=3D 2
+      && foo (0) =3D=3D 0)
+    printf ("PASS\n");
+
+  return 0;
+}
diff --git a/ld/testsuite/ld-x86-64/x86-64-jump-table.s b/ld/testsuite/ld-x=
86-64/x86-64-jump-table.s
new file mode 100644
index 00000000000..bd06f714469
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/x86-64-jump-table.s
@@ -0,0 +1,30 @@
+# Check R_X86_64_PLT32 relocation in jump table.
+
+        .text
+        .p2align 4
+        .globl	foo
+        .type	foo, @function
+foo:
+	.cfi_startproc
+        cmpl	$4, %edi
+        ja	.L1
+        leaq	.L4(%rip), %rdx
+        movl	%edi, %edi
+        movslq	(%rdx,%rdi,4), %rax
+        addq	%rdx, %rax
+        jmp	*%rax
+.L1:
+	ret
+.Lbar2:
+	jmp	bar2@PLT
+	.cfi_endproc
+        .size	foo, .-foo
+        .section	.rodata
+        .p2align 2
+.L4:
+        .long	[email protected]
+        .long	[email protected]
+        .long	.Lbar2-.L4
+        .long	[email protected]
+        .long	[email protected]
+        .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 07607810d15..985d96dcfba 100644
--- a/ld/testsuite/ld-x86-64/x86-64.exp
+++ b/ld/testsuite/ld-x86-64/x86-64.exp
@@ -1523,6 +1523,14 @@ if { [isnative] && [check_compiler_available] } {
 	    {} \
 	    "pr32067" \
 	] \
+	[list \
+	    "Build libjump-table.so" \
+	    "-shared" \
+	    "" \
+	    { x86-64-jump-table.s } \
+	    {} \
+	    "libjump-table.so" \
+	] \
     ]
=20
     if  {[istarget "x86_64-*-linux*-gnux32"]} {
@@ -2046,6 +2054,14 @@ if { [isnative] && [check_compiler_available] } {
 	    "plt3" \
 	    "pass.out" \
 	] \
+	[list \
+	    "Run pr34423" \
+	    "-Wl,--no-as-needed tmpdir/libjump-table.so" \
+	    "" \
+	    { pr34423.c } \
+	    "pr34423" \
+	    "pass.out" \
+	] \
     ]
=20
     # Run-time tests which require working ifunc attribute support.