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
 		    {
