unsigned int func_reloc_index;
};
+/* Link state information of the SFrame section. */
+enum sframe_sec_state
+{
+ SFRAME_SEC_DECODED = 1,
+ SFRAME_SEC_MERGED,
+};
+
/* SFrame decoder info.
Contains all information for a decoded .sframe section. */
struct sframe_dec_info
{
/* Decoder context. */
struct sframe_decoder_ctx *sfd_ctx;
+ /* SFrame section state as it progresses through the link process. */
+ enum sframe_sec_state sfd_state;
/* Number of function descriptor entries in this .sframe. */
unsigned int sfd_fde_count;
/* Additional information for linking. */
(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 *);
/* Decode the buffer and keep decoded contents for later use.
Relocations are performed later, but are such that the section's
size is unaffected. */
- sfd_info = bfd_alloc (abfd, sizeof (*sfd_info));
+ sfd_info = bfd_zalloc (abfd, sizeof (*sfd_info));
sf_size = sec->size;
sfd_info->sfd_ctx = sframe_decode ((const char*)sfbuf, sf_size, &decerr);
+ sfd_info->sfd_state = SFRAME_SEC_DECODED;
sfd_ctx = sfd_info->sfd_ctx;
if (!sfd_ctx)
/* Free'ing up any memory held by decoder context is done by
}
}
}
+ sfd_info->sfd_state = SFRAME_SEC_MERGED;
/* Free the SFrame decoder context. */
sframe_decoder_free (&sfd_ctx);
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. Note how it uses
+ sframe_encoder_get_num_fidx () to figure out the offset of FDE
+ in the output section. */
+
+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_num_fdes;
+ unsigned int sfd_num_fdes, sfe_num_fdes;
+ uint32_t sfd_fde_offset;
+ bfd_vma new_offset;
+
+ 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;
+ sfd_num_fdes = sframe_decoder_get_num_fidx (sfd_ctx);
+
+ BFD_ASSERT (sfd_info->sfd_state == SFRAME_SEC_DECODED);
+
+ 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);
+
+ /* The index of this FDE in the output section depends on number of deleted
+ functions (between index 0 and sec_fde_idx), if any. */
+ out_num_fdes = 0;
+ sec_fde_idx = 0;
+ for (unsigned int i = 0; i < sfd_num_fdes; i++)
+ {
+ sfd_fde_offset = sframe_decoder_get_offsetof_fde_start_addr (sfd_ctx,
+ i, NULL);
+ if (!sframe_decoder_func_deleted_p (sfd_info, i))
+ out_num_fdes++;
+
+ if (sfd_fde_offset == offset)
+ {
+ /* Found the index of the FDE (at OFFSET) in the input section. */
+ sec_fde_idx = i;
+ break;
+ }
+ }
+
+ if (sframe_decoder_func_deleted_p (sfd_info, sec_fde_idx))
+ return (bfd_vma) -1;
+
+ /* The number of FDEs in the output SFrame section. Note that the output
+ index of the FDE of interest will be (out_num_fdes - 1). */
+ out_num_fdes += sfe_num_fdes;
+
+ new_offset = sframe_decoder_get_offsetof_fde_start_addr (sfd_ctx,
+ out_num_fdes - 1,
+ NULL);
+ /* Recall that SFrame section merging has distinct requirements: All SFrame
+ FDEs from input sections are clubbed together in the beginning of the
+ output section. So, at this point in the current function, the new_offset
+ is the correct offset in the merged output SFrame section. Note, however,
+ that the default mechanism in the _elf_link_input_bfd will do the
+ following adjustment:
+ irela->r_offset += o->output_offset;
+ for all section types. However, such an adjustment in the RELA offset is
+ _not_ needed for SFrame sections. Perform the reverse adjustment here so
+ that the default mechanism does not need additional SFrame specific
+ checks. */
+ new_offset -= sec->output_offset;
+
+ return new_offset;
+}
+
/* Write out the .sframe section. This must be called after
_bfd_elf_merge_section_sframe has been called on all input
.sframe sections. */
--- /dev/null
+#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,
+ SFRAME_F_FDE_FUNC_START_ADDR_PCREL
+ 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 +