summaryrefslogtreecommitdiff
path: root/bfd/elf32-i386.c
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>2011-07-28 18:47:55 +0000
committerRoland McGrath <roland@gnu.org>2011-07-28 18:47:55 +0000
commitaedb4c2ef0bd2034e40504571eac8357eb1c3626 (patch)
tree7cc0b8d98d1e1848b7e5bb8c1340bbdf5150222a /bfd/elf32-i386.c
parentda4f3e133e09c41c5ec6942fb9e1ba6114fc669a (diff)
downloadbinutils-redhat-aedb4c2ef0bd2034e40504571eac8357eb1c3626.tar.gz
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.
Diffstat (limited to 'bfd/elf32-i386.c')
-rw-r--r--bfd/elf32-i386.c169
1 files changed, 125 insertions, 44 deletions
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index 39050eca8a..cb16fafafc 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 */
};