From: Indu Bhagat Date: Sun, 2 Mar 2025 15:45:08 +0000 (-0800) Subject: ld: bfd: sframe: fix incorrect r_addend in RELA entries X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fheads%2Fusers%2Fibhagat%2Ftry-sframe-reloc-link-v1;p=thirdparty%2Fbinutils-gdb.git ld: bfd: sframe: fix incorrect r_addend in RELA entries With the fix in GAS, we now use a different PC-relative RELA for updating the SFrame FDE function start address: The value is the offset of the start PC of the function from the start of the SFrame section. When RELAs are output (e.g. for relocatable links), there is need to adjust the r_addend. This is because the r_addend values still have the correct values for the _input_ SFrame section being linked / relocated. The values must now be (before outputing the RELAs) with respect to the _output_ SFrame section. PS: This patch should be merged with the previous commits before final commit (Otherwise the tests will fail). It is currently a separate patch as I would like to check if this is OK to do. If such a "addend fixup" is risky or wrong, it seems we will need a new type of RELOC for SFrame sections. bfd/ * elf-bfd.h: New declaration. * elf-sframe.c (_bfd_elf_sframe_section_addend): New definition. * elflink.c (elf_link_input_bfd): Fixup the r_addend of SFrame RELAs. --- diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index f62570919d5..fd301638baa 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -2551,6 +2551,8 @@ 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 bfd_vma _bfd_elf_sframe_section_addend + (bfd *, struct bfd_link_info *, asection *, unsigned int, 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 *); diff --git a/bfd/elf-sframe.c b/bfd/elf-sframe.c index 9c7bf099649..c893d406ce8 100644 --- a/bfd/elf-sframe.c +++ b/bfd/elf-sframe.c @@ -574,6 +574,37 @@ _bfd_elf_sframe_section_offset (bfd *output_bfd ATTRIBUTE_UNUSED, + out_fde_idx * sizeof (sframe_func_desc_entry)); } +/* Get the "canonicalized" addend for the symbol reference corresponding to the + relocation at RELOC_INDEX. E.g., for the following reloc for the SFrame + FDE function start address: + Offset Type Sym. Name + Addend + 00000000001c R_X86_64_PC32 .text + 1c + 000000000030 R_X86_64_PC32 .text + 3b + The canonicalized addend are 0 and b respectively as the relocs are for + symbols (.text + 0) and (.text + b) respectively. + + This is used to manually adjust the RELA addends to ensure correct values + for relocatable links. */ + +bfd_vma +_bfd_elf_sframe_section_addend (bfd *output_bfd ATTRIBUTE_UNUSED, + struct bfd_link_info *info ATTRIBUTE_UNUSED, + asection *sec, + unsigned int reloc_index, + bfd_vma addend) +{ + struct sframe_dec_info *sfd_info; + + if (sec->sec_info_type != SEC_INFO_TYPE_SFRAME) + return addend; + + sfd_info = (struct sframe_dec_info *) elf_section_data (sec)->sec_info; + BFD_ASSERT (sfd_info && sfd_info->sfd_ctx); + + return (addend - (sframe_decoder_get_hdr_size (sfd_info->sfd_ctx) + + reloc_index * 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. */ diff --git a/bfd/elflink.c b/bfd/elflink.c index 895fbb0206e..6bce2966359 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -11939,7 +11939,9 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) last_offset = o->output_offset; if (!bfd_link_relocatable (flinfo->info)) last_offset += o->output_section->vma; - for (next_erel = 0; irela < irelaend; irela++, next_erel++) + unsigned int num_reloc = 0; + for (next_erel = 0; irela < irelaend; + irela++, next_erel++, num_reloc++) { unsigned long r_symndx; asection *sec; @@ -12070,10 +12072,24 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) } } - /* Adjust the addend according to where the - section winds up in the output section. */ if (rela_normal) - irela->r_addend += sec->output_offset; + { + if (o->sec_info_type == SEC_INFO_TYPE_SFRAME) + { + bfd_vma addend + = _bfd_elf_sframe_section_addend (output_bfd, + flinfo->info, o, + num_reloc, + irela->r_addend); + /* Adjust the addend in the output RELA. The + input SFrame section has already been + relocated. */ + irela->r_addend = addend + irela->r_offset; + } + /* Adjust the addend according to where the + section winds up in the output section. */ + irela->r_addend += sec->output_offset; + } } else {