diff --git a/bfd/elf-linker-x86.h b/bfd/elf-linker-x86.h
index e39dbf21a4f..1e6ecb1bd3b 100644
--- a/bfd/elf-linker-x86.h
+++ b/bfd/elf-linker-x86.h
@@ -61,6 +61,9 @@ struct elf_linker_x86_params
   /* Report relative relocations.  */
   unsigned int report_relative_reloc : 1;
 
+  /* Mark PLT with dynamic tags.  */
+  unsigned int mark_plt : 1;
+
   /* X86-64 ISA level needed.  */
   unsigned int isa_level;
 
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index e7a0a9166f5..3b7a8aeee11 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -4455,7 +4455,12 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
 	  else
 	    {
 	      rela.r_info = htab->r_info (h->dynindx, R_X86_64_JUMP_SLOT);
-	      rela.r_addend = 0;
+	      if (htab->params->mark_plt)
+		rela.r_addend = (resolved_plt->output_section->vma
+				 + plt_offset
+				 + htab->plt.plt_indirect_branch_offset);
+	      else
+		rela.r_addend = 0;
 	      plt_index = htab->next_jump_slot_index++;
 	    }
 
diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c
index 103559d77ec..58bd76dc6fc 100644
--- a/bfd/elfxx-x86.c
+++ b/bfd/elfxx-x86.c
@@ -2525,6 +2525,19 @@ _bfd_x86_elf_size_dynamic_sections (bfd *output_bfd,
 	}
     }
 
+  asection *resolved_plt = NULL;
+
+  if (htab->params->mark_plt && htab->elf.dynamic_sections_created)
+    {
+      if (htab->plt_second != NULL)
+	resolved_plt = htab->plt_second;
+      else
+	resolved_plt = htab->elf.splt;
+
+      if (resolved_plt != NULL && resolved_plt->size == 0)
+	resolved_plt = NULL;
+    }
+
   /* We now have determined the sizes of the various dynamic sections.
      Allocate memory for them.  */
   relocs = false;
@@ -2673,6 +2686,12 @@ _bfd_x86_elf_size_dynamic_sections (bfd *output_bfd,
 	_bfd_x86_elf_write_sframe_plt (output_bfd, info, SFRAME_PLT_SEC);
     }
 
+  if (resolved_plt != NULL
+      && (!_bfd_elf_add_dynamic_entry (info, DT_X86_64_PLT, 0)
+	  || !_bfd_elf_add_dynamic_entry (info, DT_X86_64_PLTSZ, 0)
+	  || !_bfd_elf_add_dynamic_entry (info, DT_X86_64_PLTENT, 0)))
+    return false;
+
   return _bfd_elf_maybe_vxworks_add_dynamic_tags (output_bfd, info,
 						  relocs);
 }
