This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCH] binutils-2_28-branch: x86-64: Correct unwind info for the BND PLT and .plt.bnd
- From: "H.J. Lu" <hongjiu dot lu at intel dot com>
- To: binutils at sourceware dot org
- Date: Fri, 13 Jan 2017 08:56:36 -0800
- Subject: [PATCH] binutils-2_28-branch: x86-64: Correct unwind info for the BND PLT and .plt.bnd
- Authentication-results: sourceware.org; auth=none
- Reply-to: "H.J. Lu" <hjl dot tools at gmail dot com>
I backported
>From 9e65917652e994b0864b344bfa47014155d93100 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Wed, 11 Jan 2017 09:16:44 -0800
Subject: [PATCH] x86-64: Correct unwind info for the BND PLT
and
rom 8361ed4d6b7049264153434e8dc15e6dc2200ebf Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Thu, 12 Jan 2017 10:30:56 -0800
Subject: [PATCH] x86-64: Also generate unwind info for .plt.bnd
to 2.28 branch.
H.J.
--
Since the BND PLT has
230: 68 00 00 00 00 pushq $0x0
235: f2 e9 e5 ff ff ff bnd jmpq 220 <.plt>
23b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
instead of
230: ff 25 e2 0d 20 00 jmpq *0x200de2(%rip) # 201018
<func>
236: 68 00 00 00 00 pushq $0x0
23b: e9 e0 ff ff ff jmpq 220 <.plt>
its unwind info should be
DW_CFA_def_cfa_expression (DW_OP_breg7 (rsp): 8; DW_OP_breg16 (rip): 0;
DW_OP_lit15; DW_OP_and; DW_OP_lit5; DW_OP_ge; DW_OP_lit3; DW_OP_shl;
DW_OP_plus)
Also generate unwind info for the .plt.bnd section. Sine it is the same
as unwind info for the .plt.got section, we use unwind info for the
.plt.got section to cover the the .plt.bnd section.
bfd/
2017-01-13 H.J. Lu <hongjiu.lu@intel.com>
Backport from master
2017-01-12 H.J. Lu <hongjiu.lu@intel.com>
PR ld/21038
* elf64-x86-64.c (elf_x86_64_link_hash_table): Add
plt_bnd_eh_frame.
(elf_x86_64_check_relocs): Create .eh_frame section for the
.plt.bnd section.
(elf_x86_64_size_dynamic_sections): Allocate and initialize
.eh_frame section for the .plt.bnd section.
(elf_x86_64_finish_dynamic_sections): Adjust .eh_frame section
for the .plt.bnd section.
2017-01-11 H.J. Lu <hongjiu.lu@intel.com>
PR ld/21038
* elf64-x86-64.c (elf_x86_64_eh_frame_bnd_plt): New.
(elf_x86_64_bnd_arch_bed): Use elf_x86_64_eh_frame_bnd_plt and
elf_x86_64_eh_frame_plt_got.
(elf_x86_64_size_dynamic_sections): Get unwind info from
elf_x86_64_bnd_arch_bed for the BND PLT.
ld/
2017-01-13 H.J. Lu <hongjiu.lu@intel.com>
Backport from master
2017-01-12 H.J. Lu <hongjiu.lu@intel.com>
PR ld/21038
* testsuite/ld-x86-64/pr21038b.d: Updated.
* testsuite/ld-x86-64/pr21038c.d: New file.
* testsuite/ld-x86-64/pr21038c.s: Likewise.
* testsuite/ld-x86-64/x86-64.exp: Run pr21038c.
2017-01-11 H.J. Lu <hongjiu.lu@intel.com>
PR ld/21038
* testsuite/ld-x86-64/pr21038a.d: New file.
* testsuite/ld-x86-64/pr21038a.s: Likewise.
* testsuite/ld-x86-64/pr21038b.d: Likewise.
* testsuite/ld-x86-64/pr21038b.s: Likewise.
* testsuite/ld-x86-64/x86-64.exp: Run pr21038a and pr21038b.
---
bfd/ChangeLog | 24 +++++++
bfd/elf64-x86-64.c | 143 ++++++++++++++++++++++++++++++--------
ld/ChangeLog | 20 ++++++
ld/testsuite/ld-x86-64/pr21038a.d | 71 +++++++++++++++++++
ld/testsuite/ld-x86-64/pr21038a.s | 8 +++
ld/testsuite/ld-x86-64/pr21038b.d | 73 +++++++++++++++++++
ld/testsuite/ld-x86-64/pr21038b.s | 7 ++
ld/testsuite/ld-x86-64/pr21038c.d | 90 ++++++++++++++++++++++++
ld/testsuite/ld-x86-64/pr21038c.s | 9 +++
ld/testsuite/ld-x86-64/x86-64.exp | 3 +
10 files changed, 420 insertions(+), 28 deletions(-)
create mode 100644 ld/testsuite/ld-x86-64/pr21038a.d
create mode 100644 ld/testsuite/ld-x86-64/pr21038a.s
create mode 100644 ld/testsuite/ld-x86-64/pr21038b.d
create mode 100644 ld/testsuite/ld-x86-64/pr21038b.s
create mode 100644 ld/testsuite/ld-x86-64/pr21038c.d
create mode 100644 ld/testsuite/ld-x86-64/pr21038c.s
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index f1fd51f..b3565ce 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,6 +1,30 @@
2017-01-13 H.J. Lu <hongjiu.lu@intel.com>
Backport from master
+ 2017-01-12 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR ld/21038
+ * elf64-x86-64.c (elf_x86_64_link_hash_table): Add
+ plt_bnd_eh_frame.
+ (elf_x86_64_check_relocs): Create .eh_frame section for the
+ .plt.bnd section.
+ (elf_x86_64_size_dynamic_sections): Allocate and initialize
+ .eh_frame section for the .plt.bnd section.
+ (elf_x86_64_finish_dynamic_sections): Adjust .eh_frame section
+ for the .plt.bnd section.
+
+ 2017-01-11 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR ld/21038
+ * elf64-x86-64.c (elf_x86_64_eh_frame_bnd_plt): New.
+ (elf_x86_64_bnd_arch_bed): Use elf_x86_64_eh_frame_bnd_plt and
+ elf_x86_64_eh_frame_plt_got.
+ (elf_x86_64_size_dynamic_sections): Get unwind info from
+ elf_x86_64_bnd_arch_bed for the BND PLT.
+
+2017-01-13 H.J. Lu <hongjiu.lu@intel.com>
+
+ Backport from master
2017-01-10 H.J. Lu <hongjiu.lu@intel.com>
* elf32-i386.c (elf_i386_check_relocs): Align .eh_frame section
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index 1edab04..a058eca 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -659,6 +659,41 @@ static const bfd_byte elf_x86_64_eh_frame_plt[] =
DW_CFA_nop, DW_CFA_nop, DW_CFA_nop, DW_CFA_nop
};
+/* .eh_frame covering the BND .plt section. */
+
+static const bfd_byte elf_x86_64_eh_frame_bnd_plt[] =
+{
+ PLT_CIE_LENGTH, 0, 0, 0, /* CIE length */
+ 0, 0, 0, 0, /* CIE ID */
+ 1, /* CIE version */
+ 'z', 'R', 0, /* Augmentation string */
+ 1, /* Code alignment factor */
+ 0x78, /* Data alignment factor */
+ 16, /* Return address column */
+ 1, /* Augmentation size */
+ DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding */
+ DW_CFA_def_cfa, 7, 8, /* DW_CFA_def_cfa: r7 (rsp) ofs 8 */
+ DW_CFA_offset + 16, 1, /* DW_CFA_offset: r16 (rip) at cfa-8 */
+ DW_CFA_nop, DW_CFA_nop,
+
+ PLT_FDE_LENGTH, 0, 0, 0, /* FDE length */
+ PLT_CIE_LENGTH + 8, 0, 0, 0, /* CIE pointer */
+ 0, 0, 0, 0, /* R_X86_64_PC32 .plt goes here */
+ 0, 0, 0, 0, /* .plt size goes here */
+ 0, /* Augmentation size */
+ DW_CFA_def_cfa_offset, 16, /* DW_CFA_def_cfa_offset: 16 */
+ DW_CFA_advance_loc + 6, /* DW_CFA_advance_loc: 6 to __PLT__+6 */
+ DW_CFA_def_cfa_offset, 24, /* DW_CFA_def_cfa_offset: 24 */
+ DW_CFA_advance_loc + 10, /* DW_CFA_advance_loc: 10 to __PLT__+16 */
+ DW_CFA_def_cfa_expression, /* DW_CFA_def_cfa_expression */
+ 11, /* Block length */
+ DW_OP_breg7, 8, /* DW_OP_breg7 (rsp): 8 */
+ DW_OP_breg16, 0, /* DW_OP_breg16 (rip): 0 */
+ DW_OP_lit15, DW_OP_and, DW_OP_lit5, DW_OP_ge,
+ DW_OP_lit3, DW_OP_shl, DW_OP_plus,
+ DW_CFA_nop, DW_CFA_nop, DW_CFA_nop, DW_CFA_nop
+};
+
/* .eh_frame covering the .plt.got section. */
static const bfd_byte elf_x86_64_eh_frame_plt_got[] =
@@ -770,11 +805,10 @@ static const struct elf_x86_64_backend_data elf_x86_64_bnd_arch_bed =
1+6, /* plt_got_insn_size */
11, /* plt_plt_insn_end */
0, /* plt_lazy_offset */
- elf_x86_64_eh_frame_plt, /* eh_frame_plt */
- sizeof (elf_x86_64_eh_frame_plt), /* eh_frame_plt_size */
- /* FIXME: Needs .eh_frame coverage. */
- NULL, /* eh_frame_plt_got */
- 0, /* eh_frame_plt_got_size */
+ elf_x86_64_eh_frame_bnd_plt, /* eh_frame_plt */
+ sizeof (elf_x86_64_eh_frame_bnd_plt), /* eh_frame_plt_size */
+ elf_x86_64_eh_frame_plt_got, /* eh_frame_plt_got */
+ sizeof (elf_x86_64_eh_frame_plt_got), /* eh_frame_plt_got_size */
};
#define elf_backend_arch_data &elf_x86_64_arch_bed
@@ -900,6 +934,7 @@ struct elf_x86_64_link_hash_table
asection *interp;
asection *plt_eh_frame;
asection *plt_bnd;
+ asection *plt_bnd_eh_frame;
asection *plt_got;
asection *plt_got_eh_frame;
@@ -2309,23 +2344,21 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
/* MPX PLT is supported only if elf_x86_64_arch_bed
is used in 64-bit mode. */
if (ABI_64_P (abfd)
- && info->bndplt
- && (get_elf_x86_64_backend_data (abfd)
- == &elf_x86_64_arch_bed))
+ && info->bndplt
+ && (get_elf_x86_64_backend_data (abfd)
+ == &elf_x86_64_arch_bed))
{
elf_x86_64_hash_entry (h)->has_bnd_reloc = 1;
/* Create the second PLT for Intel MPX support. */
if (htab->plt_bnd == NULL)
{
- unsigned int plt_bnd_align;
const struct elf_backend_data *bed;
bed = get_elf_backend_data (info->output_bfd);
BFD_ASSERT (sizeof (elf_x86_64_bnd_plt2_entry) == 8
&& (sizeof (elf_x86_64_bnd_plt2_entry)
== sizeof (elf_x86_64_legacy_plt2_entry)));
- plt_bnd_align = 3;
if (htab->elf.dynobj == NULL)
htab->elf.dynobj = abfd;
@@ -2340,7 +2373,24 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
if (htab->plt_bnd == NULL
|| !bfd_set_section_alignment (htab->elf.dynobj,
htab->plt_bnd,
- plt_bnd_align))
+ 3))
+ goto error_return;
+ }
+
+ if (!info->no_ld_generated_unwind_info
+ && htab->plt_bnd_eh_frame == NULL)
+ {
+ flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
+ | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED);
+ htab->plt_bnd_eh_frame
+ = bfd_make_section_anyway_with_flags (htab->elf.dynobj,
+ ".eh_frame",
+ flags);
+ if (htab->plt_bnd_eh_frame == NULL
+ || !bfd_set_section_alignment (htab->elf.dynobj,
+ htab->plt_bnd_eh_frame,
+ 3))
goto error_return;
}
}
@@ -3653,6 +3703,7 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
bfd_boolean relocs;
bfd *ibfd;
const struct elf_backend_data *bed;
+ const struct elf_x86_64_backend_data *arch_data;
htab = elf_x86_64_hash_table (info);
if (htab == NULL)
@@ -3844,28 +3895,31 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
htab->elf.sgotplt->size = 0;
}
+ arch_data = (htab->plt_bnd != NULL
+ ? &elf_x86_64_bnd_arch_bed
+ : get_elf_x86_64_arch_data (bed));
+
if (_bfd_elf_eh_frame_present (info))
{
if (htab->plt_eh_frame != NULL
&& htab->elf.splt != NULL
&& htab->elf.splt->size != 0
&& !bfd_is_abs_section (htab->elf.splt->output_section))
- {
- const struct elf_x86_64_backend_data *arch_data
- = get_elf_x86_64_arch_data (bed);
- htab->plt_eh_frame->size = arch_data->eh_frame_plt_size;
- }
+ htab->plt_eh_frame->size = arch_data->eh_frame_plt_size;
if (htab->plt_got_eh_frame != NULL
&& htab->plt_got != NULL
&& htab->plt_got->size != 0
&& !bfd_is_abs_section (htab->plt_got->output_section))
- {
- const struct elf_x86_64_backend_data *arch_data
- = get_elf_x86_64_arch_data (bed);
- htab->plt_got_eh_frame->size
- = arch_data->eh_frame_plt_got_size;
- }
+ htab->plt_got_eh_frame->size = arch_data->eh_frame_plt_got_size;
+
+ /* Unwind info for .plt.bnd and .plt.got sections are
+ identical. */
+ if (htab->plt_bnd_eh_frame != NULL
+ && htab->plt_bnd != NULL
+ && htab->plt_bnd->size != 0
+ && !bfd_is_abs_section (htab->plt_bnd->output_section))
+ htab->plt_bnd_eh_frame->size = arch_data->eh_frame_plt_got_size;
}
/* We now have determined the sizes of the various dynamic sections.
@@ -3885,6 +3939,7 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
|| s == htab->plt_got
|| s == htab->plt_eh_frame
|| s == htab->plt_got_eh_frame
+ || s == htab->plt_bnd_eh_frame
|| s == htab->elf.sdynbss
|| s == htab->elf.sdynrelro)
{
@@ -3939,9 +3994,6 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
if (htab->plt_eh_frame != NULL
&& htab->plt_eh_frame->contents != NULL)
{
- const struct elf_x86_64_backend_data *arch_data
- = get_elf_x86_64_arch_data (bed);
-
memcpy (htab->plt_eh_frame->contents,
arch_data->eh_frame_plt, htab->plt_eh_frame->size);
bfd_put_32 (dynobj, htab->elf.splt->size,
@@ -3951,9 +4003,6 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
if (htab->plt_got_eh_frame != NULL
&& htab->plt_got_eh_frame->contents != NULL)
{
- const struct elf_x86_64_backend_data *arch_data
- = get_elf_x86_64_arch_data (bed);
-
memcpy (htab->plt_got_eh_frame->contents,
arch_data->eh_frame_plt_got,
htab->plt_got_eh_frame->size);
@@ -3962,6 +4011,17 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
+ PLT_FDE_LEN_OFFSET));
}
+ if (htab->plt_bnd_eh_frame != NULL
+ && htab->plt_bnd_eh_frame->contents != NULL)
+ {
+ memcpy (htab->plt_bnd_eh_frame->contents,
+ arch_data->eh_frame_plt_got,
+ htab->plt_bnd_eh_frame->size);
+ bfd_put_32 (dynobj, htab->plt_bnd->size,
+ (htab->plt_bnd_eh_frame->contents
+ + PLT_FDE_LEN_OFFSET));
+ }
+
if (htab->elf.dynamic_sections_created)
{
/* Add some entries to the .dynamic section. We fill in the
@@ -6454,6 +6514,33 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd,
}
}
+ /* Adjust .eh_frame for .plt.bnd section. */
+ if (htab->plt_bnd_eh_frame != NULL
+ && htab->plt_bnd_eh_frame->contents != NULL)
+ {
+ if (htab->plt_bnd != NULL
+ && htab->plt_bnd->size != 0
+ && (htab->plt_bnd->flags & SEC_EXCLUDE) == 0
+ && htab->plt_bnd->output_section != NULL
+ && htab->plt_bnd_eh_frame->output_section != NULL)
+ {
+ bfd_vma plt_start = htab->plt_bnd->output_section->vma;
+ bfd_vma eh_frame_start = htab->plt_bnd_eh_frame->output_section->vma
+ + htab->plt_bnd_eh_frame->output_offset
+ + PLT_FDE_START_OFFSET;
+ bfd_put_signed_32 (dynobj, plt_start - eh_frame_start,
+ htab->plt_bnd_eh_frame->contents
+ + PLT_FDE_START_OFFSET);
+ }
+ if (htab->plt_bnd_eh_frame->sec_info_type == SEC_INFO_TYPE_EH_FRAME)
+ {
+ if (! _bfd_elf_write_section_eh_frame (output_bfd, info,
+ htab->plt_bnd_eh_frame,
+ htab->plt_bnd_eh_frame->contents))
+ return FALSE;
+ }
+ }
+
if (htab->elf.sgot && htab->elf.sgot->size > 0)
elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize
= GOT_ENTRY_SIZE;
diff --git a/ld/ChangeLog b/ld/ChangeLog
index 03562de..d08b8e0 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,6 +1,26 @@
2017-01-13 H.J. Lu <hongjiu.lu@intel.com>
Backport from master
+ 2017-01-12 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR ld/21038
+ * testsuite/ld-x86-64/pr21038b.d: Updated.
+ * testsuite/ld-x86-64/pr21038c.d: New file.
+ * testsuite/ld-x86-64/pr21038c.s: Likewise.
+ * testsuite/ld-x86-64/x86-64.exp: Run pr21038c.
+
+ 2017-01-11 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR ld/21038
+ * testsuite/ld-x86-64/pr21038a.d: New file.
+ * testsuite/ld-x86-64/pr21038a.s: Likewise.
+ * testsuite/ld-x86-64/pr21038b.d: Likewise.
+ * testsuite/ld-x86-64/pr21038b.s: Likewise.
+ * testsuite/ld-x86-64/x86-64.exp: Run pr21038a and pr21038b.
+
+2017-01-13 H.J. Lu <hongjiu.lu@intel.com>
+
+ Backport from master
2017-01-10 H.J. Lu <hongjiu.lu@intel.com>
* testsuite/ld-x86-64/pr20830b.d: Updated.
diff --git a/ld/testsuite/ld-x86-64/pr21038a.d b/ld/testsuite/ld-x86-64/pr21038a.d
new file mode 100644
index 0000000..f2f88eb
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr21038a.d
@@ -0,0 +1,71 @@
+#name: PR ld/21038 (.plt.got)
+#as: --64
+#ld: -z bndplt -melf_x86_64 -shared -z relro --ld-generated-unwind-info
+#objdump: -dw -Wf
+
+.*: +file format .*
+
+Contents of the .eh_frame section:
+
+0+ 0000000000000014 00000000 CIE
+ Version: 1
+ Augmentation: "zR"
+ Code alignment factor: 1
+ Data alignment factor: -8
+ Return address column: 16
+ Augmentation data: 1b
+
+ DW_CFA_def_cfa: r7 \(rsp\) ofs 8
+ DW_CFA_offset: r16 \(rip\) at cfa-8
+ DW_CFA_nop
+ DW_CFA_nop
+
+0+18 0000000000000014 0000001c FDE cie=00000000 pc=0000000000000238..0000000000000244
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+
+0+30 0000000000000024 00000034 FDE cie=00000000 pc=0000000000000220..0000000000000230
+ DW_CFA_def_cfa_offset: 16
+ DW_CFA_advance_loc: 6 to 0000000000000226
+ DW_CFA_def_cfa_offset: 24
+ DW_CFA_advance_loc: 10 to 0000000000000230
+ DW_CFA_def_cfa_expression \(DW_OP_breg7 \(rsp\): 8; DW_OP_breg16 \(rip\): 0; DW_OP_lit15; DW_OP_and; DW_OP_lit5; DW_OP_ge; DW_OP_lit3; DW_OP_shl; DW_OP_plus\)
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+
+0+58 0000000000000014 0000005c FDE cie=00000000 pc=0000000000000230..0000000000000238
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+
+
+Disassembly of section .plt:
+
+0+220 <.plt>:
+ +[a-f0-9]+: ff 35 e2 0d 20 00 pushq 0x200de2\(%rip\) # 201008 <_GLOBAL_OFFSET_TABLE_\+0x8>
+ +[a-f0-9]+: f2 ff 25 e3 0d 20 00 bnd jmpq \*0x200de3\(%rip\) # 201010 <_GLOBAL_OFFSET_TABLE_\+0x10>
+ +[a-f0-9]+: 0f 1f 00 nopl \(%rax\)
+
+Disassembly of section .plt.got:
+
+0+230 <.plt.got>:
+ +[a-f0-9]+: f2 ff 25 c1 0d 20 00 bnd jmpq \*0x200dc1\(%rip\) # 200ff8 <func>
+ +[a-f0-9]+: 90 nop
+
+Disassembly of section .text:
+
+0+238 <foo>:
+ +[a-f0-9]+: e8 f3 ff ff ff callq 230 <.plt.got>
+ +[a-f0-9]+: 48 8b 05 b4 0d 20 00 mov 0x200db4\(%rip\),%rax # 200ff8 <func>
+#pass
diff --git a/ld/testsuite/ld-x86-64/pr21038a.s b/ld/testsuite/ld-x86-64/pr21038a.s
new file mode 100644
index 0000000..d9a1b4c
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr21038a.s
@@ -0,0 +1,8 @@
+ .text
+ .globl foo
+ .type foo, @function
+foo:
+ .cfi_startproc
+ call func@plt
+ movq func@GOTPCREL(%rip), %rax
+ .cfi_endproc
diff --git a/ld/testsuite/ld-x86-64/pr21038b.d b/ld/testsuite/ld-x86-64/pr21038b.d
new file mode 100644
index 0000000..053d908
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr21038b.d
@@ -0,0 +1,73 @@
+#name: PR ld/21038 (.plt.bnd)
+#as: --64
+#ld: -z bndplt -melf_x86_64 -shared -z relro --ld-generated-unwind-info
+#objdump: -dw -Wf
+
+.*: +file format .*
+
+Contents of the .eh_frame section:
+
+0+ 0000000000000014 00000000 CIE
+ Version: 1
+ Augmentation: "zR"
+ Code alignment factor: 1
+ Data alignment factor: -8
+ Return address column: 16
+ Augmentation data: 1b
+
+ DW_CFA_def_cfa: r7 \(rsp\) ofs 8
+ DW_CFA_offset: r16 \(rip\) at cfa-8
+ DW_CFA_nop
+ DW_CFA_nop
+
+0+18 0000000000000014 0000001c FDE cie=00000000 pc=0000000000000248..000000000000024d
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+
+0+30 0000000000000024 00000034 FDE cie=00000000 pc=0000000000000220..0000000000000240
+ DW_CFA_def_cfa_offset: 16
+ DW_CFA_advance_loc: 6 to 0000000000000226
+ DW_CFA_def_cfa_offset: 24
+ DW_CFA_advance_loc: 10 to 0000000000000230
+ DW_CFA_def_cfa_expression \(DW_OP_breg7 \(rsp\): 8; DW_OP_breg16 \(rip\): 0; DW_OP_lit15; DW_OP_and; DW_OP_lit5; DW_OP_ge; DW_OP_lit3; DW_OP_shl; DW_OP_plus\)
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+
+0+58 0000000000000014 0000005c FDE cie=00000000 pc=0000000000000240..0000000000000248
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+
+
+Disassembly of section .plt:
+
+0+220 <.plt>:
+ +[a-f0-9]+: ff 35 e2 0d 20 00 pushq 0x200de2\(%rip\) # 201008 <_GLOBAL_OFFSET_TABLE_\+0x8>
+ +[a-f0-9]+: f2 ff 25 e3 0d 20 00 bnd jmpq \*0x200de3\(%rip\) # 201010 <_GLOBAL_OFFSET_TABLE_\+0x10>
+ +[a-f0-9]+: 0f 1f 00 nopl \(%rax\)
+ +[a-f0-9]+: 68 00 00 00 00 pushq \$0x0
+ +[a-f0-9]+: f2 e9 e5 ff ff ff bnd jmpq 220 <.plt>
+ +[a-f0-9]+: 0f 1f 44 00 00 nopl 0x0\(%rax,%rax,1\)
+
+Disassembly of section .plt.bnd:
+
+0+240 <func@plt>:
+ +[a-f0-9]+: f2 ff 25 d1 0d 20 00 bnd jmpq \*0x200dd1\(%rip\) # 201018 <func>
+ +[a-f0-9]+: 90 nop
+
+Disassembly of section .text:
+
+0+248 <foo>:
+ +[a-f0-9]+: e8 f3 ff ff ff callq 240 <func@plt>
+#pass
diff --git a/ld/testsuite/ld-x86-64/pr21038b.s b/ld/testsuite/ld-x86-64/pr21038b.s
new file mode 100644
index 0000000..3a8fc47
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr21038b.s
@@ -0,0 +1,7 @@
+ .text
+ .globl foo
+ .type foo, @function
+foo:
+ .cfi_startproc
+ call func@plt
+ .cfi_endproc
diff --git a/ld/testsuite/ld-x86-64/pr21038c.d b/ld/testsuite/ld-x86-64/pr21038c.d
new file mode 100644
index 0000000..33ff4ed
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr21038c.d
@@ -0,0 +1,90 @@
+#name: PR ld/21038 (.plt.got and .plt.bnd)
+#as: --64
+#ld: -z bndplt -melf_x86_64 -shared -z relro --ld-generated-unwind-info
+#objdump: -dw -Wf
+
+.*: +file format .*
+
+Contents of the .eh_frame section:
+
+0+ 0000000000000014 00000000 CIE
+ Version: 1
+ Augmentation: "zR"
+ Code alignment factor: 1
+ Data alignment factor: -8
+ Return address column: 16
+ Augmentation data: 1b
+
+ DW_CFA_def_cfa: r7 \(rsp\) ofs 8
+ DW_CFA_offset: r16 \(rip\) at cfa-8
+ DW_CFA_nop
+ DW_CFA_nop
+
+0+18 0000000000000014 0000001c FDE cie=00000000 pc=0000000000000290..00000000000002a1
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+
+0+30 0000000000000024 00000034 FDE cie=00000000 pc=0000000000000260..0000000000000280
+ DW_CFA_def_cfa_offset: 16
+ DW_CFA_advance_loc: 6 to 0000000000000266
+ DW_CFA_def_cfa_offset: 24
+ DW_CFA_advance_loc: 10 to 0000000000000270
+ DW_CFA_def_cfa_expression \(DW_OP_breg7 \(rsp\): 8; DW_OP_breg16 \(rip\): 0; DW_OP_lit15; DW_OP_and; DW_OP_lit5; DW_OP_ge; DW_OP_lit3; DW_OP_shl; DW_OP_plus\)
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+
+0+58 0000000000000014 0000005c FDE cie=00000000 pc=0000000000000288..0000000000000290
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+
+0+70 0000000000000014 00000074 FDE cie=00000000 pc=0000000000000280..0000000000000288
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+
+
+Disassembly of section .plt:
+
+0+260 <.plt>:
+ +[a-f0-9]+: ff 35 a2 0d 20 00 pushq 0x200da2\(%rip\) # 201008 <_GLOBAL_OFFSET_TABLE_\+0x8>
+ +[a-f0-9]+: f2 ff 25 a3 0d 20 00 bnd jmpq \*0x200da3\(%rip\) # 201010 <_GLOBAL_OFFSET_TABLE_\+0x10>
+ +[a-f0-9]+: 0f 1f 00 nopl \(%rax\)
+ +[a-f0-9]+: 68 00 00 00 00 pushq \$0x0
+ +[a-f0-9]+: f2 e9 e5 ff ff ff bnd jmpq 260 <.plt>
+ +[a-f0-9]+: 0f 1f 44 00 00 nopl 0x0\(%rax,%rax,1\)
+
+Disassembly of section .plt.got:
+
+0+280 <.plt.got>:
+ +[a-f0-9]+: f2 ff 25 71 0d 20 00 bnd jmpq \*0x200d71\(%rip\) # 200ff8 <func1>
+ +[a-f0-9]+: 90 nop
+
+Disassembly of section .plt.bnd:
+
+0+288 <func2@plt>:
+ +[a-f0-9]+: f2 ff 25 89 0d 20 00 bnd jmpq \*0x200d89\(%rip\) # 201018 <func2>
+ +[a-f0-9]+: 90 nop
+
+Disassembly of section .text:
+
+0+290 <foo>:
+ +[a-f0-9]+: e8 eb ff ff ff callq 280 <.plt.got>
+ +[a-f0-9]+: e8 ee ff ff ff callq 288 <func2@plt>
+ +[a-f0-9]+: 48 8b 05 57 0d 20 00 mov 0x200d57\(%rip\),%rax # 200ff8 <func1>
+#pass
diff --git a/ld/testsuite/ld-x86-64/pr21038c.s b/ld/testsuite/ld-x86-64/pr21038c.s
new file mode 100644
index 0000000..38fc10d
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr21038c.s
@@ -0,0 +1,9 @@
+ .text
+ .globl foo
+ .type foo, @function
+foo:
+ .cfi_startproc
+ call func1@plt
+ call func2@plt
+ movq func1@GOTPCREL(%rip), %rax
+ .cfi_endproc
diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp
index 3a7ba38..ce8e838 100644
--- a/ld/testsuite/ld-x86-64/x86-64.exp
+++ b/ld/testsuite/ld-x86-64/x86-64.exp
@@ -1019,3 +1019,6 @@ run_dump_test "pltgot-1"
run_dump_test "pltgot-2"
run_dump_test "pr20830a"
run_dump_test "pr20830b"
+run_dump_test "pr21038a"
+run_dump_test "pr21038b"
+run_dump_test "pr21038c"
--
2.9.3