]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commit
ld: bfd: sframe: fix incorrect r_offset in RELA entries
authorIndu Bhagat <indu.bhagat@oracle.com>
Thu, 6 Feb 2025 21:38:04 +0000 (13:38 -0800)
committerIndu Bhagat <indu.bhagat@oracle.com>
Wed, 28 May 2025 04:58:14 +0000 (21:58 -0700)
commit0238bab9b7d979e8a1a161adfbb47cd748dd80d1
tree4ae4e26666e2b70338c503696174677b18beb294
parentda657732c7413f88623559e75baf3ca72ac286d2
ld: bfd: sframe: fix incorrect r_offset in RELA entries

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 SFrame 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.

Unlike EH_Frame sections, which also use the _bfd_elf_section_offset (),
to update the r_offset, SFrame sections have distinct merging semantics.
In case of SFrame, the SFrame FDE will not simply sit at location
"sec->output_offset + offset of SFrame FDE in sec".  Recall that information
layout in an SFrame section is as follows:
   SFrame Header
   SFrame FDE 1
   SFrame FDE 2
   ...
   SFrame FDEn
   SFrame FREs (Frame Row Entries)
Note how the SFrame FDEs and SFrame FREs are clubber together in groups
of their own.

Next, also note how the elf_link_input_bfd () does a:
            irela->r_offset += o->output_offset;
This, however, needs to be avoided for SFrame sections because the
placement of all FDEs is at the beginning of the section.  So, rather than
conditionalizing this as follows:
          if (o->sec_info_type != SEC_INFO_TYPE_SFRAME)
            irela->r_offset += o->output_offset;
the implementation in _bfd_elf_sframe_section_offset () does a reverse
adjustment, so that the generic parts of the linking process in
elf_link_input_bfd () are not made to do SFrame specific adjustments.

Add a new enum to track the current state of the SFrame input section
during the linking process (SFRAME_SEC_DECODED, SFRAME_SEC_MERGED) for
each input SFrame section.  This is then used to assert an assumption
that _bfd_elf_sframe_section_offset () is being used on an input SFrame
sections which have not been merged (via
_bfd_elf_merge_section_sframe ()) yet.

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.
ld/testsuite/
        * ld-x86-64/x86-64.exp: New test.
        * ld-x86-64/sframe-reloc-1.d: New test.

---
Notes:

This patch was previously reviewed.
https://inbox.sourceware.org/binutils/d914ea1f-6c11-4ef5-ac15-404fd7afd26d@suse.com/

There was a comment on moving this
          if (o->sec_info_type != SEC_INFO_TYPE_SFRAME)
            irela->r_offset += o->output_offset;
to inside the _bfd_elf_sframe_section_offset () or keep it in
elf_link_input_bfd () with some code comments.  Although, I think
keeping it deliberatly out of _bfd_elf_sframe_section_offset () was
clearer as that helped keep the contract of _bfd_elf_section_offset ()
symmetrical across section types.  That said, taking the overall
opinions shared in the previous review, I have moved the stub inside
_bfd_elf_sframe_section_offset ().  But if opinions have changed, I am
happy to bring the conditional back to elf_link_input_bfd ().
bfd/elf-bfd.h
bfd/elf-sframe.c
bfd/elf.c
ld/testsuite/ld-x86-64/sframe-reloc-1.d [new file with mode: 0644]
ld/testsuite/ld-x86-64/x86-64.exp