diff --git a/gas/gen-sframe.c b/gas/gen-sframe.c
index 4cc86eb6c815..7f3b406c7882 100644
--- a/gas/gen-sframe.c
+++ b/gas/gen-sframe.c
@@ -251,7 +251,7 @@ fre_offset_func_map[SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX+1] =
 static struct sframe_version_ops sframe_ver_ops;
 
 /* SFrame (SFRAME_VERSION_1) set FRE info.  */
-
+/*
 static unsigned char
 sframe_v1_set_fre_info (unsigned int base_reg, unsigned int num_offsets,
 			unsigned int offset_size, bool mangled_ra_p)
@@ -261,6 +261,19 @@ sframe_v1_set_fre_info (unsigned int base_reg, unsigned int num_offsets,
   fre_info = SFRAME_V1_FRE_INFO_UPDATE_MANGLED_RA_P (mangled_ra_p, fre_info);
   return fre_info;
 }
+*/
+
+/* SFrame (SFRAME_VERSION_2) set FRE info.  */
+
+static unsigned char
+sframe_v2_set_fre_info (unsigned int base_reg, unsigned int offset_flags,
+			unsigned int offset_size, bool mangled_ra_p)
+{
+  unsigned char fre_info;
+  fre_info = SFRAME_V2_FRE_INFO (base_reg, offset_flags, offset_size);
+  fre_info = SFRAME_V1_FRE_INFO_UPDATE_MANGLED_RA_P (mangled_ra_p, fre_info);
+  return fre_info;
+}
 
 /* SFrame (SFRAME_VERSION_1) set function info.  */
 static unsigned char
@@ -280,10 +293,10 @@ sframe_set_version (uint32_t sframe_version ATTRIBUTE_UNUSED)
 {
   sframe_ver_ops.format_version = SFRAME_VERSION_2;
 
-  /* These operations remain the same for SFRAME_VERSION_2 as fre_info and
-     func_info have not changed from SFRAME_VERSION_1.  */
+  sframe_ver_ops.set_fre_info = sframe_v2_set_fre_info;
 
-  sframe_ver_ops.set_fre_info = sframe_v1_set_fre_info;
+  /* This operation remains the same for SFRAME_VERSION_2 as func_info
+     has not changed from SFRAME_VERSION_1.  */
 
   sframe_ver_ops.set_func_info = sframe_v1_set_func_info;
 }
@@ -291,10 +304,10 @@ sframe_set_version (uint32_t sframe_version ATTRIBUTE_UNUSED)
 /* SFrame set FRE info.  */
 
 static unsigned char
