From: Jens Remus Date: Mon, 27 Jan 2025 15:47:10 +0000 (+0100) Subject: s390: Generate .eh_frame unwind information for .plt section X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=98d9fe6cb62ee17366fb4073cd04a85193f0ab6b;p=thirdparty%2Fbinutils-gdb.git s390: Generate .eh_frame unwind information for .plt section Enable unwinding using .eh_frame information through PLT entries. Based on x86-64. This enhances stack traces if the instruction pointer is in a PLT entry. For instance perf call graphs, when using --call-graph=dwarf, and Glibc backtraces, when using backtrace() e.g. from a signal handler. Note that GDB could already unwind through PLT entries using its s390- specific prologue unwinder. Furthermore this lays the foundation to generate SFrame information for the PLT section in the future. bfd/ * elf64-s390.c: Include dwarf2.h. (PLT_CIE_SIZE, PLT_FDE_SIZE, PLT_FDE_START_OFFSET, PLT_FDE_LEN_OFFSET, elf_s390x_eh_frame_plt): New .eh_frame template for .plt section. (elf_s390_link_hash_table): Add plt_eh_frame field. (elf_s390_create_dynamic_sections): New s390-specific wrapper around _bfd_elf_create_dynamic_sections. Create .eh_frame section for .plt section. (elf_backend_create_dynamic_sections): Register s390-specific elf_s390_create_dynamic_sections. (elf_s390_late_size_sections): Fill in .eh_frame section for .plt section. Write .plt section size into .eh_frame FDE covering .plt section. (elf_s390_finish_dynamic_sections): Write .plt section start into .eh_frame FDE covering .plt section. Call _bfd_elf_write_section_eh_frame on on htab->plt_eh_frame section. ld/ * NEWS: Add news entry. * emulparams/elf64_s390.sh: Include plt_unwind.sh. ld/testsuite/ * ld-s390/plt_64-1_eh.wf: New PLT .eh_frame generation test. * ld-s390/s390.exp: Link some existing test cases with --no-ld-generated-unwind-info so that they do not fail. Run new PLT .eh_frame generation test. Signed-off-by: Jens Remus --- diff --git a/bfd/elf64-s390.c b/bfd/elf64-s390.c index 27836b87d6f..259ad13be51 100644 --- a/bfd/elf64-s390.c +++ b/bfd/elf64-s390.c @@ -26,6 +26,7 @@ #include "elf-bfd.h" #include "elf/s390.h" #include "elf-s390.h" +#include "dwarf2.h" #include /* In case we're on a 32-bit machine, construct a 64-bit "-1" value @@ -564,6 +565,35 @@ static const bfd_byte elf_s390x_first_plt_entry[PLT_FIRST_ENTRY_SIZE] = 0x07, 0x00 /* nopr %r0 */ }; +/* .eh_frame covering the .plt section. */ + +#define PLT_CIE_SIZE 24 +#define PLT_FDE_SIZE 20 +#define PLT_FDE_START_OFFSET (PLT_CIE_SIZE + 8) +#define PLT_FDE_LEN_OFFSET (PLT_CIE_SIZE + 12) + +static const bfd_byte elf_s390x_eh_frame_plt[] = +{ + 0, 0, 0, PLT_CIE_SIZE - 4, /* CIE length */ + 0, 0, 0, 0, /* CIE ID */ + 1, /* CIE version */ + 'z', 'R', 0, /* Augmentation string */ + 1, /* Code alignment factor */ + 0x78, /* Data alignment factor */ + 14, /* Return address column */ + 1, /* Augmentation size */ + DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding */ + DW_CFA_def_cfa, 15, 0xa0, 0x01, /* DW_CFA_def_cfa: r15 ofs 160 */ + DW_CFA_nop, DW_CFA_nop, DW_CFA_nop, + + 0, 0, 0, PLT_FDE_SIZE - 4, /* FDE length */ + 0, 0, 0, PLT_CIE_SIZE + 4, /* CIE pointer */ + 0, 0, 0, 0, /* R_S390_PC32 .plt goes here */ + 0, 0, 0, 0, /* .plt size goes here */ + 0, /* Augmentation size */ + DW_CFA_nop, DW_CFA_nop, DW_CFA_nop +}; + /* s390 ELF linker hash entry. */ @@ -656,6 +686,7 @@ struct elf_s390_link_hash_table /* Short-cuts to get to dynamic linker sections. */ asection *irelifunc; + asection *plt_eh_frame; union { bfd_signed_vma refcount; @@ -1852,6 +1883,15 @@ elf_s390_late_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED, sym dynamic relocs. */ elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, info); + 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)) + htab->plt_eh_frame->size = sizeof (elf_s390x_eh_frame_plt); + } + /* We now have determined the sizes of the various dynamic sections. Allocate memory for them. */ relocs = false; @@ -1863,6 +1903,7 @@ elf_s390_late_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED, if (s == htab->elf.splt || s == htab->elf.sgot || s == htab->elf.sgotplt + || s == htab->plt_eh_frame || s == htab->elf.sdynbss || s == htab->elf.sdynrelro || s == htab->elf.iplt @@ -1930,6 +1971,16 @@ elf_s390_late_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED, s->alloced = 1; } + if (htab->plt_eh_frame != NULL + && htab->plt_eh_frame->contents != NULL) + { + memcpy (htab->plt_eh_frame->contents, + elf_s390x_eh_frame_plt, + htab->plt_eh_frame->size); + bfd_put_32 (dynobj, htab->elf.splt->size, + htab->plt_eh_frame->contents + PLT_FDE_LEN_OFFSET); + } + return _bfd_elf_add_dynamic_tags (output_bfd, info, relocs); } @@ -3703,6 +3754,38 @@ elf_s390_finish_dynamic_sections (bfd *output_bfd, } } + /* Adjust .eh_frame for .plt section. */ + if (htab->plt_eh_frame != NULL + && htab->plt_eh_frame->contents != NULL) + { + if (htab->elf.splt != NULL + && htab->elf.splt->size != 0 + && (htab->elf.splt->flags & SEC_EXCLUDE) == 0 + && htab->elf.splt->output_section != NULL + && htab->plt_eh_frame->output_section != NULL) + { + bfd_vma plt_start = htab->elf.splt->output_section->vma; + bfd_vma eh_frame_start = htab->plt_eh_frame->output_section->vma + + htab->plt_eh_frame->output_offset + + PLT_FDE_START_OFFSET; + /* Note: Linker may have discarded the FDE, so that store may + be beyond current htab->plt_eh_frame->size. Can be ignored, + as htab->plt_eh_frame->contents got allocated with + sizeof (elf_s390x_eh_frame_plt). See PR 12570. */ + bfd_put_signed_32 (dynobj, plt_start - eh_frame_start, + htab->plt_eh_frame->contents + + PLT_FDE_START_OFFSET); + } + + if (htab->plt_eh_frame->sec_info_type == SEC_INFO_TYPE_EH_FRAME) + { + if (! _bfd_elf_write_section_eh_frame (output_bfd, info, + htab->plt_eh_frame, + htab->plt_eh_frame->contents)) + return NULL; + } + } + return true; } @@ -3926,6 +4009,47 @@ bfd_elf_s390_set_options (struct bfd_link_info *info, return true; } +/* Create .plt, .rela.plt, .got, .got.plt, .rela.got, .dynbss, and + .rela.bss sections in DYNOBJ, and set up shortcuts to them in our + hash table. */ + +static bool +elf_s390_create_dynamic_sections (bfd *dynobj, + struct bfd_link_info *info) +{ + struct elf_s390_link_hash_table *htab; + + if (!_bfd_elf_create_dynamic_sections (dynobj, info)) + return false; + + htab = elf_s390_hash_table (info); + if (htab == NULL) + return false; + + if (htab->elf.splt != NULL) + { + /* Create .eh_frame section for .plt section. */ + if (!info->no_ld_generated_unwind_info) + { + flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY + | SEC_HAS_CONTENTS | SEC_IN_MEMORY + | SEC_LINKER_CREATED); + + if (htab->plt_eh_frame == NULL) + { + htab->plt_eh_frame + = bfd_make_section_anyway_with_flags (dynobj, + ".eh_frame", + flags); + if (htab->plt_eh_frame == NULL + || !bfd_set_section_alignment (htab->plt_eh_frame, 3)) + return false; + } + } + } + + return true; +} /* Why was the hash table entry size definition changed from ARCH_SIZE/8 to 4? This breaks the 64 bit dynamic linker and @@ -3992,7 +4116,7 @@ const struct elf_size_info s390_elf64_size_info = #define elf_backend_adjust_dynamic_symbol elf_s390_adjust_dynamic_symbol #define elf_backend_check_relocs elf_s390_check_relocs #define elf_backend_copy_indirect_symbol elf_s390_copy_indirect_symbol -#define elf_backend_create_dynamic_sections _bfd_elf_create_dynamic_sections +#define elf_backend_create_dynamic_sections elf_s390_create_dynamic_sections #define elf_backend_finish_dynamic_sections elf_s390_finish_dynamic_sections #define elf_backend_finish_dynamic_symbol elf_s390_finish_dynamic_symbol #define elf_backend_gc_mark_hook elf_s390_gc_mark_hook diff --git a/ld/NEWS b/ld/NEWS index 17fb20a6b9f..acb3263a29f 100644 --- a/ld/NEWS +++ b/ld/NEWS @@ -1,5 +1,11 @@ -*- text -*- +* On s390, generate ".eh_frame" unwind information for the linker generated + .plt section. Enabled by default. Can be disabled using linker option + --no-ld-generated-unwind-info. + +* On s390, add support for linker option --[no-]ld-generated-unwind-info. + Changes in 2.44: * Support for Nios II target has been removed, as this architecture has been diff --git a/ld/emulparams/elf64_s390.sh b/ld/emulparams/elf64_s390.sh index d0a2a59a092..b58314800d1 100644 --- a/ld/emulparams/elf64_s390.sh +++ b/ld/emulparams/elf64_s390.sh @@ -1,3 +1,4 @@ +source_sh ${srcdir}/emulparams/plt_unwind.sh SCRIPT_NAME=elf ELFSIZE=64 OUTPUT_FORMAT="elf64-s390" diff --git a/ld/testsuite/ld-s390/plt_64-1_eh.wf b/ld/testsuite/ld-s390/plt_64-1_eh.wf new file mode 100644 index 00000000000..717e7a7e2a6 --- /dev/null +++ b/ld/testsuite/ld-s390/plt_64-1_eh.wf @@ -0,0 +1,31 @@ +#source: plt_64-1.s +#as: -m64 +#ld: -m elf64_s390 +#readelf: -wf +#target: s390x-*-* + +Contents of the .eh_frame section: + + +00000000 0000000000000014 00000000 CIE + Version: 1 + Augmentation: "zR" + Code alignment factor: 1 + Data alignment factor: -8 + Return address column: 14 + Augmentation data: 1b + DW_CFA_def_cfa: r15 ofs 160 + DW_CFA_nop + DW_CFA_nop + DW_CFA_nop + +00000018 0000000000000014 0000001c FDE cie=00000000 pc=0000000001000258..00000000010002b8 + DW_CFA_nop + DW_CFA_nop + DW_CFA_nop + DW_CFA_nop + DW_CFA_nop + DW_CFA_nop + DW_CFA_nop + +#... diff --git a/ld/testsuite/ld-s390/s390.exp b/ld/testsuite/ld-s390/s390.exp index 26dab72c013..d91eeacc730 100644 --- a/ld/testsuite/ld-s390/s390.exp +++ b/ld/testsuite/ld-s390/s390.exp @@ -74,7 +74,7 @@ set s390tests { } set s390xtests { - {"TLS -fpic -shared transitions" "-shared -melf64_s390 --hash-style=sysv" "" + {"TLS -fpic -shared transitions" "-shared -melf64_s390 --hash-style=sysv --no-ld-generated-unwind-info" "" "-m64 -Aesame" {tlspic1_64.s tlspic2_64.s} {{readelf -WSsrl tlspic_64.rd} {objdump -dzrj.text tlspic_64.dd} {objdump -sj.got tlspic_64.sd} {objdump -sj.tdata tlspic_64.td}} @@ -82,7 +82,7 @@ set s390xtests { {"Helper shared library" "-shared -melf64_s390" "" "-m64 -Aesame" {tlslib_64.s} {} "libtlslib_64.so"} {"TLS -fpic and -fno-pic exec transitions" - "-melf64_s390 tmpdir/libtlslib_64.so --hash-style=sysv" "" + "-melf64_s390 tmpdir/libtlslib_64.so --hash-style=sysv --no-ld-generated-unwind-info" "" "-m64 -Aesame" {tlsbinpic_64.s tlsbin_64.s} {{readelf -WSsrl tlsbin_64.rd} {objdump -dzrj.text tlsbin_64.dd} {objdump -sj.got tlsbin_64.sd} {objdump -sj.tdata tlsbin_64.td}} @@ -117,10 +117,14 @@ set s390xtests { "-shared -m elf64_s390" "" "-m64" {pltlib.s} {} "libpltlib_64.so"} - {"PLT: PLT generation" - "-m elf64_s390 tmpdir/libpltlib_64.so" "" "-m64" {plt_64-1.s} + {"PLT: PLT generation without .eh_frame unwind info" + "-m elf64_s390 tmpdir/libpltlib_64.so --no-ld-generated-unwind-info" "" "-m64" {plt_64-1.s} {{objdump "-dzrj.plt" plt_64-1.pd} {readelf "-wf" plt_64-1.wf}} "plt_64-1"} + {"PLT: PLT generation with .eh_frame unwind info" + "-m elf64_s390 tmpdir/libpltlib_64.so" "" "-m64" {plt_64-1.s} + {{objdump "-dzrj.plt" plt_64-1.pd} {readelf "-wf" plt_64-1_eh.wf}} + "plt_64-1_eh"} } if [istarget "s390-*-*"] {