From 25e762b98d2a9891b27043cde93d733287950465 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 28 Jul 2011 18:47:56 +0000 Subject: [PATCH] Parameterize elf32-i386 PLT generation: * elf32-i386.c (struct elf_i386_plt_layout): New type. (GET_PLT_ENTRY_SIZE): New macro. (elf_i386_plt): New variable. (struct elf_i386_backend_data): New member `plt'. (elf_i386_arch_bed): Add initializer for it. (elf_i386_vxworks_arch_bed): Likewise. (elf_i386_allocate_dynrelocs): Use GET_PLT_ENTRY_SIZE. (elf_i386_plt_sym_val): Likewise. (elf_i386_relocate_section): Likewise. (elf_i386_finish_dynamic_symbol): Likewise. Also use other elf_i386_plt_layout members for PLT details. (elf_i386_finish_dynamic_sections): Likewise. --- bfd/ChangeLog | 13 ++++ bfd/elf32-i386.c | 169 +++++++++++++++++++++++++++++++++++------------ 2 files changed, 138 insertions(+), 44 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 0e52185159a..f1885cb1338 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,5 +1,18 @@ 2011-07-28 Roland McGrath + * elf32-i386.c (struct elf_i386_plt_layout): New type. + (GET_PLT_ENTRY_SIZE): New macro. + (elf_i386_plt): New variable. + (struct elf_i386_backend_data): New member `plt'. + (elf_i386_arch_bed): Add initializer for it. + (elf_i386_vxworks_arch_bed): Likewise. + (elf_i386_allocate_dynrelocs): Use GET_PLT_ENTRY_SIZE. + (elf_i386_plt_sym_val): Likewise. + (elf_i386_relocate_section): Likewise. + (elf_i386_finish_dynamic_symbol): Likewise. + Also use other elf_i386_plt_layout members for PLT details. + (elf_i386_finish_dynamic_sections): Likewise. + * elf32-i386.c (struct elf_i386_backend_data): New type. (get_elf_i386_backend_data): New macro. (elf_i386_arch_bed): New variable. diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index 39050eca8ac..cb16fafafc5 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -614,6 +614,62 @@ static const bfd_byte elf_i386_eh_frame_plt[] = DW_CFA_nop, DW_CFA_nop, DW_CFA_nop, DW_CFA_nop }; +struct elf_i386_plt_layout +{ + /* The first entry in an absolute procedure linkage table looks like this. */ + const bfd_byte *plt0_entry; + unsigned int plt0_entry_size; + + /* Offsets into plt0_entry that are to be replaced with GOT[1] and GOT[2]. */ + unsigned int plt0_got1_offset; + unsigned int plt0_got2_offset; + + /* Later entries in an absolute procedure linkage table look like this. */ + const bfd_byte *plt_entry; + unsigned int plt_entry_size; + + /* Offsets into plt_entry that are to be replaced with... */ + unsigned int plt_got_offset; /* ... address of this symbol in .got. */ + unsigned int plt_reloc_offset; /* ... offset into relocation table. */ + unsigned int plt_plt_offset; /* ... offset to start of .plt. */ + + /* Offset into plt_entry where the initial value of the GOT entry points. */ + unsigned int plt_lazy_offset; + + /* The first entry in a PIC procedure linkage table looks like this. */ + const bfd_byte *pic_plt0_entry; + + /* Subsequent entries in a PIC procedure linkage table look like this. */ + const bfd_byte *pic_plt_entry; + + /* .eh_frame covering the .plt section. */ + const bfd_byte *eh_frame_plt; + unsigned int eh_frame_plt_size; +}; + +#define GET_PLT_ENTRY_SIZE(abfd) \ + get_elf_i386_backend_data (abfd)->plt->plt_entry_size + +/* These are the standard parameters. */ +static const struct elf_i386_plt_layout elf_i386_plt = + { + elf_i386_plt0_entry, /* plt0_entry */ + sizeof (elf_i386_plt0_entry), /* plt0_entry_size */ + 2, /* plt0_got1_offset */ + 8, /* plt0_got2_offset */ + elf_i386_plt_entry, /* plt_entry */ + PLT_ENTRY_SIZE, /* plt_entry_size */ + 2, /* plt_got_offset */ + 7, /* plt_reloc_offset */ + 12, /* plt_plt_offset */ + 6, /* plt_lazy_offset */ + elf_i386_pic_plt0_entry, /* pic_plt0_entry */ + elf_i386_pic_plt_entry, /* pic_plt_entry */ + elf_i386_eh_frame_plt, /* eh_frame_plt */ + sizeof (elf_i386_eh_frame_plt), /* eh_frame_plt_size */ + }; + + /* On VxWorks, the .rel.plt.unloaded section has absolute relocations for the PLTResolve stub and then for each PLT entry. */ #define PLTRESOLVE_RELOCS_SHLIB 0 @@ -624,6 +680,9 @@ static const bfd_byte elf_i386_eh_frame_plt[] = struct elf_i386_backend_data { + /* Parameters describing PLT generation. */ + const struct elf_i386_plt_layout *plt; + /* Value used to fill the unused bytes of the first PLT entry. */ bfd_byte plt0_pad_byte; @@ -638,6 +697,7 @@ struct elf_i386_backend_data /* These are the standard parameters. */ static const struct elf_i386_backend_data elf_i386_arch_bed = { + &elf_i386_plt, /* plt */ 0, /* plt0_pad_byte */ 0, /* is_vxworks */ }; @@ -2157,6 +2217,7 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) struct elf_i386_link_hash_table *htab; struct elf_i386_link_hash_entry *eh; struct elf_dyn_relocs *p; + unsigned plt_entry_size; if (h->root.type == bfd_link_hash_indirect) return TRUE; @@ -2168,13 +2229,14 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) if (htab == NULL) return FALSE; + plt_entry_size = GET_PLT_ENTRY_SIZE (info->output_bfd); + /* Since STT_GNU_IFUNC symbol must go through PLT, we handle it here if it is defined and referenced in a non-shared object. */ if (h->type == STT_GNU_IFUNC && h->def_regular) - return _bfd_elf_allocate_ifunc_dyn_relocs (info, h, - &eh->dyn_relocs, - PLT_ENTRY_SIZE, 4); + return _bfd_elf_allocate_ifunc_dyn_relocs (info, h, &eh->dyn_relocs, + plt_entry_size, 4); else if (htab->elf.dynamic_sections_created && h->plt.refcount > 0) { @@ -2195,7 +2257,7 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) /* If this is the first .plt entry, make room for the special first entry. */ if (s->size == 0) - s->size += PLT_ENTRY_SIZE; + s->size += plt_entry_size; h->plt.offset = s->size; @@ -2212,7 +2274,7 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) } /* Make room for this entry. */ - s->size += PLT_ENTRY_SIZE; + s->size += plt_entry_size; /* We also need to make an entry in the .got.plt section, which will be placed in the .got section by the linker script. */ @@ -2233,7 +2295,7 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) R_386_32 relocation for _GLOBAL_OFFSET_TABLE_ + 4 and an R_386_32 relocation for _GLOBAL_OFFSET_TABLE_ + 8. */ - if (h->plt.offset == PLT_ENTRY_SIZE) + if (h->plt.offset == plt_entry_size) htab->srelplt2->size += (sizeof (Elf32_External_Rel) * 2); /* There are two extra relocations for each subsequent PLT entry: @@ -2959,6 +3021,7 @@ elf_i386_relocate_section (bfd *output_bfd, Elf_Internal_Rela *rel; Elf_Internal_Rela *relend; bfd_boolean is_vxworks_tls; + unsigned plt_entry_size; BFD_ASSERT (is_i386_elf (input_bfd)); @@ -2978,6 +3041,8 @@ elf_i386_relocate_section (bfd *output_bfd, elf_i386_set_tls_module_base (info); + plt_entry_size = GET_PLT_ENTRY_SIZE (output_bfd); + rel = relocs; relend = relocs + input_section->reloc_count; for (; rel < relend; rel++) @@ -3244,13 +3309,13 @@ elf_i386_relocate_section (bfd *output_bfd, if (htab->elf.splt != NULL) { - plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1; + plt_index = h->plt.offset / plt_entry_size - 1; off = (plt_index + 3) * 4; base_got = htab->elf.sgotplt; } else { - plt_index = h->plt.offset / PLT_ENTRY_SIZE; + plt_index = h->plt.offset / plt_entry_size; off = plt_index * 4; base_got = htab->elf.igotplt; } @@ -4246,11 +4311,16 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, Elf_Internal_Sym *sym) { struct elf_i386_link_hash_table *htab; + unsigned plt_entry_size; + const struct elf_i386_backend_data *abed; htab = elf_i386_hash_table (info); if (htab == NULL) return FALSE; + abed = get_elf_i386_backend_data (output_bfd); + plt_entry_size = GET_PLT_ENTRY_SIZE (output_bfd); + if (h->plt.offset != (bfd_vma) -1) { bfd_vma plt_index; @@ -4299,27 +4369,28 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, if (plt == htab->elf.splt) { - plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1; + plt_index = h->plt.offset / plt_entry_size - 1; got_offset = (plt_index + 3) * 4; } else { - plt_index = h->plt.offset / PLT_ENTRY_SIZE; + plt_index = h->plt.offset / plt_entry_size; got_offset = plt_index * 4; } /* Fill in the entry in the procedure linkage table. */ if (! info->shared) { - memcpy (plt->contents + h->plt.offset, elf_i386_plt_entry, - PLT_ENTRY_SIZE); + memcpy (plt->contents + h->plt.offset, abed->plt->plt_entry, + abed->plt->plt_entry_size); bfd_put_32 (output_bfd, (gotplt->output_section->vma + gotplt->output_offset + got_offset), - plt->contents + h->plt.offset + 2); + plt->contents + h->plt.offset + + abed->plt->plt_got_offset); - if (get_elf_i386_backend_data (output_bfd)->is_vxworks) + if (abed->is_vxworks) { int s, k, reloc_index; @@ -4327,7 +4398,8 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, for this PLT entry. */ /* S: Current slot number (zero-based). */ - s = (h->plt.offset - PLT_ENTRY_SIZE) / PLT_ENTRY_SIZE; + s = ((h->plt.offset - abed->plt->plt_entry_size) + / abed->plt->plt_entry_size); /* K: Number of relocations for PLTResolve. */ if (info->shared) k = PLTRESOLVE_RELOCS_SHLIB; @@ -4357,19 +4429,23 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, } else { - memcpy (plt->contents + h->plt.offset, elf_i386_pic_plt_entry, - PLT_ENTRY_SIZE); + memcpy (plt->contents + h->plt.offset, abed->plt->pic_plt_entry, + abed->plt->plt_entry_size); bfd_put_32 (output_bfd, got_offset, - plt->contents + h->plt.offset + 2); + plt->contents + h->plt.offset + + abed->plt->plt_got_offset); } /* Don't fill PLT entry for static executables. */ if (plt == htab->elf.splt) { bfd_put_32 (output_bfd, plt_index * sizeof (Elf32_External_Rel), - plt->contents + h->plt.offset + 7); - bfd_put_32 (output_bfd, - (h->plt.offset + PLT_ENTRY_SIZE), - plt->contents + h->plt.offset + 12); + plt->contents + h->plt.offset + + abed->plt->plt_reloc_offset); + bfd_put_32 (output_bfd, - (h->plt.offset + + abed->plt->plt_plt_offset + 4), + plt->contents + h->plt.offset + + abed->plt->plt_plt_offset); } /* Fill in the entry in the global offset table. */ @@ -4377,7 +4453,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, (plt->output_section->vma + plt->output_offset + h->plt.offset - + 6), + + abed->plt->plt_lazy_offset), gotplt->contents + got_offset); /* Fill in the entry in the .rel.plt section. */ @@ -4518,7 +4594,7 @@ do_glob_dat: is relative to the ".got" section. */ if (sym != NULL && (strcmp (h->root.root.string, "_DYNAMIC") == 0 - || (!get_elf_i386_backend_data (output_bfd)->is_vxworks + || (!abed->is_vxworks && h == htab->elf.hgot))) sym->st_shndx = SHN_ABS; @@ -4568,6 +4644,7 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd, struct elf_i386_link_hash_table *htab; bfd *dynobj; asection *sdyn; + const struct elf_i386_backend_data *abed; htab = elf_i386_hash_table (info); if (htab == NULL) @@ -4575,6 +4652,7 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd, dynobj = htab->elf.dynobj; sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); + abed = get_elf_i386_backend_data (output_bfd); if (htab->elf.dynamic_sections_created) { @@ -4595,8 +4673,8 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd, switch (dyn.d_tag) { default: - if (get_elf_i386_backend_data (output_bfd)->is_vxworks - && elf_vxworks_finish_dynamic_entry (output_bfd, &dyn)) + if (abed->is_vxworks + && elf_vxworks_finish_dynamic_entry (output_bfd, &dyn)) break; continue; @@ -4649,31 +4727,33 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd, { if (info->shared) { - memcpy (htab->elf.splt->contents, elf_i386_pic_plt0_entry, - sizeof (elf_i386_pic_plt0_entry)); - memset (htab->elf.splt->contents + sizeof (elf_i386_pic_plt0_entry), - get_elf_i386_backend_data (output_bfd)->plt0_pad_byte, - PLT_ENTRY_SIZE - sizeof (elf_i386_pic_plt0_entry)); + memcpy (htab->elf.splt->contents, abed->plt->pic_plt0_entry, + abed->plt->plt0_entry_size); + memset (htab->elf.splt->contents + abed->plt->plt0_entry_size, + abed->plt0_pad_byte, + abed->plt->plt_entry_size - abed->plt->plt0_entry_size); } else { - memcpy (htab->elf.splt->contents, elf_i386_plt0_entry, - sizeof(elf_i386_plt0_entry)); - memset (htab->elf.splt->contents + sizeof (elf_i386_plt0_entry), - get_elf_i386_backend_data (output_bfd)->plt0_pad_byte, - PLT_ENTRY_SIZE - sizeof (elf_i386_plt0_entry)); + memcpy (htab->elf.splt->contents, abed->plt->plt0_entry, + abed->plt->plt0_entry_size); + memset (htab->elf.splt->contents + abed->plt->plt0_entry_size, + abed->plt0_pad_byte, + abed->plt->plt_entry_size - abed->plt->plt0_entry_size); bfd_put_32 (output_bfd, (htab->elf.sgotplt->output_section->vma + htab->elf.sgotplt->output_offset + 4), - htab->elf.splt->contents + 2); + htab->elf.splt->contents + + abed->plt->plt0_got1_offset); bfd_put_32 (output_bfd, (htab->elf.sgotplt->output_section->vma + htab->elf.sgotplt->output_offset + 8), - htab->elf.splt->contents + 8); + htab->elf.splt->contents + + abed->plt->plt0_got2_offset); - if (get_elf_i386_backend_data (output_bfd)->is_vxworks) + if (abed->is_vxworks) { Elf_Internal_Rela rel; @@ -4682,14 +4762,14 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd, the PLT directly. */ rel.r_offset = (htab->elf.splt->output_section->vma + htab->elf.splt->output_offset - + 2); + + abed->plt->plt0_got1_offset); rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_386_32); bfd_elf32_swap_reloc_out (output_bfd, &rel, htab->srelplt2->contents); /* Generate a relocation for _GLOBAL_OFFSET_TABLE_ + 8. */ rel.r_offset = (htab->elf.splt->output_section->vma + htab->elf.splt->output_offset - + 8); + + abed->plt->plt0_got2_offset); rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_386_32); bfd_elf32_swap_reloc_out (output_bfd, &rel, htab->srelplt2->contents + @@ -4703,10 +4783,10 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd, ->this_hdr.sh_entsize = 4; /* Correct the .rel.plt.unloaded relocations. */ - if (get_elf_i386_backend_data (output_bfd)->is_vxworks - && !info->shared) + if (abed->is_vxworks && !info->shared) { - int num_plts = (htab->elf.splt->size / PLT_ENTRY_SIZE) - 1; + int num_plts = (htab->elf.splt->size + / abed->plt->plt_entry_size) - 1; unsigned char *p; p = htab->srelplt2->contents; @@ -4800,7 +4880,7 @@ static bfd_vma elf_i386_plt_sym_val (bfd_vma i, const asection *plt, const arelent *rel ATTRIBUTE_UNUSED) { - return plt->vma + (i + 1) * PLT_ENTRY_SIZE; + return plt->vma + (i + 1) * GET_PLT_ENTRY_SIZE (plt->owner); } /* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */ @@ -4960,6 +5040,7 @@ elf_i386_fbsd_post_process_headers (bfd *abfd, struct bfd_link_info *info) static const struct elf_i386_backend_data elf_i386_vxworks_arch_bed = { + &elf_i386_plt, /* plt */ 0x90, /* plt0_pad_byte */ 1, /* is_vxworks */ }; -- 2.30.2