-sframe_set_fre_info (unsigned int base_reg, unsigned int num_offsets,
+sframe_set_fre_info (unsigned int base_reg, unsigned int offset_count_or_flags,
 		     unsigned int offset_size, bool mangled_ra_p)
 {
-  return sframe_ver_ops.set_fre_info (base_reg, num_offsets,
+  return sframe_ver_ops.set_fre_info (base_reg, offset_count_or_flags,
 				      offset_size, mangled_ra_p);
 }
 
@@ -353,6 +366,24 @@ get_fre_num_offsets (struct sframe_row_entry *sframe_fre)
   return fre_num_offsets;
 }
 
+/* Get offset flags necessary for the SFrame Frame Row Entry.  */
+
+static unsigned int
+get_fre_offset_flags (struct sframe_row_entry *sframe_fre)
+{
+  /* CFA offset must always be present.  */
+  unsigned int fre_offset_flags = 1 << SFRAME_FRE_CFA_OFFSET_IDX;
+
+  if (sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
+    fre_offset_flags |= 1 << SFRAME_FRE_FP_OFFSET_IDX;
+#ifdef SFRAME_FRE_RA_TRACKING
+  if (sframe_ra_tracking_p ()
+      && sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK)
+    fre_offset_flags |= 1 << SFRAME_FRE_RA_OFFSET_IDX;
+#endif
+  return fre_offset_flags;
+}
+
 /* Get the minimum necessary offset size (in bytes) for this
    SFrame frame row entry.  */
 
@@ -494,6 +525,7 @@ output_sframe_row_entry (symbolS *fde_start_addr,
 {
   unsigned char fre_info;
   unsigned int fre_num_offsets;
+  unsigned int fre_offset_flags;
   unsigned int fre_offset_size;
   unsigned int fre_base_reg;
   expressionS exp;
@@ -524,8 +556,9 @@ output_sframe_row_entry (symbolS *fde_start_addr,
      size of offset in this frame row entry.  */
   fre_base_reg = get_fre_base_reg_id (sframe_fre);
   fre_num_offsets = get_fre_num_offsets (sframe_fre);
+  fre_offset_flags = get_fre_offset_flags (sframe_fre);
   fre_offset_size = sframe_get_fre_offset_size (sframe_fre);
-  fre_info = sframe_set_fre_info (fre_base_reg, fre_num_offsets,
+  fre_info = sframe_set_fre_info (fre_base_reg, fre_offset_flags,
 				  fre_offset_size, sframe_fre->mangled_ra_p);
   out_one (fre_info);
 
@@ -1497,25 +1530,6 @@ sframe_do_fde (struct sframe_xlate_ctx *xlate_ctx,
 	= get_dw_fde_end_addrS (xlate_ctx->dw_fde);
     }
 
-#ifdef SFRAME_FRE_RA_TRACKING
-  if (sframe_ra_tracking_p ())
-    {
-      struct sframe_row_entry *fre;
-
-      /* Iterate over the scratchpad FREs and validate them.  */
-      for (fre = xlate_ctx->first_fre; fre; fre = fre->next)
-	{
-	  /* SFrame format cannot represent FP on stack without RA on stack.  */
-	  if (fre->ra_loc != SFRAME_FRE_ELEM_LOC_STACK
-	      && fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
-	    {
-	      as_warn (_("skipping SFrame FDE due to FP without RA on stack"));
-	      return SFRAME_XLATE_ERR_NOTREPRESENTED;
-	    }
-	}
-    }
-#endif /* SFRAME_FRE_RA_TRACKING  */
-
   return SFRAME_XLATE_OK;
 }
 
diff --git a/include/sframe.h b/include/sframe.h
index 90bc92a32f84..093dca6cda9a 100644
--- a/include/sframe.h
+++ b/include/sframe.h
@@ -241,14 +241,14 @@ typedef struct sframe_fre_info
 {
   /* Information about
      - 1 bit: base reg for CFA
-     - 4 bits: Number of offsets (N).  A value of upto 3 is allowed to track
-     all three of CFA, FP and RA (fixed implicit order).
+     - 4 bits: Flags for offsets.  Upto 3 are allowed to track
+     all three of CFA, FP and RA (fixed order).
      - 2 bits: information about size of the offsets (S) in bytes.
      Valid values are SFRAME_FRE_OFFSET_1B, SFRAME_FRE_OFFSET_2B,
      SFRAME_FRE_OFFSET_4B
      - 1 bit: Mangled RA state bit (aarch64 only).
      ----------------------------------------------------------------------------------
-     | Mangled-RA (aarch64) |  Size of offsets   |   Number of offsets    |   base_reg |
+     | Mangled-RA (aarch64) |  Size of offsets   |   Flags for offsets    |   base_reg |
      | Unused (amd64, s390) |                    |                        |            |
      ----------------------------------------------------------------------------------
      8                     7                    5                        1            0
@@ -264,6 +264,11 @@ typedef struct sframe_fre_info
   (((0 & 0x1) << 7) | (((offset_size) & 0x3) << 5) | \
    (((offset_num) & 0xf) << 1) | ((base_reg_id) & 0x1))
 
+/* Note: Set mangled_ra_p to zero by default.  */
+#define SFRAME_V2_FRE_INFO(base_reg_id, offset_flags, offset_size) \
+  (((0 & 0x1) << 7) | (((offset_size) & 0x3) << 5) | \
+   (((offset_flags) & 0xf) << 1) | ((base_reg_id) & 0x1))
+
 /* Set the mangled_ra_p bit as indicated.  */
 #define SFRAME_V1_FRE_INFO_UPDATE_MANGLED_RA_P(mangled_ra_p, fre_info) \
   ((((mangled_ra_p) & 0x1) << 7) | ((fre_info) & 0x7f))
@@ -273,6 +278,8 @@ typedef struct sframe_fre_info
 #define SFRAME_V1_FRE_OFFSET_SIZE(data)		  (((data) >> 5) & 0x3)
 #define SFRAME_V1_FRE_MANGLED_RA_P(data)	  (((data) >> 7) & 0x1)
 
+#define SFRAME_V2_FRE_OFFSET_FLAGS(data)	  (((data) >> 1) & 0xf)
+
 /* SFrame Frame Row Entry definitions.
 
    Used for AMD64, AARCH64, and S390.
diff --git a/libsframe/sframe.c b/libsframe/sframe.c
index 460face4168e..f43f9eaecfd1 100644
--- a/libsframe/sframe.c
+++ b/libsframe/sframe.c
@@ -115,7 +115,10 @@ sframe_get_hdr_size (sframe_header *sfh)
 static uint8_t
 sframe_fre_get_offset_count (uint8_t fre_info)
 {
-  return SFRAME_V1_FRE_OFFSET_COUNT (fre_info);
+  unsigned int fre_offset_flags = SFRAME_V2_FRE_OFFSET_FLAGS (fre_info);
+  const char flags_to_count[16] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
+
+  return flags_to_count[fre_offset_flags];
 }
 
 static uint8_t
@@ -130,6 +133,19 @@ sframe_get_fre_ra_mangled_p (uint8_t fre_info)
   return SFRAME_V1_FRE_MANGLED_RA_P (fre_info);
 }
 
+static int
+sframe_get_fre_offset_index (uint8_t fre_info, unsigned int tracked_offset)
+{
+  unsigned int fre_offset_flags = SFRAME_V2_FRE_OFFSET_FLAGS (fre_info);
+  const char flags_to_count[16] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
+  unsigned int mask = (1 << tracked_offset) - 1;
+
+  if ((fre_offset_flags & (1 << tracked_offset)) == 0)
+    return -1;
+
+  return flags_to_count[fre_offset_flags & mask];
+}
+
 /* Access functions for info from function descriptor entry.  */
 
 static uint32_t
@@ -680,7 +696,13 @@ int32_t
 sframe_fre_get_cfa_offset (sframe_decoder_ctx *dctx ATTRIBUTE_UNUSED,
 			   sframe_frame_row_entry *fre, int *errp)
 {
-  return sframe_get_fre_offset (fre, SFRAME_FRE_CFA_OFFSET_IDX, errp);
+  int cfa_offset_idx = sframe_get_fre_offset_index (fre->fre_info,
+						    SFRAME_FRE_CFA_OFFSET_IDX);
+  if (cfa_offset_idx == -1)
+    return sframe_set_errno (errp, SFRAME_ERR_FREOFFSET_NOPRESENT);
+  sframe_assert (cfa_offset_idx == 0);
+
+  return sframe_get_fre_offset (fre, cfa_offset_idx, errp);
 }
 
 /* Get the FP offset from the FRE.  If the offset is invalid, sets errp.  */
@@ -689,7 +711,7 @@ int32_t
 sframe_fre_get_fp_offset (sframe_decoder_ctx *dctx,
 			  sframe_frame_row_entry *fre, int *errp)
 {
-  uint32_t fp_offset_idx = 0;
+  int fp_offset_idx;
   int8_t fp_offset = sframe_decoder_get_fixed_fp_offset (dctx);
   /* If the FP offset is not being tracked, return the fixed FP offset
      from the SFrame header.  */
@@ -700,13 +722,13 @@ sframe_fre_get_fp_offset (sframe_decoder_ctx *dctx,
       return fp_offset;
     }
 
-  /* In some ABIs, the stack offset to recover RA (using the CFA) from is
-     fixed (like AMD64).  In such cases, the stack offset to recover FP will
-     appear at the second index.  */
-  fp_offset_idx = ((sframe_decoder_get_fixed_ra_offset (dctx)
-		    != SFRAME_CFA_FIXED_RA_INVALID)
-		   ? SFRAME_FRE_RA_OFFSET_IDX
-		   : SFRAME_FRE_FP_OFFSET_IDX);
+  /* Get the FP offset index and check that it is valid.  */
+  fp_offset_idx = sframe_get_fre_offset_index (fre->fre_info,
+					       SFRAME_FRE_FP_OFFSET_IDX);
+  if (fp_offset_idx == -1)
+    return sframe_set_errno (errp, SFRAME_ERR_FREOFFSET_NOPRESENT);
+
+  /* Otherwise, get the FP offset from the FRE.  */
   return sframe_get_fre_offset (fre, fp_offset_idx, errp);
 }
 
@@ -716,6 +738,7 @@ int32_t
 sframe_fre_get_ra_offset (sframe_decoder_ctx *dctx,
 			  sframe_frame_row_entry *fre, int *errp)
 {
+  int ra_offset_idx;
   int8_t ra_offset = sframe_decoder_get_fixed_ra_offset (dctx);
   /* If the RA offset was not being tracked, return the fixed RA offset
      from the SFrame header.  */
@@ -726,8 +749,14 @@ sframe_fre_get_ra_offset (sframe_decoder_ctx *dctx,
       return ra_offset;
     }
 
+  /* Get the RA offset index and check that it is valid.  */
+  ra_offset_idx = sframe_get_fre_offset_index (fre->fre_info,
+					       SFRAME_FRE_RA_OFFSET_IDX);
+  if (ra_offset_idx == -1)
+    return sframe_set_errno (errp, SFRAME_ERR_FREOFFSET_NOPRESENT);
+
   /* Otherwise, get the RA offset from the FRE.  */
-  return sframe_get_fre_offset (fre, SFRAME_FRE_RA_OFFSET_IDX, errp);
+  return sframe_get_fre_offset (fre, ra_offset_idx, errp);
 }
 
 /* Get whether the RA is mangled.  */
