]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
s390: Generate .eh_frame unwind information for .plt section
authorJens Remus <jremus@linux.ibm.com>
Mon, 27 Jan 2025 15:47:10 +0000 (16:47 +0100)
committerJens Remus <jremus@linux.ibm.com>
Mon, 27 Jan 2025 15:47:10 +0000 (16:47 +0100)
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 <jremus@linux.ibm.com>
bfd/elf64-s390.c
ld/NEWS
ld/emulparams/elf64_s390.sh
ld/testsuite/ld-s390/plt_64-1_eh.wf [new file with mode: 0644]
ld/testsuite/ld-s390/s390.exp

index 27836b87d6f83fc6f22b094151421f6054d641a9..259ad13be51f161a141d8b76d0b07a3de0329660 100644 (file)
@@ -26,6 +26,7 @@
 #include "elf-bfd.h"
 #include "elf/s390.h"
 #include "elf-s390.h"
+#include "dwarf2.h"
 #include <stdarg.h>
 
 /* 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;
 }
 \f
@@ -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 17fb20a6b9f7813748dc3346075291ce7ad13f56..acb3263a29f67cf8f35cc56b610548a16c6c3c68 100644 (file)
--- 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
index d0a2a59a0926932ce74f650cedb948f5d3774b94..b58314800d10b44ec01b1e5915a5cacbd2a2f44f 100644 (file)
@@ -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 (file)
index 0000000..717e7a7
--- /dev/null
@@ -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
+
+#...
index 26dab72c013d751db049edfdb7a9ff97c44d14b3..d91eeacc730a3361ccf8204954cd002ed8a3e1de 100644 (file)
@@ -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-*-*"] {