From: Indu Bhagat Date: Fri, 25 Oct 2024 14:33:21 -0700 To: jpoimboe@kernel.org Cc: Indu Bhagat Subject: [PATCH 3/3] ld: generate SFrame stack trace info for .plt.got X-Mailer: git-send-email 2.43.0 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset=utf-8 PR/32298 sframe: no SFrame stack trace info generated for .plt.got Add support to generate SFrame stack trace info for .plt.got section. Enhance the current definition of struct elf_x86_sframe_plt to include initialized SFrame FDE/FREs applicable for .plt.got section. There are two variants of .plt.got entries: 16 byte and 8 byte. 8 byte: ff 25 00 00 00 00 jmpq *name@GOTPCREL(%rip) 66 90 xchg %ax,%ax 16 byte: f3 0f 1e fa endbr64 ff 25 66 2f 00 00 jmpq *name@GOTPCREL(%rip) 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1) For the testcase, define some application symbols such that their PLT entry is placed in .plt.got and ensure SFrame information is generated with and without -z ibtplt. ChangeLog: PR/32298 * bfd/elf64-x86-64.c (elf_x86_64_link_setup_gnu_properties): PLT GOT entry size is different for IBT vs non IBT PLTs. * bfd/elfxx-x86.c (enum dynobj_sframe_plt_type): New enum for SFRAME_PLT_GOT. (_bfd_x86_elf_create_sframe_plt): Handle SFRAME_PLT_GOT. (_bfd_x86_elf_write_sframe_plt): Likewise. (_bfd_x86_elf_late_size_sections): Likewise. (_bfd_x86_elf_finish_dynamic_sections): Likewise. * bfd/elfxx-x86.h (struct elf_x86_sframe_plt): Add new members to keep information about PLT GOT entries. (struct elf_x86_link_hash_table): Add support for creating SFrame section for .plt.got. * ld/testsuite/ld-x86-64/x86-64.exp: Add new tests. * ld/testsuite/ld-x86-64/sframe-pltgot-1.d: New test. * ld/testsuite/ld-x86-64/sframe-pltgot-1.s: New test. * ld/testsuite/ld-x86-64/sframe-pltgot-2.d: New test. --- bfd/elf64-x86-64.c | 42 ++++++++++-- bfd/elfxx-x86.c | 86 ++++++++++++++++++++++-- bfd/elfxx-x86.h | 6 ++ ld/testsuite/ld-x86-64/sframe-pltgot-1.d | 28 ++++++++ ld/testsuite/ld-x86-64/sframe-pltgot-1.s | 15 +++++ ld/testsuite/ld-x86-64/sframe-pltgot-2.d | 28 ++++++++ ld/testsuite/ld-x86-64/x86-64.exp | 2 + 7 files changed, 198 insertions(+), 9 deletions(-) create mode 100644 ld/testsuite/ld-x86-64/sframe-pltgot-1.d create mode 100644 ld/testsuite/ld-x86-64/sframe-pltgot-1.s create mode 100644 ld/testsuite/ld-x86-64/sframe-pltgot-2.d diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index abbebbe92b4..a62fa621f99 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -922,7 +922,7 @@ static const sframe_frame_row_entry elf_x86_64_sframe_sec_pltn_fre1 = SFRAME_V1_FRE_INFO (SFRAME_BASE_REG_SP, 1, SFRAME_FRE_OFFSET_1B) /* FRE info. */ }; -/* SFrame helper object for non-lazy PLT. Also used for IBT enabled PLT. */ +/* SFrame helper object for non-lazy PLT. */ static const struct elf_x86_sframe_plt elf_x86_64_sframe_non_lazy_plt = { LAZY_PLT_ENTRY_SIZE, @@ -935,7 +935,31 @@ static const struct elf_x86_sframe_plt elf_x86_64_sframe_non_lazy_plt = { &elf_x86_64_sframe_sec_pltn_fre1, &elf_x86_64_sframe_null_fre }, 0, 0, /* There is no second PLT necessary. */ - { &elf_x86_64_sframe_null_fre } + { &elf_x86_64_sframe_null_fre }, + NON_LAZY_PLT_ENTRY_SIZE, + 1, /* Number of FREs for PLT GOT. */ + /* Array of SFrame FREs for PLT GOT. */ + { &elf_x86_64_sframe_null_fre }, +}; + +/* SFrame helper object for non-lazy IBT enabled PLT. */ +static const struct elf_x86_sframe_plt elf_x86_64_sframe_non_lazy_ibt_plt = +{ + LAZY_PLT_ENTRY_SIZE, + 2, /* Number of FREs for PLT0. */ + /* Array of SFrame FREs for plt0. */ + { &elf_x86_64_sframe_plt0_fre1, &elf_x86_64_sframe_plt0_fre2 }, + LAZY_PLT_ENTRY_SIZE, + 1, /* Number of FREs for PLTn. */ + /* Array of SFrame FREs for plt. */ + { &elf_x86_64_sframe_sec_pltn_fre1, &elf_x86_64_sframe_null_fre }, + 0, + 0, /* There is no second PLT necessary. */ + { &elf_x86_64_sframe_null_fre }, + LAZY_PLT_ENTRY_SIZE, + 1, /* Number of FREs for PLT GOT. */ + /* Array of SFrame FREs for PLT GOT. */ + { &elf_x86_64_sframe_null_fre }, }; /* SFrame helper object for lazy PLT. */ @@ -952,7 +976,11 @@ static const struct elf_x86_sframe_plt elf_x86_64_sframe_plt = NON_LAZY_PLT_ENTRY_SIZE, 1, /* Number of FREs for second PLT. */ /* Array of SFrame FREs for second PLT. */ - { &elf_x86_64_sframe_sec_pltn_fre1 } + { &elf_x86_64_sframe_sec_pltn_fre1 }, + NON_LAZY_PLT_ENTRY_SIZE, + 1, /* Number of FREs for PLT GOT. */ + /* Array of SFrame FREs for PLT GOT. */ + { &elf_x86_64_sframe_null_fre }, }; /* SFrame helper object for lazy PLT with IBT. */ @@ -969,7 +997,11 @@ static const struct elf_x86_sframe_plt elf_x86_64_sframe_ibt_plt = LAZY_PLT_ENTRY_SIZE, 1, /* Number of FREs for second PLT. */ /* Array of SFrame FREs for second plt. */ - { &elf_x86_64_sframe_sec_pltn_fre1 } + { &elf_x86_64_sframe_sec_pltn_fre1 }, + LAZY_PLT_ENTRY_SIZE, + 1, /* Number of FREs for PLT GOT. */ + /* Array of SFrame FREs for PLT GOT. */ + { &elf_x86_64_sframe_null_fre }, }; /* These are the standard parameters. */ @@ -5703,7 +5735,7 @@ elf_x86_64_link_setup_gnu_properties (struct bfd_link_info *info) init_table.sframe_lazy_plt = &elf_x86_64_sframe_plt; init_table.sframe_non_lazy_plt = &elf_x86_64_sframe_non_lazy_plt; init_table.sframe_lazy_ibt_plt = &elf_x86_64_sframe_ibt_plt; - init_table.sframe_non_lazy_ibt_plt = &elf_x86_64_sframe_non_lazy_plt; + init_table.sframe_non_lazy_ibt_plt = &elf_x86_64_sframe_non_lazy_ibt_plt; } else { diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c index cb90f688b6f..0843803171b 100644 --- a/bfd/elfxx-x86.c +++ b/bfd/elfxx-x86.c @@ -1817,7 +1817,8 @@ elf_x86_relative_reloc_compare (const void *pa, const void *pb) enum dynobj_sframe_plt_type { SFRAME_PLT = 1, - SFRAME_PLT_SEC = 2 + SFRAME_PLT_SEC = 2, + SFRAME_PLT_GOT = 3, }; /* Create SFrame stack trace info for the plt entries in the .plt section @@ -1880,6 +1881,21 @@ _bfd_x86_elf_create_sframe_plt (bfd *output_bfd, break; } + case SFRAME_PLT_GOT: + { + ectx = &htab->plt_got_cfe_ctx; + dpltsec = htab->plt_got; + + plt0_entry_size = 0; + + plt_entry_size = htab->sframe_plt->plt_got_entry_size; + pltn_fres = htab->sframe_plt->plt_got_fres; + num_pltn_fres = htab->sframe_plt->plt_got_num_fres; + num_pltn_entries = dpltsec->size / plt_entry_size; + + break; + } + default: /* No other value is possible. */ return false; @@ -1984,6 +2000,10 @@ _bfd_x86_elf_write_sframe_plt (bfd *output_bfd, ectx = htab->plt_second_cfe_ctx; sec = htab->plt_second_sframe; break; + case SFRAME_PLT_GOT: + ectx = htab->plt_got_cfe_ctx; + sec = htab->plt_got_sframe; + break; default: /* No other value is possible. */ return false; @@ -2511,7 +2531,18 @@ _bfd_x86_elf_late_size_sections (bfd *output_bfd, htab->plt_sframe->size = sizeof (sframe_header) + 1; } - /* FIXME - generate for .plt.got ? */ + if (htab->plt_got_sframe != NULL + && htab->plt_got != NULL + && htab->plt_got->size != 0 + && !bfd_is_abs_section (htab->plt_got->output_section)) + { + _bfd_x86_elf_create_sframe_plt (output_bfd, info, SFRAME_PLT_GOT); + /* FIXME - Dirty Hack. Set the size to something non-zero for now, + so that the section does not get stripped out below. The precise + size of this section is known only when the contents are + serialized in _bfd_x86_elf_write_sframe_plt. */ + htab->plt_got_sframe->size = sizeof (sframe_header) + 1; + } if (htab->plt_second_sframe != NULL && htab->plt_second != NULL @@ -2578,6 +2609,7 @@ _bfd_x86_elf_late_size_sections (bfd *output_bfd, || s == htab->plt_second_eh_frame || s == htab->plt_sframe || s == htab->plt_second_sframe + || s == htab->plt_got_sframe || s == htab->elf.sdynbss || s == htab->elf.sdynrelro) { @@ -2622,7 +2654,8 @@ _bfd_x86_elf_late_size_sections (bfd *output_bfd, /* Skip allocating contents for .sframe section as it is written out differently. See below. */ - if ((s == htab->plt_sframe) || (s == htab->plt_second_sframe)) + if ((s == htab->plt_sframe) || (s == htab->plt_second_sframe) + || (s == htab->plt_got_sframe)) continue; /* NB: Initially, the iplt section has minimal alignment to @@ -2687,6 +2720,12 @@ _bfd_x86_elf_late_size_sections (bfd *output_bfd, && htab->plt_second->size != 0 && htab->plt_second_sframe->contents == NULL) _bfd_x86_elf_write_sframe_plt (output_bfd, info, SFRAME_PLT_SEC); + + if (htab->plt_got_sframe != NULL + && htab->plt_got != NULL + && htab->plt_got->size != 0 + && htab->plt_got_sframe->contents == NULL) + _bfd_x86_elf_write_sframe_plt (output_bfd, info, SFRAME_PLT_GOT); } if (resolved_plt != NULL @@ -2997,6 +3036,34 @@ _bfd_x86_elf_finish_dynamic_sections (bfd *output_bfd, return NULL; } } + + if (htab->plt_got_sframe != NULL + && htab->plt_got_sframe->contents != NULL) + { + if (htab->plt_got != NULL + && htab->plt_got->size != 0 + && (htab->plt_got->flags & SEC_EXCLUDE) == 0 + && htab->plt_got->output_section != NULL + && htab->plt_got_sframe->output_section != NULL) + { + bfd_vma plt_start = htab->plt_got->output_section->vma; + bfd_vma sframe_start + = (htab->plt_got_sframe->output_section->vma + + htab->plt_got_sframe->output_offset + + PLT_SFRAME_FDE_START_OFFSET); + bfd_put_signed_32 (dynobj, plt_start - sframe_start, + htab->plt_got_sframe->contents + + PLT_SFRAME_FDE_START_OFFSET); + } + if (htab->plt_got_sframe->sec_info_type == SEC_INFO_TYPE_SFRAME) + { + if (! _bfd_elf_merge_section_sframe (output_bfd, info, + htab->plt_got_sframe, + htab->plt_got_sframe->contents)) + return NULL; + } + } + if (htab->elf.sgot && htab->elf.sgot->size > 0) elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize = htab->got_entry_size; @@ -4764,7 +4831,18 @@ _bfd_x86_elf_link_setup_gnu_properties htab->plt_second_sframe = sec; } - /* FIXME - add later for plt_got. */ + + /* .plt.got. */ + if (htab->plt_got != NULL) + { + sec = bfd_make_section_anyway_with_flags (dynobj, + ".sframe", + flags); + if (sec == NULL) + info->callbacks->einfo (_("%F%P: failed to create PLT GOT .sframe section\n")); + + htab->plt_got_sframe = sec; + } } } diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h index b042d45c282..cd26e8fc6f2 100644 --- a/bfd/elfxx-x86.h +++ b/bfd/elfxx-x86.h @@ -401,6 +401,10 @@ struct elf_x86_sframe_plt unsigned int sec_pltn_entry_size; unsigned int sec_pltn_num_fres; const sframe_frame_row_entry *sec_pltn_fres[SFRAME_PLTN_MAX_NUM_FRES]; + + unsigned int plt_got_entry_size; + unsigned int plt_got_num_fres; + const sframe_frame_row_entry *plt_got_fres[SFRAME_PLTN_MAX_NUM_FRES]; }; struct elf_x86_lazy_plt_layout @@ -606,6 +610,8 @@ struct elf_x86_link_hash_table asection *plt_sframe; sframe_encoder_ctx *plt_second_cfe_ctx; asection *plt_second_sframe; + sframe_encoder_ctx *plt_got_cfe_ctx; + asection *plt_got_sframe; /* Parameters describing PLT generation, lazy or non-lazy. */ struct elf_x86_plt_layout plt; diff --git a/ld/testsuite/ld-x86-64/sframe-pltgot-1.d b/ld/testsuite/ld-x86-64/sframe-pltgot-1.d new file mode 100644 index 00000000000..e26a741b635 --- /dev/null +++ b/ld/testsuite/ld-x86-64/sframe-pltgot-1.d @@ -0,0 +1,28 @@ +#as: --gsframe +#source: sframe-pltgot-1.s +#objdump: --sframe=.sframe +#ld: -shared -z ibtplt --no-rosegment +#name: SFrame for .plt.got + +.*: +file format .* + +Contents of the SFrame section .sframe: + Header : + + Version: SFRAME_VERSION_2 + Flags: SFRAME_F_FDE_SORTED + CFA fixed RA offset: \-8 +#... + + Function Index : + + func idx \[0\]: pc = 0x1000, size = 16 bytes + STARTPC +CFA +FP +RA + + 0+1000 +sp\+16 +u +f + + 0+1006 +sp\+24 +u +f + + + func idx \[1\]: pc = 0x1010, size = 64 bytes + STARTPC\[m\] +CFA +FP +RA + + 0+0000 +sp\+16 +u +f + + +#... diff --git a/ld/testsuite/ld-x86-64/sframe-pltgot-1.s b/ld/testsuite/ld-x86-64/sframe-pltgot-1.s new file mode 100644 index 00000000000..e596e846439 --- /dev/null +++ b/ld/testsuite/ld-x86-64/sframe-pltgot-1.s @@ -0,0 +1,15 @@ + .text + .globl foo + .type foo, @function +foo: + .cfi_startproc + call func1@plt + movq func1@GOTPCREL(%rip), %rax + call func2@plt + movq func2@GOTPCREL(%rip), %rax + call func3@plt + movq func3@GOTPCREL(%rip), %rax + call func4@plt + movq func4@GOTPCREL(%rip), %rax + .cfi_endproc + .section .note.GNU-stack,"",@progbits diff --git a/ld/testsuite/ld-x86-64/sframe-pltgot-2.d b/ld/testsuite/ld-x86-64/sframe-pltgot-2.d new file mode 100644 index 00000000000..7a99d12faa8 --- /dev/null +++ b/ld/testsuite/ld-x86-64/sframe-pltgot-2.d @@ -0,0 +1,28 @@ +#as: --gsframe +#source: sframe-pltgot-1.s +#objdump: --sframe=.sframe +#ld: -shared --no-rosegment +#name: SFrame for .plt.got + +.*: +file format .* + +Contents of the SFrame section .sframe: + Header : + + Version: SFRAME_VERSION_2 + Flags: SFRAME_F_FDE_SORTED + CFA fixed RA offset: \-8 +#... + + Function Index : + + func idx \[0\]: pc = 0x1000, size = 16 bytes + STARTPC +CFA +FP +RA + + 0+1000 +sp\+16 +u +f + + 0+1006 +sp\+24 +u +f + + + func idx \[1\]: pc = 0x1010, size = 32 bytes + STARTPC\[m\] +CFA +FP +RA + + 0+0000 +sp\+16 +u +f + + +#... diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp index 0632397bccc..a66d28eb0d1 100644 --- a/ld/testsuite/ld-x86-64/x86-64.exp +++ b/ld/testsuite/ld-x86-64/x86-64.exp @@ -548,6 +548,8 @@ if { ![skip_sframe_tests] } { run_dump_test "sframe-simple-1" run_dump_test "sframe-plt-1" run_dump_test "sframe-ibt-plt-1" + run_dump_test "sframe-pltgot-1" + run_dump_test "sframe-pltgot-2" } if ![istarget "x86_64-*-linux*"] { -- 2.43.0