diff options
Diffstat (limited to 'bfd/elfxx-x86.c')
-rw-r--r-- | bfd/elfxx-x86.c | 375 |
1 files changed, 371 insertions, 4 deletions
diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c index 7fb9727..c48d038 100644 --- a/bfd/elfxx-x86.c +++ b/bfd/elfxx-x86.c @@ -1777,6 +1777,191 @@ elf_x86_relative_reloc_compare (const void *pa, const void *pb) return 0; } +enum dynobj_sframe_plt_type +{ + SFRAME_PLT = 1, + SFRAME_PLT_SEC = 2 +}; + +/* Create SFrame unwind info for the plt entries in the .plt section + of type PLT_SEC_TYPE. */ + +static bool +_bfd_x86_elf_create_sframe_plt (bfd *output_bfd, + struct bfd_link_info *info, + unsigned int plt_sec_type) +{ + struct elf_x86_link_hash_table *htab; + const struct elf_backend_data *bed; + + bool plt0_generated_p; + unsigned int plt0_entry_size; + unsigned char func_info; + unsigned int fre_type; + /* The dynamic plt section for which .sframe unwind information is being + created. */ + asection *dpltsec; + + int err = 0; + + sframe_encoder_ctx **ectx = NULL; + unsigned plt_entry_size = 0; + unsigned int num_pltn_fres = 0; + unsigned int num_pltn_entries = 0; + + bed = get_elf_backend_data (output_bfd); + htab = elf_x86_hash_table (info, bed->target_id); + /* Whether SFrame unwind info for plt0 is to be generated. */ + plt0_generated_p = htab->plt.has_plt0; + plt0_entry_size + = (plt0_generated_p) ? htab->sframe_plt->plt0_entry_size : 0; + + switch (plt_sec_type) + { + case SFRAME_PLT: + { + ectx = &htab->plt_cfe_ctx; + dpltsec = htab->elf.splt; + + plt_entry_size = htab->plt.plt_entry_size; + num_pltn_fres = htab->sframe_plt->pltn_num_fres; + num_pltn_entries + = (htab->elf.splt->size - plt0_entry_size) / plt_entry_size; + + break; + } + case SFRAME_PLT_SEC: + { + ectx = &htab->plt_second_cfe_ctx; + /* FIXME - this or htab->plt_second_sframe ? */ + dpltsec = htab->plt_second_eh_frame; + + plt_entry_size = htab->sframe_plt->sec_pltn_entry_size; + num_pltn_fres = htab->sframe_plt->sec_pltn_num_fres; + num_pltn_entries + = htab->plt_second_eh_frame->size / plt_entry_size; + break; + } + default: + /* No other value is possible. */ + return false; + break; + } + + *ectx = sframe_encode (SFRAME_VERSION_1, + 0, + SFRAME_ABI_AMD64_ENDIAN_LITTLE, + SFRAME_CFA_FIXED_FP_INVALID, + -8, /* Fixed RA offset. */ + &err); + + /* FRE type is dependent on the size of the function. */ + fre_type = sframe_calc_fre_type (dpltsec->size); + func_info = sframe_fde_func_info (fre_type, + SFRAME_FDE_TYPE_PCINC); + + /* Add SFrame FDE and the associated FREs for plt0 if plt0 has been + generated. */ + if (plt0_generated_p) + { + /* Add SFrame FDE for plt0, the function start address is updated later + at _bfd_elf_merge_section_sframe time. */ + sframe_encoder_add_funcdesc (*ectx, + 0, /* func start addr. */ + plt0_entry_size, + func_info, + 0 /* Num FREs. */); + sframe_frame_row_entry plt0_fre; + unsigned int num_plt0_fres = htab->sframe_plt->plt0_num_fres; + for (unsigned int j = 0; j < num_plt0_fres; j++) + { + plt0_fre = *(htab->sframe_plt->plt0_fres[j]); + sframe_encoder_add_fre (*ectx, 0, &plt0_fre); + } + } + + + if (num_pltn_entries) + { + /* pltn entries use an SFrame FDE of type + SFRAME_FDE_TYPE_PCMASK to exploit the repetitive + pattern of the instructions in these entries. Using this SFrame FDE + type helps in keeping the unwind information for pltn entries + compact. */ + func_info = sframe_fde_func_info (fre_type, SFRAME_FDE_TYPE_PCMASK); + /* Add the SFrame FDE for all PCs starting at the first pltn entry (hence, + function start address = plt0_entry_size. As usual, this will be + updated later at _bfd_elf_merge_section_sframe, by when the + sections are relocated. */ + sframe_encoder_add_funcdesc (*ectx, + plt0_entry_size, /* func start addr. */ + dpltsec->size - plt0_entry_size, + func_info, + 0 /* Num FREs. */); + + sframe_frame_row_entry pltn_fre; + /* Now add the FREs for pltn. Simply adding the two FREs suffices due + to the usage of SFRAME_FDE_TYPE_PCMASK above. */ + for (unsigned int j = 0; j < num_pltn_fres; j++) + { + pltn_fre = *(htab->sframe_plt->pltn_fres[j]); + sframe_encoder_add_fre (*ectx, 1, &pltn_fre); + } + } + + return true; +} + +/* Put contents of the .sframe section corresponding to the specified + PLT_SEC_TYPE. */ + +static bool +_bfd_x86_elf_write_sframe_plt (bfd *output_bfd, + struct bfd_link_info *info, + unsigned int plt_sec_type) +{ + struct elf_x86_link_hash_table *htab; + const struct elf_backend_data *bed; + sframe_encoder_ctx *ectx; + size_t sec_size; + asection *sec; + bfd *dynobj; + + int err = 0; + + bed = get_elf_backend_data (output_bfd); + htab = elf_x86_hash_table (info, bed->target_id); + dynobj = htab->elf.dynobj; + + switch (plt_sec_type) + { + case SFRAME_PLT: + ectx = htab->plt_cfe_ctx; + sec = htab->plt_sframe; + break; + case SFRAME_PLT_SEC: + ectx = htab->plt_second_cfe_ctx; + sec = htab->plt_second_sframe; + break; + default: + /* No other value is possible. */ + return false; + break; + } + + BFD_ASSERT (ectx); + + void *contents = sframe_encoder_write (ectx, &sec_size, &err); + + sec->size = (bfd_size_type) sec_size; + sec->contents = (unsigned char *) bfd_zalloc (dynobj, sec->size); + memcpy (sec->contents, contents, sec_size); + + sframe_encoder_free (&ectx); + + return true; +} + bool _bfd_elf_x86_size_relative_relocs (struct bfd_link_info *info, bool *need_layout) @@ -2267,6 +2452,42 @@ _bfd_x86_elf_size_dynamic_sections (bfd *output_bfd, = htab->non_lazy_plt->eh_frame_plt_size; } + /* No need to size the .sframe section explicitly because the write-out + mechanism is different. Simply prep up the FDE/FRE for the + .plt section. */ + if (_bfd_elf_sframe_present (info)) + { + if (htab->plt_sframe != NULL + && htab->elf.splt != NULL + && htab->elf.splt->size != 0 + && !bfd_is_abs_section (htab->elf.splt->output_section)) + { + _bfd_x86_elf_create_sframe_plt (output_bfd, info, SFRAME_PLT); + /* FIXME - Dirty Hack. Set the size to something non-zero for now, + so that the section does not get stripped out below. The precise + size of this section is known only when the contents are + serialized in _bfd_x86_elf_write_sframe_plt. */ + htab->plt_sframe->size = sizeof (sframe_header) + 1; + } + + /* FIXME - generate for .got.plt ? */ + + /* Unwind info for the second PLT. */ + if (htab->plt_second_sframe != NULL + && htab->plt_second != NULL + && htab->plt_second->size != 0 + && !bfd_is_abs_section (htab->plt_second->output_section)) + { + _bfd_x86_elf_create_sframe_plt (output_bfd, info, + SFRAME_PLT_SEC); + /* FIXME - Dirty Hack. Set the size to something non-zero for now, + so that the section does not get stripped out below. The precise + size of this section is known only when the contents are + serialized in _bfd_x86_elf_write_sframe_plt. */ + htab->plt_second_sframe->size = sizeof (sframe_header) + 1; + } + } + /* We now have determined the sizes of the various dynamic sections. Allocate memory for them. */ relocs = false; @@ -2302,6 +2523,8 @@ _bfd_x86_elf_size_dynamic_sections (bfd *output_bfd, || s == htab->plt_eh_frame || s == htab->plt_got_eh_frame || s == htab->plt_second_eh_frame + || s == htab->plt_sframe + || s == htab->plt_second_sframe || s == htab->elf.sdynbss || s == htab->elf.sdynrelro) { @@ -2344,6 +2567,11 @@ _bfd_x86_elf_size_dynamic_sections (bfd *output_bfd, if ((s->flags & SEC_HAS_CONTENTS) == 0) continue; + /* Skip allocating contents for .sframe section as it is written + out differently. See below. */ + if ((s == htab->plt_sframe) || (s == htab->plt_second_sframe)) + continue; + /* NB: Initially, the iplt section has minimal alignment to avoid moving dot of the following section backwards when it is empty. Update its section alignment now since it @@ -2393,6 +2621,21 @@ _bfd_x86_elf_size_dynamic_sections (bfd *output_bfd, + PLT_FDE_LEN_OFFSET)); } + if (_bfd_elf_sframe_present (info)) + { + if (htab->plt_sframe != NULL + && htab->elf.splt != NULL + && htab->elf.splt->size != 0 + && htab->plt_sframe->contents == NULL) + _bfd_x86_elf_write_sframe_plt (output_bfd, info, SFRAME_PLT); + + if (htab->plt_second_sframe != NULL + && htab->elf.splt != NULL + && htab->elf.splt->size != 0 + && htab->plt_second_sframe->contents == NULL) + _bfd_x86_elf_write_sframe_plt (output_bfd, info, SFRAME_PLT_SEC); + } + return _bfd_elf_maybe_vxworks_add_dynamic_tags (output_bfd, info, relocs); } @@ -2607,6 +2850,74 @@ _bfd_x86_elf_finish_dynamic_sections (bfd *output_bfd, } } + /* Make any adjustment if necessary and merge .sframe section to + create the final .sframe section for output_bfd. */ + if (htab->plt_sframe != NULL + && htab->plt_sframe->contents != NULL) + { + if (htab->elf.splt != NULL + && htab->elf.splt->size != 0 + && (htab->elf.splt->flags & SEC_EXCLUDE) == 0 + && htab->elf.splt->output_section != NULL + && htab->plt_sframe->output_section != NULL) + { + bfd_vma plt_start = htab->elf.splt->output_section->vma; + bfd_vma sframe_start = htab->plt_sframe->output_section->vma + + htab->plt_sframe->output_offset + + PLT_SFRAME_FDE_START_OFFSET; +#if 0 /* FIXME Testing only. Remove before review. */ + bfd_vma test_value = (plt_start - sframe_start) + + htab->plt_sframe->output_section->vma + + htab->plt_sframe->output_offset + + PLT_SFRAME_FDE_START_OFFSET; + bfd_put_signed_32 (dynobj, test_value, +#endif + bfd_put_signed_32 (dynobj, plt_start - sframe_start, + htab->plt_sframe->contents + + PLT_SFRAME_FDE_START_OFFSET); + } + if (htab->plt_sframe->sec_info_type == SEC_INFO_TYPE_SFRAME) + { + if (! _bfd_elf_merge_section_sframe (output_bfd, info, + htab->plt_sframe, + htab->plt_sframe->contents)) + return NULL; + } + } + + if (htab->plt_second_sframe != NULL + && htab->plt_second_sframe->contents != NULL) + { + if (htab->plt_second != NULL + && htab->plt_second->size != 0 + && (htab->plt_second->flags & SEC_EXCLUDE) == 0 + && htab->plt_second->output_section != NULL + && htab->plt_second_sframe->output_section != NULL) + { + bfd_vma plt_start = htab->plt_second->output_section->vma; + bfd_vma sframe_start + = (htab->plt_second_sframe->output_section->vma + + htab->plt_second_sframe->output_offset + + PLT_SFRAME_FDE_START_OFFSET); +#if 0 /* FIXME Testing only. Remove before review. */ + bfd_vma test_value = (plt_start - sframe_start) + + htab->plt_second_sframe->output_section->vma + + htab->plt_second_sframe->output_offset + + PLT_SFRAME_FDE_START_OFFSET; + bfd_put_signed_32 (dynobj, test_value, +#endif + bfd_put_signed_32 (dynobj, plt_start - sframe_start, + htab->plt_second_sframe->contents + + PLT_SFRAME_FDE_START_OFFSET); + } + if (htab->plt_second_sframe->sec_info_type == SEC_INFO_TYPE_SFRAME) + { + if (! _bfd_elf_merge_section_sframe (output_bfd, info, + htab->plt_second_sframe, + htab->plt_second_sframe->contents)) + return NULL; + } + } if (htab->elf.sgot && htab->elf.sgot->size > 0) elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize = htab->got_entry_size; @@ -3949,12 +4260,36 @@ _bfd_x86_elf_link_setup_gnu_properties pltsec = htab->elf.splt; - /* If the non-lazy PLT is available, use it for all PLT entries if - there are no PLT0 or no .plt section. */ if (htab->non_lazy_plt != NULL && (!htab->plt.has_plt0 || pltsec == NULL)) + lazy_plt = false; + else + lazy_plt = true; + + if (normal_target) + { + if (use_ibt_plt) + { + if (lazy_plt) + htab->sframe_plt = init_table->sframe_lazy_ibt_plt; + else + htab->sframe_plt = init_table->sframe_non_lazy_ibt_plt; + } + else + { + if (lazy_plt) + htab->sframe_plt = init_table->sframe_lazy_plt; + else + htab->sframe_plt = init_table->sframe_non_lazy_plt; + } + } + else + htab->sframe_plt = NULL; + + /* If the non-lazy PLT is available, use it for all PLT entries if + there are no PLT0 or no .plt section. */ + if (!lazy_plt) { - lazy_plt = false; if (bfd_link_pic (info)) htab->plt.plt_entry = htab->non_lazy_plt->pic_plt_entry; else @@ -3969,7 +4304,6 @@ _bfd_x86_elf_link_setup_gnu_properties } else { - lazy_plt = true; if (bfd_link_pic (info)) { htab->plt.plt0_entry = htab->lazy_plt->pic_plt0_entry; @@ -4145,6 +4479,39 @@ _bfd_x86_elf_link_setup_gnu_properties htab->plt_second_eh_frame = sec; } } + + /* .sframe sections are emitted for AMD64 ABI only. */ + if (ABI_64_P (info->output_bfd) && !info->no_ld_generated_unwind_info) + { + flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY + | SEC_HAS_CONTENTS | SEC_IN_MEMORY + | SEC_LINKER_CREATED); + + sec = bfd_make_section_anyway_with_flags (dynobj, + ".sframe", + flags); + if (sec == NULL) + info->callbacks->einfo (_("%F%P: failed to create PLT .sframe section\n")); + + // FIXME check this + // if (!bfd_set_section_alignment (sec, class_align)) + // goto error_alignment; + + htab->plt_sframe = sec; + + /* Second PLT is generated for Intel IBT / MPX Support + lazy plt. */ + if (htab->plt_second != NULL) + { + sec = bfd_make_section_anyway_with_flags (dynobj, + ".sframe", + flags); + if (sec == NULL) + info->callbacks->einfo (_("%F%P: failed to create second PLT .sframe section\n")); + + htab->plt_second_sframe = sec; + } + /* FIXME - add later for plt_got. */ + } } /* The .iplt section is used for IFUNC symbols in static |