aboutsummaryrefslogtreecommitdiff
path: root/bfd/elfxx-x86.c
diff options
context:
space:
mode:
Diffstat (limited to 'bfd/elfxx-x86.c')
-rw-r--r--bfd/elfxx-x86.c375
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