]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
ld: bfd: sframe: fix incorrect offset in RELA entries users/ibhagat/try-pr32589-pr32666
authorIndu Bhagat <indu.bhagat@oracle.com>
Thu, 6 Feb 2025 21:38:04 +0000 (13:38 -0800)
committerIndu Bhagat <indu.bhagat@oracle.com>
Wed, 26 Feb 2025 00:00:43 +0000 (16:00 -0800)
PR/32666  Incorrect .rela.sframe when using ld -r

Input SFrame sections are merged using _bfd_elf_merge_section_sframe (),
which clubs all SFrame FDEs together in one blob and all SFrame FREs in
another.  This, of course, means the offset of an FDE in the output
section cannot be simply derived from the output_offset of the sections.

Fix this by providing _bfd_elf_sframe_section_offset () which returns
the new offset of the SFrame FDE in the merged SFrame section.

TBD:
  - Q: The _bfd_elf_sframe_section_offset () function does assume that
    _bfd_elf_merge_section_sframe () has not been called on the
    associated .sframe section yet.  Is this an OK assumption ?

bfd/
        * elf-bfd.h: New declaration.
        * elf-sframe.c (_bfd_elf_sframe_section_offset): New definition.
        * elf.c (_bfd_elf_section_offset): Adjust offset if SFrame
section.
        * elflink.c (elf_link_input_bfd): RELA offset adjust be done
conditionally.

ld/testsuite/
        * ld-x86-64/x86-64.exp: New test.
        * ld-x86-64/sframe-reloc-1.d: New test.

bfd/elf-bfd.h
bfd/elf-sframe.c
bfd/elf.c
bfd/elflink.c
ld/testsuite/ld-x86-64/sframe-reloc-1.d [new file with mode: 0644]
ld/testsuite/ld-x86-64/x86-64.exp

index d2bf8e5cbaef9809df98256ef856d469111381e6..f5b253a0d429570f7ac0d86246eec2b02b037aa1 100644 (file)
@@ -2535,6 +2535,8 @@ extern bool _bfd_elf_discard_section_sframe
   (asection *, bool (*) (bfd_vma, void *), struct elf_reloc_cookie *);
 extern bool _bfd_elf_merge_section_sframe
   (bfd *, struct bfd_link_info *, asection *, bfd_byte *);
+extern bfd_vma _bfd_elf_sframe_section_offset
+  (bfd *, struct bfd_link_info *, asection *, bfd_vma);
 extern bool _bfd_elf_write_section_sframe
   (bfd *, struct bfd_link_info *);
 extern bool _bfd_elf_set_section_sframe (bfd *, struct bfd_link_info *);
index 67ed874e02524e9fb9ce69221305eeb50c488634..92245792fe804af53fe97521d820a49b41b7b6d4 100644 (file)
@@ -515,6 +515,56 @@ _bfd_elf_merge_section_sframe (bfd *abfd,
   return true;
 }
 
+/* Adjust an address in the .sframe section.  Given OFFSET within
+   SEC, this returns the new offset in the merged .sframe section,
+   or -1 if the address refers to an FDE which has been removed.
+
+   PS: This function assumes that _bfd_elf_merge_section_sframe has not been
+   called on the input section SEC yet.  */
+
+bfd_vma
+_bfd_elf_sframe_section_offset (bfd *output_bfd ATTRIBUTE_UNUSED,
+                               struct bfd_link_info *info,
+                               asection *sec,
+                               bfd_vma offset)
+{
+  struct sframe_dec_info *sfd_info;
+  struct sframe_enc_info *sfe_info;
+  sframe_decoder_ctx *sfd_ctx;
+  sframe_encoder_ctx *sfe_ctx;
+  struct elf_link_hash_table *htab;
+
+  unsigned int sec_fde_idx, out_fde_idx = 0;
+  unsigned int i, sfe_num_fdes;
+
+  if (sec->sec_info_type != SEC_INFO_TYPE_SFRAME)
+    return offset;
+
+  sfd_info = (struct sframe_dec_info *) elf_section_data (sec)->sec_info;
+  sfd_ctx = sfd_info->sfd_ctx;
+
+  htab = elf_hash_table (info);
+  sfe_info = &(htab->sfe_info);
+  sfe_ctx = sfe_info->sfe_ctx;
+
+  sfe_num_fdes = sframe_encoder_get_num_fidx (sfe_ctx);
+  /* Identify the index of the FDE (at OFFSET) in the input section.  */
+  sec_fde_idx = ((offset - sframe_decoder_get_hdr_size (sfd_ctx))
+                / sizeof (sframe_func_desc_entry));
+  /* The index of this FDE in the output section depends on number of deleted
+     functions, if any.  */
+  for (i = 0; i < sec_fde_idx; i++)
+    {
+      if (!sframe_decoder_func_deleted_p (sfd_info, i))
+       out_fde_idx++;
+    }
+  /* The actual index of the FDE in the output SFrame section.  */
+  out_fde_idx += sfe_num_fdes;
+
+  return (sframe_decoder_get_hdr_size (sfd_ctx)
+         + out_fde_idx * sizeof (sframe_func_desc_entry));
+}
+
 /* Write out the .sframe section.  This must be called after
    _bfd_elf_merge_section_sframe has been called on all input
    .sframe sections.  */