@@ -2747,6 +2766,12 @@ _bfd_x86_elf_finish_dynamic_sections (bfd *output_bfd,
   if (sdyn == NULL || htab->elf.sgot == NULL)
     abort ();
 
+  asection *resolved_plt;
+  if (htab->plt_second != NULL)
+    resolved_plt = htab->plt_second;
+  else
+    resolved_plt = htab->elf.splt;
+
   sizeof_dyn = bed->s->sizeof_dyn;
   dyncon = sdyn->contents;
   dynconend = sdyn->contents + sdyn->size;
@@ -2791,6 +2816,19 @@ _bfd_x86_elf_finish_dynamic_sections (bfd *output_bfd,
 	  dyn.d_un.d_ptr = s->output_section->vma + s->output_offset
 	    + htab->elf.tlsdesc_got;
 	  break;
+
+	case DT_X86_64_PLT:
+	  s = resolved_plt->output_section;
+	  dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
+	  break;
+
+	case DT_X86_64_PLTSZ:
+	  dyn.d_un.d_val = resolved_plt->size;
+	  break;
+
+	case DT_X86_64_PLTENT:
+	  dyn.d_un.d_ptr = htab->plt.plt_entry_size;
+	  break;
 	}
 
       (*bed->s->swap_dyn_out) (output_bfd, &dyn, dyncon);
@@ -3561,6 +3599,7 @@ _bfd_x86_elf_get_synthetic_symtab (bfd *abfd,
   bfd_vma (*get_plt_got_vma) (struct elf_x86_plt *, bfd_vma, bfd_vma,
 			      bfd_vma);
   bool (*valid_plt_reloc_p) (unsigned int);
+  unsigned int jump_slot_reloc;
 
   dynrelbuf = NULL;
   if (count == 0)
@@ -3601,11 +3640,13 @@ _bfd_x86_elf_get_synthetic_symtab (bfd *abfd,
     {
       get_plt_got_vma = elf_x86_64_get_plt_got_vma;
       valid_plt_reloc_p = elf_x86_64_valid_plt_reloc_p;
+      jump_slot_reloc = R_X86_64_JUMP_SLOT;
     }
   else
     {
       get_plt_got_vma = elf_i386_get_plt_got_vma;
       valid_plt_reloc_p = elf_i386_valid_plt_reloc_p;
+      jump_slot_reloc = R_386_JUMP_SLOT;
       if (got_addr)
 	{
 	  /* Check .got.plt and then .got to get the _GLOBAL_OFFSET_TABLE_
@@ -3710,7 +3751,9 @@ _bfd_x86_elf_get_synthetic_symtab (bfd *abfd,
 		len = strlen ((*p->sym_ptr_ptr)->name);
 		memcpy (names, (*p->sym_ptr_ptr)->name, len);
 		names += len;
-		if (p->addend != 0)
+		/* There may be JUMP_SLOT and IRELATIVE relocations.
+		   JUMP_SLOT r_addend should be ignored.  */
+		if (p->addend != 0 && p->howto->type != jump_slot_reloc)
 		  {
 		    char buf[30], *a;
 
@@ -4275,6 +4318,7 @@ _bfd_x86_elf_link_setup_gnu_properties
      still be used with LD_AUDIT or LD_PROFILE if PLT entry is used for
      canonical function address.  */
   htab->plt.has_plt0 = 1;
+  htab->plt.plt_indirect_branch_offset = 0;
   normal_target = htab->elf.target_os == is_normal;
 
   if (normal_target)
@@ -4283,6 +4327,7 @@ _bfd_x86_elf_link_setup_gnu_properties
 	{
 	  htab->lazy_plt = init_table->lazy_ibt_plt;
 	  htab->non_lazy_plt = init_table->non_lazy_ibt_plt;
+	  htab->plt.plt_indirect_branch_offset = 4;
 	}
       else
 	{
diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h
index 3b4644ca478..0bc966b1274 100644
--- a/bfd/elfxx-x86.h
+++ b/bfd/elfxx-x86.h
@@ -502,6 +502,9 @@ struct elf_x86_plt_layout
   /* 1 has PLT0.  */
   unsigned int has_plt0;
 
+  /* Offset of indirect branch in plt_entry.  */
+  unsigned int plt_indirect_branch_offset;
+
   /* Offsets into plt_entry that are to be replaced with...  */
   unsigned int plt_got_offset;    /* ... address of this symbol in .got. */
 
diff --git a/binutils/readelf.c b/binutils/readelf.c
index e9935c010cf..34ac6b62443 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -2522,6 +2522,22 @@ get_riscv_dynamic_type (unsigned long type)
     }
 }
 
+static const char *
+get_x86_64_dynamic_type (unsigned long type)
+{
+  switch (type)
+    {
+    case DT_X86_64_PLT:
+      return "DT_X86_64_PLT";
+    case DT_X86_64_PLTSZ:
+      return "DT_X86_64_PLTSZ";
+    case DT_X86_64_PLTENT:
+      return "DT_X86_64_PLTENT";
+    default:
+      return NULL;
+    }
+}
+
 static const char *
 get_dynamic_type (Filedata * filedata, unsigned long type)
 {
@@ -2650,6 +2666,9 @@ get_dynamic_type (Filedata * filedata, unsigned long type)
 	    case EM_RISCV:
 	      result = get_riscv_dynamic_type (type);
 	      break;
+	    case EM_X86_64:
+	      result = get_x86_64_dynamic_type (type);
+	      break;
 	    default:
 	      if (filedata->file_header.e_ident[EI_OSABI] == ELFOSABI_SOLARIS)
 		result = get_solaris_dynamic_type (type);
diff --git a/include/elf/x86-64.h b/include/elf/x86-64.h
index 60b3c2ad10e..1b87beef41a 100644
--- a/include/elf/x86-64.h
+++ b/include/elf/x86-64.h
@@ -95,4 +95,9 @@ END_RELOC_NUMBERS (R_X86_64_max)
 #define SHN_X86_64_LCOMMON 	(SHN_LORESERVE + 2)
 
 #define SHF_X86_64_LARGE	0x10000000
+
+#define DT_X86_64_PLT		(DT_LOPROC + 0)
+#define DT_X86_64_PLTSZ		(DT_LOPROC + 1)
+#define DT_X86_64_PLTENT	(DT_LOPROC + 3)
+
 #endif
diff --git a/ld/emulparams/elf32_x86_64.sh b/ld/emulparams/elf32_x86_64.sh
index 4bff41287c1..f6c6de9cc9e 100644
--- a/ld/emulparams/elf32_x86_64.sh
+++ b/ld/emulparams/elf32_x86_64.sh
@@ -6,6 +6,7 @@ source_sh ${srcdir}/emulparams/call_nop.sh
 source_sh ${srcdir}/emulparams/cet.sh
 source_sh ${srcdir}/emulparams/x86-report-relative.sh
 source_sh ${srcdir}/emulparams/x86-64-level.sh
+source_sh ${srcdir}/emulparams/x86-64-plt.sh
 source_sh ${srcdir}/emulparams/static.sh
 source_sh ${srcdir}/emulparams/dt-relr.sh
 SCRIPT_NAME=elf
diff --git a/ld/emulparams/elf_x86_64.sh b/ld/emulparams/elf_x86_64.sh
index a689a7b6dc4..466da2c48ca 100644
--- a/ld/emulparams/elf_x86_64.sh
+++ b/ld/emulparams/elf_x86_64.sh
@@ -7,6 +7,7 @@ source_sh ${srcdir}/emulparams/cet.sh
 source_sh ${srcdir}/emulparams/x86-report-relative.sh
 source_sh ${srcdir}/emulparams/x86-64-level.sh
 source_sh ${srcdir}/emulparams/x86-64-lam.sh
+source_sh ${srcdir}/emulparams/x86-64-plt.sh
 source_sh ${srcdir}/emulparams/static.sh
 source_sh ${srcdir}/emulparams/dt-relr.sh
 SCRIPT_NAME=elf
diff --git a/ld/emulparams/x86-64-plt.sh b/ld/emulparams/x86-64-plt.sh
new file mode 100644
index 00000000000..fc2093df5d4
--- /dev/null
+++ b/ld/emulparams/x86-64-plt.sh
@@ -0,0 +1,12 @@
+PARSE_AND_LIST_OPTIONS_X86_64_PLT='
+  fprintf (file, _("\
+  -z mark-plt                 Mark PLT with dynamic tags\n\
+  -z nomark-plt               Do not mark PLT with dynamic tags (default)\n"));
+'
+PARSE_AND_LIST_ARGS_CASE_Z_X86_64_PLT='
+      else if (strcmp (optarg, "mark-plt") == 0)
+	params.mark_plt = 1;
+'
+
+PARSE_AND_LIST_OPTIONS="$PARSE_AND_LIST_OPTIONS $PARSE_AND_LIST_OPTIONS_X86_64_PLT"
+PARSE_AND_LIST_ARGS_CASE_Z="$PARSE_AND_LIST_ARGS_CASE_Z $PARSE_AND_LIST_ARGS_CASE_Z_X86_64_PLT"
diff --git a/ld/testsuite/ld-x86-64/mark-plt-1.s b/ld/testsuite/ld-x86-64/mark-plt-1.s
new file mode 100644
index 00000000000..e3f03c89b51
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/mark-plt-1.s
@@ -0,0 +1,7 @@
+	.text
+	.globl	foo
+	.type	foo, @function
+foo:
+	call	bar@PLT
+	ret
+	.section	.note.GNU-stack,"",@progbits
diff --git a/ld/testsuite/ld-x86-64/mark-plt-1a-x32.d b/ld/testsuite/ld-x86-64/mark-plt-1a-x32.d
new file mode 100644
index 00000000000..2051356be73
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/mark-plt-1a-x32.d
@@ -0,0 +1,12 @@
+#source: mark-plt-1.s
+#as: --x32
+#ld: -melf32_x86_64 -shared -z mark-plt
+#readelf: -drW
+
+#...
+ 0x70000000 \(DT_X86_64_PLT\)              0x1000
+ 0x70000001 \(DT_X86_64_PLTSZ\)            0x20
+ 0x70000003 \(DT_X86_64_PLTENT\)           0x10
+#...
+[0-9a-f ]+R_X86_64_JUMP_SLOT +0+ +bar \+ 1010
+#pass
diff --git a/ld/testsuite/ld-x86-64/mark-plt-1a.d b/ld/testsuite/ld-x86-64/mark-plt-1a.d
new file mode 100644
index 00000000000..a252e95e759
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/mark-plt-1a.d
@@ -0,0 +1,12 @@
+#source: mark-plt-1.s
+#as: --64
+#ld: -melf_x86_64 -shared -z mark-plt
+#readelf: -drW
+
+#...
+ 0x0000000070000000 \(DT_X86_64_PLT\)      0x1000
+ 0x0000000070000001 \(DT_X86_64_PLTSZ\)    0x20
+ 0x0000000070000003 \(DT_X86_64_PLTENT\)   0x10
+#...
+[0-9a-f ]+R_X86_64_JUMP_SLOT +0+ +bar \+ 1010
+#pass
diff --git a/ld/testsuite/ld-x86-64/mark-plt-1b-x32.d b/ld/testsuite/ld-x86-64/mark-plt-1b-x32.d
new file mode 100644
index 00000000000..74306a0d8d7
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/mark-plt-1b-x32.d
@@ -0,0 +1,16 @@
+#source: mark-plt-1.s
+#as: --x32
+#ld: -melf32_x86_64 -shared -z mark-plt
+#objdump: -dw
+
+#...
+0+1010 <bar@plt>:
+ +1010:	ff 25 9a 10 00 00    	jmp    \*0x109a\(%rip\)        # 20b0 <bar>
+ +1016:	68 00 00 00 00       	push   \$0x0
+ +101b:	e9 e0 ff ff ff       	jmp    1000 <bar@plt-0x10>
+
+Disassembly of section .text:
+
+0+1020 <foo>:
+ +1020:	e8 eb ff ff ff       	call   1010 <bar@plt>
+#pass
diff --git a/ld/testsuite/ld-x86-64/mark-plt-1b.d b/ld/testsuite/ld-x86-64/mark-plt-1b.d
new file mode 100644
index 00000000000..dc046c031eb
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/mark-plt-1b.d
@@ -0,0 +1,16 @@
+#source: mark-plt-1.s
+#as: --64
+#ld: -melf_x86_64 -shared -z mark-plt
+#objdump: -dw
+
+#...
+0+1010 <bar@plt>:
+ +1010:	ff 25 32 11 00 00    	jmp    \*0x1132\(%rip\)        # 2148 <bar>
+ +1016:	68 00 00 00 00       	push   \$0x0
+ +101b:	e9 e0 ff ff ff       	jmp    1000 <bar@plt-0x10>
+
+Disassembly of section .text:
+
+0+1020 <foo>:
+ +1020:	e8 eb ff ff ff       	call   1010 <bar@plt>
+#pass
diff --git a/ld/testsuite/ld-x86-64/mark-plt-1c-x32.d b/ld/testsuite/ld-x86-64/mark-plt-1c-x32.d
new file mode 100644
index 00000000000..6354dc3bd95
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/mark-plt-1c-x32.d
@@ -0,0 +1,12 @@
+#source: mark-plt-1.s
+#as: --x32
+#ld: -melf32_x86_64 -shared -z mark-plt -z ibtplt
+#readelf: -drW
+
+#...
+ 0x70000000 \(DT_X86_64_PLT\)              0x1020
+ 0x70000001 \(DT_X86_64_PLTSZ\)            0x10
+ 0x70000003 \(DT_X86_64_PLTENT\)           0x10
+#...
+[0-9a-f ]+R_X86_64_JUMP_SLOT +0+ +bar \+ 1024
+#pass
diff --git a/ld/testsuite/ld-x86-64/mark-plt-1c.d b/ld/testsuite/ld-x86-64/mark-plt-1c.d
new file mode 100644
index 00000000000..e11e0b7a758
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/mark-plt-1c.d
@@ -0,0 +1,12 @@
+#source: mark-plt-1.s
+#as: --64
+#ld: -melf_x86_64 -shared -z mark-plt -z ibtplt
+#readelf: -drW
+
+#...
+ 0x0000000070000000 \(DT_X86_64_PLT\)      0x1020
+ 0x0000000070000001 \(DT_X86_64_PLTSZ\)    0x10
+ 0x0000000070000003 \(DT_X86_64_PLTENT\)   0x10
+#...
+[0-9a-f ]+R_X86_64_JUMP_SLOT +0+ +bar \+ 1024
+#pass
diff --git a/ld/testsuite/ld-x86-64/mark-plt-1d-x32.d b/ld/testsuite/ld-x86-64/mark-plt-1d-x32.d
new file mode 100644
index 00000000000..318ca1f0931
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/mark-plt-1d-x32.d
@@ -0,0 +1,16 @@
+#source: mark-plt-1.s
+#as: --x32
+#ld: -melf32_x86_64 -shared -z mark-plt -z ibtplt
+#objdump: -dw
+
+#...
+0+1020 <bar@plt>:
+ +1020:	f3 0f 1e fa          	endbr64
+ +1024:	ff 25 86 10 00 00    	jmp    \*0x1086\(%rip\)        # 20b0 <bar>
+ +102a:	66 0f 1f 44 00 00    	nopw   0x0\(%rax,%rax,1\)
+
+Disassembly of section .text:
+
+0+1030 <foo>:
+ +1030:	e8 eb ff ff ff       	call   1020 <bar@plt>
+#pass
diff --git a/ld/testsuite/ld-x86-64/mark-plt-1d.d b/ld/testsuite/ld-x86-64/mark-plt-1d.d
new file mode 100644
index 00000000000..2dd63bc10b7
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/mark-plt-1d.d
@@ -0,0 +1,16 @@
+#source: mark-plt-1.s
+#as: --64
+#ld: -melf_x86_64 -shared -z mark-plt -z ibtplt
+#objdump: -dw
+
+#...
+0+1020 <bar@plt>:
+ +1020:	f3 0f 1e fa          	endbr64
+ +1024:	ff 25 1e 11 00 00    	jmp    \*0x111e\(%rip\)        # 2148 <bar>
+ +102a:	66 0f 1f 44 00 00    	nopw   0x0\(%rax,%rax,1\)
+
+Disassembly of section .text:
+
+0+1030 <foo>:
+ +1030:	e8 eb ff ff ff       	call   1020 <bar@plt>
+#pass
diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp
index f94284b079c..3dc8cb47192 100644
--- a/ld/testsuite/ld-x86-64/x86-64.exp
+++ b/ld/testsuite/ld-x86-64/x86-64.exp
@@ -2228,5 +2228,13 @@ run_dump_test "ibt-plt-3a-x32"
 run_dump_test "ibt-plt-3b-x32"
 run_dump_test "ibt-plt-3c-x32"
 run_dump_test "ibt-plt-3d-x32"
+run_dump_test "mark-plt-1a"
+run_dump_test "mark-plt-1b"
+run_dump_test "mark-plt-1c"
+run_dump_test "mark-plt-1d"
+run_dump_test "mark-plt-1a-x32"
+run_dump_test "mark-plt-1b-x32"
+run_dump_test "mark-plt-1c-x32"
+run_dump_test "mark-plt-1d-x32"
 
 set ASFLAGS "$saved_ASFLAGS"
