|  | /* .sframe section processing. | 
|  | Copyright (C) 2022-2023 Free Software Foundation, Inc. | 
|  |  | 
|  | This file is part of BFD, the Binary File Descriptor library. | 
|  |  | 
|  | This program is free software; you can redistribute it and/or modify | 
|  | it under the terms of the GNU General Public License as published by | 
|  | the Free Software Foundation; either version 3 of the License, or | 
|  | (at your option) any later version. | 
|  |  | 
|  | This program is distributed in the hope that it will be useful, | 
|  | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | GNU General Public License for more details. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License | 
|  | along with this program; if not, write to the Free Software | 
|  | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, | 
|  | MA 02110-1301, USA.  */ | 
|  |  | 
|  | #include "sysdep.h" | 
|  | #include "bfd.h" | 
|  | #include "libbfd.h" | 
|  | #include "elf-bfd.h" | 
|  | #include "sframe-api.h" | 
|  |  | 
|  | /* Return TRUE if the function has been marked for deletion during the linking | 
|  | process.  */ | 
|  |  | 
|  | static bool | 
|  | sframe_decoder_func_deleted_p (struct sframe_dec_info *sfd_info, | 
|  | unsigned int func_idx) | 
|  | { | 
|  | if (func_idx < sfd_info->sfd_fde_count) | 
|  | return sfd_info->sfd_func_bfdinfo[func_idx].func_deleted_p; | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /* Mark the function in the decoder info for deletion.  */ | 
|  |  | 
|  | static void | 
|  | sframe_decoder_mark_func_deleted (struct sframe_dec_info *sfd_info, | 
|  | unsigned int func_idx) | 
|  | { | 
|  | if (func_idx < sfd_info->sfd_fde_count) | 
|  | sfd_info->sfd_func_bfdinfo[func_idx].func_deleted_p = true; | 
|  | } | 
|  |  | 
|  | /* Get the relocation offset from the decoder info for the given function.  */ | 
|  |  | 
|  | static unsigned int | 
|  | sframe_decoder_get_func_r_offset (struct sframe_dec_info *sfd_info, | 
|  | unsigned int func_idx) | 
|  | { | 
|  | BFD_ASSERT (func_idx < sfd_info->sfd_fde_count); | 
|  | unsigned int func_r_offset | 
|  | = sfd_info->sfd_func_bfdinfo[func_idx].func_r_offset; | 
|  | /* There must have been a reloc.  */ | 
|  | BFD_ASSERT (func_r_offset); | 
|  | return func_r_offset; | 
|  | } | 
|  |  | 
|  | /* Bookkeep the function relocation offset in the decoder info.  */ | 
|  |  | 
|  | static void | 
|  | sframe_decoder_set_func_r_offset (struct sframe_dec_info *sfd_info, | 
|  | unsigned int func_idx, | 
|  | unsigned int r_offset) | 
|  | { | 
|  | if (func_idx < sfd_info->sfd_fde_count) | 
|  | sfd_info->sfd_func_bfdinfo[func_idx].func_r_offset = r_offset; | 
|  | } | 
|  |  | 
|  | /* Get the relocation index in the elf_reloc_cookie for the function.  */ | 
|  |  | 
|  | static unsigned int | 
|  | sframe_decoder_get_func_reloc_index (struct sframe_dec_info *sfd_info, | 
|  | unsigned int func_idx) | 
|  | { | 
|  | BFD_ASSERT (func_idx < sfd_info->sfd_fde_count); | 
|  | return sfd_info->sfd_func_bfdinfo[func_idx].func_reloc_index; | 
|  | } | 
|  |  | 
|  | /* Bookkeep the relocation index in the elf_reloc_cookie for the function.  */ | 
|  |  | 
|  | static void | 
|  | sframe_decoder_set_func_reloc_index (struct sframe_dec_info *sfd_info, | 
|  | unsigned int func_idx, | 
|  | unsigned int reloc_index) | 
|  | { | 
|  | if (func_idx < sfd_info->sfd_fde_count) | 
|  | sfd_info->sfd_func_bfdinfo[func_idx].func_reloc_index = reloc_index; | 
|  | } | 
|  |  | 
|  | /* Initialize the set of additional information in CFD_INFO, | 
|  | needed for linking SEC.  Returns TRUE if setup is done successfully.  */ | 
|  |  | 
|  | static bool | 
|  | sframe_decoder_init_func_bfdinfo (asection *sec, | 
|  | struct sframe_dec_info *sfd_info, | 
|  | struct elf_reloc_cookie *cookie) | 
|  | { | 
|  | unsigned int fde_count; | 
|  | unsigned int func_bfdinfo_size, i; | 
|  |  | 
|  | fde_count = sframe_decoder_get_num_fidx (sfd_info->sfd_ctx); | 
|  | sfd_info->sfd_fde_count = fde_count; | 
|  |  | 
|  | /* Allocate and clear the memory.  */ | 
|  | func_bfdinfo_size = (sizeof (struct sframe_func_bfdinfo)) * fde_count; | 
|  | sfd_info->sfd_func_bfdinfo | 
|  | = (struct sframe_func_bfdinfo*) bfd_malloc (func_bfdinfo_size); | 
|  | if (sfd_info->sfd_func_bfdinfo == NULL) | 
|  | return false; | 
|  | memset (sfd_info->sfd_func_bfdinfo, 0, func_bfdinfo_size); | 
|  |  | 
|  | /* For linker generated .sframe sections, we have no relocs.  Skip.  */ | 
|  | if ((sec->flags & SEC_LINKER_CREATED) && cookie->rels == NULL) | 
|  | return true; | 
|  |  | 
|  | for (i = 0; i < fde_count; i++) | 
|  | { | 
|  | cookie->rel = cookie->rels + i; | 
|  | BFD_ASSERT (cookie->rel < cookie->relend); | 
|  | /* Bookkeep the relocation offset and relocation index of each function | 
|  | for later use.  */ | 
|  | sframe_decoder_set_func_r_offset (sfd_info, i, cookie->rel->r_offset); | 
|  | sframe_decoder_set_func_reloc_index (sfd_info, i, | 
|  | (cookie->rel - cookie->rels)); | 
|  |  | 
|  | cookie->rel++; | 
|  | } | 
|  | BFD_ASSERT (cookie->rel == cookie->relend); | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /* Read the value from CONTENTS at the specified OFFSET for the given ABFD.  */ | 
|  |  | 
|  | static bfd_vma | 
|  | sframe_read_value (bfd *abfd, bfd_byte *contents, unsigned int offset, | 
|  | unsigned int width) | 
|  | { | 
|  | BFD_ASSERT (contents && offset); | 
|  | /* Supporting the usecase of reading only the 4-byte relocated | 
|  | value (signed offset for func start addr) for now.  */ | 
|  | BFD_ASSERT (width == 4); | 
|  | /* FIXME endianness ?? */ | 
|  | unsigned char *buf = contents + offset; | 
|  | bfd_vma value = bfd_get_signed_32 (abfd, buf); | 
|  | return value; | 
|  | } | 
|  |  | 
|  | /* Return true if there is at least one non-empty .sframe section in | 
|  | input files.  Can only be called after ld has mapped input to | 
|  | output sections, and before sections are stripped.  */ | 
|  |  | 
|  | bool | 
|  | _bfd_elf_sframe_present (struct bfd_link_info *info) | 
|  | { | 
|  | asection *sframe = bfd_get_section_by_name (info->output_bfd, ".sframe"); | 
|  |  | 
|  | if (sframe == NULL) | 
|  | return false; | 
|  |  | 
|  | /* Count only sections which have at least a single FDE.  */ | 
|  | for (sframe = sframe->map_head.s; sframe != NULL; sframe = sframe->map_head.s) | 
|  | /* Note that this may become an approximate check in the future when | 
|  | some ABI/arch begin to use the sfh_auxhdr_len.  When sfh_auxhdr_len has | 
|  | non-zero value, it will need to be accounted for in the calculation of | 
|  | the SFrame header size.  */ | 
|  | if (sframe->size > sizeof (sframe_header)) | 
|  | return true; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /* Try to parse .sframe section SEC, which belongs to ABFD.  Store the | 
|  | information in the section's sec_info field on success.  COOKIE | 
|  | describes the relocations in SEC. | 
|  |  | 
|  | Returns TRUE if success, FALSE if any error or failure.  */ | 
|  |  | 
|  | bool | 
|  | _bfd_elf_parse_sframe (bfd *abfd, | 
|  | struct bfd_link_info *info ATTRIBUTE_UNUSED, | 
|  | asection *sec, struct elf_reloc_cookie *cookie) | 
|  | { | 
|  | bfd_byte *sfbuf = NULL; | 
|  | struct sframe_dec_info *sfd_info; | 
|  | sframe_decoder_ctx *sfd_ctx; | 
|  | bfd_size_type sf_size; | 
|  | int decerr = 0; | 
|  |  | 
|  | if (sec->size == 0 | 
|  | || (sec->flags & SEC_HAS_CONTENTS) == 0 | 
|  | || sec->sec_info_type != SEC_INFO_TYPE_NONE) | 
|  | { | 
|  | /* This file does not contain .sframe information.  */ | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (bfd_is_abs_section (sec->output_section)) | 
|  | { | 
|  | /* At least one of the sections is being discarded from the | 
|  | link, so we should just ignore them.  */ | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /* Read the SFrame stack trace information from abfd.  */ | 
|  | if (!bfd_malloc_and_get_section (abfd, sec, &sfbuf)) | 
|  | goto fail_no_free; | 
|  |  | 
|  | /* 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_malloc (sizeof (struct sframe_dec_info)); | 
|  | sf_size = sec->size; | 
|  |  | 
|  | sfd_info->sfd_ctx = sframe_decode ((const char*)sfbuf, sf_size, &decerr); | 
|  | sfd_ctx = sfd_info->sfd_ctx; | 
|  | if (!sfd_ctx) | 
|  | /* Free'ing up any memory held by decoder context is done by | 
|  | sframe_decode in case of error.  */ | 
|  | goto fail_no_free; | 
|  |  | 
|  | if (!sframe_decoder_init_func_bfdinfo (sec, sfd_info, cookie)) | 
|  | { | 
|  | sframe_decoder_free (&sfd_ctx); | 
|  | goto fail_no_free; | 
|  | } | 
|  |  | 
|  | elf_section_data (sec)->sec_info = sfd_info; | 
|  | sec->sec_info_type = SEC_INFO_TYPE_SFRAME; | 
|  |  | 
|  | goto success; | 
|  |  | 
|  | fail_no_free: | 
|  | _bfd_error_handler | 
|  | (_("error in %pB(%pA); no .sframe will be created"), | 
|  | abfd, sec); | 
|  | return false; | 
|  | success: | 
|  | free (sfbuf); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /* This function is called for each input file before the .sframe section | 
|  | is relocated.  It marks the SFrame FDE for the discarded functions for | 
|  | deletion. | 
|  |  | 
|  | The function returns TRUE iff any entries have been deleted.  */ | 
|  |  | 
|  | bool | 
|  | _bfd_elf_discard_section_sframe | 
|  | (asection *sec, | 
|  | bool (*reloc_symbol_deleted_p) (bfd_vma, void *), | 
|  | struct elf_reloc_cookie *cookie) | 
|  | { | 
|  | bool changed; | 
|  | bool keep; | 
|  | unsigned int i; | 
|  | unsigned int func_desc_offset; | 
|  | unsigned int num_fidx; | 
|  | struct sframe_dec_info *sfd_info; | 
|  |  | 
|  | changed = false; | 
|  | /* FIXME - if relocatable link and changed = true, how does the final | 
|  | .rela.sframe get updated ?.  */ | 
|  | keep = false; | 
|  |  | 
|  | sfd_info = (struct sframe_dec_info *) elf_section_data (sec)->sec_info; | 
|  |  | 
|  | /* Skip checking for the linker created .sframe sections | 
|  | (for PLT sections).  */ | 
|  | if ((sec->flags & SEC_LINKER_CREATED) == 0 || cookie->rels != NULL) | 
|  | { | 
|  | num_fidx = sframe_decoder_get_num_fidx (sfd_info->sfd_ctx); | 
|  | for (i = 0; i < num_fidx; i++) | 
|  | { | 
|  | func_desc_offset = sframe_decoder_get_func_r_offset (sfd_info, i); | 
|  |  | 
|  | cookie->rel = cookie->rels | 
|  | + sframe_decoder_get_func_reloc_index (sfd_info, i); | 
|  | keep = !(*reloc_symbol_deleted_p) (func_desc_offset, cookie); | 
|  |  | 
|  | if (!keep) | 
|  | { | 
|  | sframe_decoder_mark_func_deleted (sfd_info, i); | 
|  | changed = true; | 
|  | } | 
|  | } | 
|  | } | 
|  | return changed; | 
|  | } | 
|  |  | 
|  | /* Update the reference to the output .sframe section in the output ELF | 
|  | BFD ABFD.  Returns true if no error.  */ | 
|  |  | 
|  | bool | 
|  | _bfd_elf_set_section_sframe (bfd *abfd, | 
|  | struct bfd_link_info *info) | 
|  | { | 
|  | asection *cfsec; | 
|  |  | 
|  | cfsec = bfd_get_section_by_name (info->output_bfd, ".sframe"); | 
|  | if (!cfsec) | 
|  | return false; | 
|  |  | 
|  | elf_sframe (abfd) = cfsec; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /* Merge .sframe section SEC.  This is called with the relocated | 
|  | CONTENTS.  */ | 
|  |  | 
|  | bool | 
|  | _bfd_elf_merge_section_sframe (bfd *abfd, | 
|  | struct bfd_link_info *info, | 
|  | asection *sec, | 
|  | bfd_byte *contents) | 
|  | { | 
|  | struct sframe_dec_info *sfd_info; | 
|  | struct sframe_enc_info *sfe_info; | 
|  | sframe_decoder_ctx *sfd_ctx; | 
|  | sframe_encoder_ctx *sfe_ctx; | 
|  | uint8_t sfd_ctx_abi_arch; | 
|  | int8_t sfd_ctx_fixed_fp_offset; | 
|  | int8_t sfd_ctx_fixed_ra_offset; | 
|  | uint8_t dctx_version; | 
|  | uint8_t ectx_version; | 
|  | int encerr = 0; | 
|  |  | 
|  | struct elf_link_hash_table *htab; | 
|  | asection *cfsec; | 
|  |  | 
|  | /* Sanity check - handle SFrame sections only.  */ | 
|  | if (sec->sec_info_type != SEC_INFO_TYPE_SFRAME) | 
|  | return false; | 
|  |  | 
|  | sfd_info = (struct sframe_dec_info *) elf_section_data (sec)->sec_info; | 
|  | sfd_ctx = sfd_info->sfd_ctx; | 
|  |  | 
|  | htab = elf_hash_table (info); | 
|  | sfe_info = &(htab->sfe_info); | 
|  | sfe_ctx = sfe_info->sfe_ctx; | 
|  |  | 
|  | /* All input bfds are expected to have a valid SFrame section.  Even if | 
|  | the SFrame section is empty with only a header, there must be a valid | 
|  | SFrame decoder context by now.  The SFrame encoder context, however, | 
|  | will get set later here, if this is the first call to the function.  */ | 
|  | if (sfd_ctx == NULL || sfe_info == NULL) | 
|  | return false; | 
|  |  | 
|  | if (htab->sfe_info.sfe_ctx == NULL) | 
|  | { | 
|  | sfd_ctx_abi_arch = sframe_decoder_get_abi_arch (sfd_ctx); | 
|  | sfd_ctx_fixed_fp_offset = sframe_decoder_get_fixed_fp_offset (sfd_ctx); | 
|  | sfd_ctx_fixed_ra_offset = sframe_decoder_get_fixed_ra_offset (sfd_ctx); | 
|  |  | 
|  | /* Valid values are non-zero.  */ | 
|  | if (!sfd_ctx_abi_arch) | 
|  | return false; | 
|  |  | 
|  | htab->sfe_info.sfe_ctx = sframe_encode (SFRAME_VERSION_2, | 
|  | 0, /* SFrame flags.  */ | 
|  | sfd_ctx_abi_arch, | 
|  | sfd_ctx_fixed_fp_offset, | 
|  | sfd_ctx_fixed_ra_offset, | 
|  | &encerr); | 
|  | /* Handle errors from sframe_encode.  */ | 
|  | if (htab->sfe_info.sfe_ctx == NULL) | 
|  | return false; | 
|  | } | 
|  | sfe_ctx = sfe_info->sfe_ctx; | 
|  |  | 
|  | if (sfe_info->sframe_section == NULL) | 
|  | { | 
|  | /* Make sure things are set for an eventual write. | 
|  | Size of the output section is not known until | 
|  | _bfd_elf_write_section_sframe is ready with the buffer | 
|  | to write out.  */ | 
|  | cfsec = bfd_get_section_by_name (info->output_bfd, ".sframe"); | 
|  | if (cfsec) | 
|  | { | 
|  | sfe_info->sframe_section = cfsec; | 
|  | // elf_sframe (abfd) = cfsec; | 
|  | } | 
|  | else | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /* Check that all .sframe sections being linked have the same | 
|  | ABI/arch.  */ | 
|  | if (sframe_decoder_get_abi_arch (sfd_ctx) | 
|  | != sframe_encoder_get_abi_arch (sfe_ctx)) | 
|  | { | 
|  | _bfd_error_handler | 
|  | (_("input SFrame sections with different abi prevent .sframe" | 
|  | " generation")); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /* Check that all .sframe sections being linked have the same version.  */ | 
|  | dctx_version = sframe_decoder_get_version (sfd_ctx); | 
|  | ectx_version = sframe_encoder_get_version (sfe_ctx); | 
|  | if (dctx_version != SFRAME_VERSION_2 || dctx_version != ectx_version) | 
|  | { | 
|  | _bfd_error_handler | 
|  | (_("input SFrame sections with different format versions prevent" | 
|  | " .sframe generation")); | 
|  | return false; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Iterate over the function descriptor entries and the FREs of the | 
|  | function from the decoder context.  Add each of them to the encoder | 
|  | context, if suitable.  */ | 
|  | uint32_t i = 0, j = 0, cur_fidx = 0; | 
|  |  | 
|  | uint32_t num_fidx = sframe_decoder_get_num_fidx (sfd_ctx); | 
|  | uint32_t num_enc_fidx = sframe_encoder_get_num_fidx (sfe_ctx); | 
|  |  | 
|  | for (i = 0; i < num_fidx; i++) | 
|  | { | 
|  | unsigned int num_fres = 0; | 
|  | int32_t func_start_addr; | 
|  | bfd_vma address; | 
|  | uint32_t func_size = 0; | 
|  | unsigned char func_info = 0; | 
|  | unsigned int r_offset = 0; | 
|  | bool pltn_reloc_by_hand = false; | 
|  | unsigned int pltn_r_offset = 0; | 
|  | uint8_t rep_block_size = 0; | 
|  |  | 
|  | if (!sframe_decoder_get_funcdesc_v2 (sfd_ctx, i, &num_fres, &func_size, | 
|  | &func_start_addr, &func_info, | 
|  | &rep_block_size)) | 
|  | { | 
|  | /* If function belongs to a deleted section, skip editing the | 
|  | function descriptor entry.  */ | 
|  | if (sframe_decoder_func_deleted_p(sfd_info, i)) | 
|  | continue; | 
|  |  | 
|  | /* Don't edit function descriptor entries for relocatable link.  */ | 
|  | if (!bfd_link_relocatable (info)) | 
|  | { | 
|  | if (!(sec->flags & SEC_LINKER_CREATED)) | 
|  | { | 
|  | /* Get relocated contents by reading the value of the | 
|  | relocated function start address at the beginning of the | 
|  | function descriptor entry.  */ | 
|  | r_offset = sframe_decoder_get_func_r_offset (sfd_info, i); | 
|  | } | 
|  | else | 
|  | { | 
|  | /* Expected to land here when SFrame stack trace info is | 
|  | created dynamically for the .plt* sections.  These | 
|  | sections are expected to have upto two SFrame FDE entries. | 
|  | Although the code should work for > 2,  leaving this | 
|  | assert here for safety.  */ | 
|  | BFD_ASSERT (num_fidx <= 2); | 
|  | /* For the first entry, we know the offset of the SFrame FDE's | 
|  | sfde_func_start_address.  Side note: see how the value | 
|  | of PLT_SFRAME_FDE_START_OFFSET is also set to the | 
|  | same.  */ | 
|  | r_offset = sframe_decoder_get_hdr_size (sfd_ctx); | 
|  | /* For any further SFrame FDEs, the generator has already put | 
|  | in an offset in place of sfde_func_start_address of the | 
|  | corresponding FDE.  We will use it by hand to relocate.  */ | 
|  | if (i > 0) | 
|  | { | 
|  | pltn_r_offset | 
|  | = r_offset + (i * sizeof (sframe_func_desc_entry)); | 
|  | pltn_reloc_by_hand = true; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Get the SFrame FDE function start address after relocation.  */ | 
|  | address = sframe_read_value (abfd, contents, r_offset, 4); | 
|  | if (pltn_reloc_by_hand) | 
|  | address += sframe_read_value (abfd, contents, | 
|  | pltn_r_offset, 4); | 
|  | address += (sec->output_offset + r_offset); | 
|  |  | 
|  | /* FIXME For testing only. Cleanup later.  */ | 
|  | // address += (sec->output_section->vma); | 
|  |  | 
|  | func_start_addr = address; | 
|  | } | 
|  |  | 
|  | /* Update the encoder context with updated content.  */ | 
|  | int err = sframe_encoder_add_funcdesc_v2 (sfe_ctx, func_start_addr, | 
|  | func_size, func_info, | 
|  | rep_block_size, num_fres); | 
|  | cur_fidx++; | 
|  | BFD_ASSERT (!err); | 
|  | } | 
|  |  | 
|  | for (j = 0; j < num_fres; j++) | 
|  | { | 
|  | sframe_frame_row_entry fre; | 
|  | if (!sframe_decoder_get_fre (sfd_ctx, i, j, &fre)) | 
|  | { | 
|  | int err = sframe_encoder_add_fre (sfe_ctx, | 
|  | cur_fidx-1+num_enc_fidx, | 
|  | &fre); | 
|  | BFD_ASSERT (!err); | 
|  | } | 
|  | } | 
|  | } | 
|  | /* Free the SFrame decoder context.  */ | 
|  | sframe_decoder_free (&sfd_ctx); | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /* Write out the .sframe section.  This must be called after | 
|  | _bfd_elf_merge_section_sframe has been called on all input | 
|  | .sframe sections.  */ | 
|  |  | 
|  | bool | 
|  | _bfd_elf_write_section_sframe (bfd *abfd, struct bfd_link_info *info) | 
|  | { | 
|  | bool retval = true; | 
|  |  | 
|  | struct elf_link_hash_table *htab; | 
|  | struct sframe_enc_info *sfe_info; | 
|  | sframe_encoder_ctx *sfe_ctx; | 
|  | asection *sec; | 
|  | void *contents; | 
|  | size_t sec_size; | 
|  | int err = 0; | 
|  |  | 
|  | htab = elf_hash_table (info); | 
|  | sfe_info = &htab->sfe_info; | 
|  | sec = sfe_info->sframe_section; | 
|  | sfe_ctx = sfe_info->sfe_ctx; | 
|  |  | 
|  | if (sec == NULL) | 
|  | return true; | 
|  |  | 
|  | contents = sframe_encoder_write (sfe_ctx, &sec_size, &err); | 
|  | sec->size = (bfd_size_type) sec_size; | 
|  |  | 
|  | if (!bfd_set_section_contents (abfd, sec->output_section, contents, | 
|  | (file_ptr) sec->output_offset, | 
|  | sec->size)) | 
|  | retval = false; | 
|  | else if (!bfd_link_relocatable (info)) | 
|  | { | 
|  | Elf_Internal_Shdr *hdr = &elf_section_data (sec)->this_hdr; | 
|  | hdr->sh_size = sec->size; | 
|  | } | 
|  | /* For relocatable links, do not update the section size as the section | 
|  | contents have not been relocated.  */ | 
|  |  | 
|  | sframe_encoder_free (&sfe_ctx); | 
|  |  | 
|  | return retval; | 
|  | } |