index 3f8bc838bfb34b367c500b916046a090b4015143..3d65486ad5ba655f740490dabf1fe4195c47a88f 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -13491,6 +13491,9 @@ _bfd_elf_section_offset (bfd *abfd,
     case SEC_INFO_TYPE_EH_FRAME:
       return _bfd_elf_eh_frame_section_offset (abfd, info, sec, offset);
 
+    case SEC_INFO_TYPE_SFRAME:
+      return _bfd_elf_sframe_section_offset (abfd, info, sec, offset);
+
     default:
       if ((sec->flags & SEC_ELF_REVERSE_COPY) != 0)
        {
index 0df19769483620a3190064a3997303c12bb4748f..8e6711f6ae1175be18606b4192dd6ce1c7513c40 100644 (file)
@@ -11974,7 +11974,8 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
                      continue;
                    }
 
-                 irela->r_offset += o->output_offset;
+                 if (o->sec_info_type != SEC_INFO_TYPE_SFRAME)
+                   irela->r_offset += o->output_offset;
 
                  /* Relocs in an executable have to be virtual addresses.  */
                  if (!bfd_link_relocatable (flinfo->info))
diff --git a/ld/testsuite/ld-x86-64/sframe-reloc-1.d b/ld/testsuite/ld-x86-64/sframe-reloc-1.d
new file mode 100644 (file)
index 0000000..308f94b
--- /dev/null
@@ -0,0 +1,34 @@
+#as: --gsframe
+#source: sframe-foo.s
+#source: sframe-bar.s
+#objdump: --sframe=.sframe
+#ld: -r --no-rosegment
+#name: SFrame simple link - relocatable
+
+.*: +file format .*
+
+Contents of the SFrame section .sframe:
+  Header :
+
+    Version: SFRAME_VERSION_2
+    Flags: SFRAME_F_FDE_SORTED
+    CFA fixed RA offset: \-8
+    Num FDEs: 2
+    Num FREs: 8
+
+  Function Index :
+
+
+    func idx \[0\]: pc = 0x0, size = 53 bytes
+    STARTPC +CFA +FP +RA +
+    0+0000 +sp\+8 +u +f +
+    0+0001 +sp\+16 +c-16 +f +
+    0+0004 +fp\+16 +c-16 +f +
+    0+0034 +sp\+8 +c-16 +f +
+
+    func idx \[1\]: pc = 0x35, size = 37 bytes
+    STARTPC +CFA +FP +RA +
+    0+0035 +sp\+8 +u +f +
+    0+0036 +sp\+16 +c-16 +f +
+    0+0039 +fp\+16 +c-16 +f +
+    0+0059 +sp\+8 +c-16 +f +
index 01d6459b5d79c03de4587e009284cb1433361fad..eed06af80df1cdf9ff144da843ec0dbf88ec7899 100644 (file)
@@ -566,6 +566,7 @@ run_dump_test "pr32591-4-x32"
 
 if { ![skip_sframe_tests] } {
     run_dump_test "sframe-simple-1"
+    run_dump_test "sframe-reloc-1"
     run_dump_test "sframe-plt-1"
     run_dump_test "sframe-ibt-plt-1"
     run_dump_test "sframe-pltgot-1"