This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCH] parameterize elf64-x86-64 PLT generation
- From: Roland McGrath <mcgrathr at google dot com>
- To: binutils at sourceware dot org
- Date: Wed, 14 Mar 2012 17:15:26 -0700
- Subject: [PATCH] parameterize elf64-x86-64 PLT generation
This changes the elf64-x86-64 backend to parameterize the details
of PLT generation using the arch_data member of struct elf_backend_data.
This is quite similar to what I did in elf32-i386, though here I put all
the PLT stuff directly in the new struct elf_x86_64_backend_data rather
than having it point to another struct of PLT-related parameters, since
there is nothing else to put there.
Once this goes in, I will have elf64-x86-64-nacl backend support that
takes advantage of the flexibility to define its PLT details differently.
Ok for trunk?
Thanks,
Roland
bfd/
* elf64-x86-64.c (struct elf_x86_64_backend_data): New type.
(get_elf_x86_64_backend_data, GET_PLT_ENTRY_SIZE): New macros.
(elf_x86_64_arch_bed): New variable.
(elf_backend_arch_data): New macro.
(elf_x86_64_adjust_dynamic_symbol): Use GET_PLT_ENTRY_SIZE.
(elf_x86_64_allocate_dynrelocs): Likewise.
(elf_x86_64_relocate_section): Likewise.
(elf_x86_64_plt_sym_val): Likewise.
(elf_x86_64_finish_dynamic_symbol): Use elf_x86_64_backend_data
parameters for PLT details.
(elf_x86_64_finish_dynamic_sections): Likewise.
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index 88c47f9..280d6dc 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -585,6 +585,70 @@ static const bfd_byte elf_x86_64_eh_frame_plt[] =
DW_CFA_nop, DW_CFA_nop, DW_CFA_nop, DW_CFA_nop
};
+/* Architecture-specific backend data for x86-64. */
+
+struct elf_x86_64_backend_data
+{
+ /* Templates for the initial PLT entry and for subsequent entries. */
+ const bfd_byte *plt0_entry;
+ const bfd_byte *plt_entry;
+ unsigned int plt_entry_size; /* Size of each PLT entry. */
+
+ /* 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;
+
+ /* Offset of the end of the PC-relative instruction containing
+ plt0_got2_offset. */
+ unsigned int plt0_got2_insn_end;
+
+ /* 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. */
+
+ /* Length of the PC-relative instruction containing plt_got_offset. */
+ unsigned int plt_got_insn_size;
+
+ /* Offset of the end of the PC-relative jump to plt0_entry. */
+ unsigned int plt_plt_insn_end;
+
+ /* Offset into plt_entry where the initial value of the GOT entry points. */
+ unsigned int plt_lazy_offset;
+
+ /* .eh_frame covering the .plt section. */
+ const bfd_byte *eh_frame_plt;
+ unsigned int eh_frame_plt_size;
+};
+
+#define get_elf_x86_64_backend_data(abfd) \
+ ((const struct elf_x86_64_backend_data *) \
+ get_elf_backend_data (abfd)->arch_data)
+
+#define GET_PLT_ENTRY_SIZE(abfd) \
+ get_elf_x86_64_backend_data (abfd)->plt_entry_size
+
+/* These are the standard parameters. */
+static const struct elf_x86_64_backend_data elf_x86_64_arch_bed =
+ {
+ elf_x86_64_plt0_entry, /* plt0_entry */
+ elf_x86_64_plt_entry, /* plt_entry */
+ sizeof (elf_x86_64_plt_entry), /* plt_entry_size */
+ 2, /* plt0_got1_offset */
+ 8, /* plt0_got2_offset */
+ 12, /* plt0_got2_insn_end */
+ 2, /* plt_got_offset */
+ 7, /* plt_reloc_offset */
+ 12, /* plt_plt_offset */
+ 6, /* plt_got_insn_size */
+ PLT_ENTRY_SIZE, /* plt_plt_insn_end */
+ 6, /* plt_lazy_offset */
+ elf_x86_64_eh_frame_plt, /* eh_frame_plt */
+ sizeof (elf_x86_64_eh_frame_plt), /* eh_frame_plt_size */
+ };
+
+#define elf_backend_arch_data &elf_x86_64_arch_bed
+
/* x86-64 ELF linker hash entry. */
struct elf_x86_64_link_hash_entry
@@ -2207,6 +2271,7 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
struct elf_x86_64_link_hash_entry *eh;
struct elf_dyn_relocs *p;
const struct elf_backend_data *bed;
+ unsigned int plt_entry_size;
if (h->root.type == bfd_link_hash_indirect)
return TRUE;
@@ -2218,6 +2283,7 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
if (htab == NULL)
return FALSE;
bed = get_elf_backend_data (info->output_bfd);
+ 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. */
@@ -2225,7 +2291,7 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
&& h->def_regular)
return _bfd_elf_allocate_ifunc_dyn_relocs (info, h,
&eh->dyn_relocs,
- PLT_ENTRY_SIZE,
+ plt_entry_size,
GOT_ENTRY_SIZE);
else if (htab->elf.dynamic_sections_created
&& h->plt.refcount > 0)
@@ -2247,7 +2313,7 @@ elf_x86_64_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;
@@ -2264,7 +2330,7 @@ elf_x86_64_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. */
@@ -2688,9 +2754,9 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
/* Reserve room for the initial entry.
FIXME: we could probably do away with it in this case. */
if (htab->elf.splt->size == 0)
- htab->elf.splt->size += PLT_ENTRY_SIZE;
+ htab->elf.splt->size += GET_PLT_ENTRY_SIZE (output_bfd);
htab->tlsdesc_plt = htab->elf.splt->size;
- htab->elf.splt->size += PLT_ENTRY_SIZE;
+ htab->elf.splt->size += GET_PLT_ENTRY_SIZE (output_bfd);
}
}
@@ -2981,6 +3047,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
bfd_vma *local_tlsdesc_gotents;
Elf_Internal_Rela *rel;
Elf_Internal_Rela *relend;
+ const unsigned int plt_entry_size = GET_PLT_ENTRY_SIZE (info->output_bfd);
BFD_ASSERT (is_x86_64_elf (input_bfd));
@@ -3211,13 +3278,13 @@ elf_x86_64_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) * GOT_ENTRY_SIZE;
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 * GOT_ENTRY_SIZE;
base_got = htab->elf.igotplt;
}
@@ -3291,7 +3358,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
state, or even just remember the offset, as
finish_dynamic_symbol would use that as offset into
.got. */
- bfd_vma plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
+ bfd_vma plt_index = h->plt.offset / plt_entry_size - 1;
off = (plt_index + 3) * GOT_ENTRY_SIZE;
base_got = htab->elf.sgotplt;
}
@@ -4154,6 +4221,8 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
Elf_Internal_Sym *sym)
{
struct elf_x86_64_link_hash_table *htab;
+ const struct elf_x86_64_backend_data *const abed
+ = get_elf_x86_64_backend_data (output_bfd);
htab = elf_x86_64_hash_table (info);
if (htab == NULL)
@@ -4207,24 +4276,23 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
if (plt == htab->elf.splt)
{
- got_offset = h->plt.offset / PLT_ENTRY_SIZE - 1;
+ got_offset = h->plt.offset / abed->plt_entry_size - 1;
got_offset = (got_offset + 3) * GOT_ENTRY_SIZE;
}
else
{
- got_offset = h->plt.offset / PLT_ENTRY_SIZE;
+ got_offset = h->plt.offset / abed->plt_entry_size;
got_offset = got_offset * GOT_ENTRY_SIZE;
}
/* Fill in the entry in the procedure linkage table. */
- memcpy (plt->contents + h->plt.offset, elf_x86_64_plt_entry,
- PLT_ENTRY_SIZE);
-
- /* Insert the relocation positions of the plt section. The magic
- numbers at the end of the statements are the positions of the
- relocations in the plt section. */
- /* Put offset for jmp *name@GOTPCREL(%rip), since the
- instruction uses 6 bytes, subtract this value. */
+ memcpy (plt->contents + h->plt.offset, abed->plt_entry,
+ abed->plt_entry_size);
+
+ /* Insert the relocation positions of the plt section. */
+
+ /* Put offset the PC-relative instruction referring to the GOT entry,
+ subtracting the size of that instruction. */
bfd_put_32 (output_bfd,
(gotplt->output_section->vma
+ gotplt->output_offset
@@ -4232,14 +4300,14 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
- plt->output_section->vma
- plt->output_offset
- h->plt.offset
- - 6),
- plt->contents + h->plt.offset + 2);
+ - abed->plt_got_insn_size),
+ plt->contents + h->plt.offset + abed->plt_got_offset);
/* Fill in the entry in the global offset table, initially this
- points to the pushq instruction in the PLT which is at offset 6. */
+ points to the second part of the PLT entry. */
bfd_put_64 (output_bfd, (plt->output_section->vma
+ plt->output_offset
- + h->plt.offset + 6),
+ + h->plt.offset + abed->plt_lazy_offset),
gotplt->contents + got_offset);
/* Fill in the entry in the .rela.plt section. */
@@ -4273,10 +4341,10 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
{
/* Put relocation index. */
bfd_put_32 (output_bfd, plt_index,
- plt->contents + h->plt.offset + 7);
+ plt->contents + h->plt.offset + abed->plt_reloc_offset);
/* Put offset for jmp .PLT0. */
- bfd_put_32 (output_bfd, - (h->plt.offset + PLT_ENTRY_SIZE),
- plt->contents + h->plt.offset + 12);
+ bfd_put_32 (output_bfd, - (h->plt.offset + abed->plt_plt_insn_end),
+ plt->contents + h->plt.offset + abed->plt_plt_offset);
}
bed = get_elf_backend_data (output_bfd);
@@ -4442,6 +4510,8 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd,
struct elf_x86_64_link_hash_table *htab;
bfd *dynobj;
asection *sdyn;
+ const struct elf_x86_64_backend_data *const abed
+ = get_elf_x86_64_backend_data (output_bfd);
htab = elf_x86_64_hash_table (info);
if (htab == NULL)
@@ -4524,8 +4594,8 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd,
if (htab->elf.splt && htab->elf.splt->size > 0)
{
/* Fill in the first entry in the procedure linkage table. */
- memcpy (htab->elf.splt->contents, elf_x86_64_plt0_entry,
- PLT_ENTRY_SIZE);
+ memcpy (htab->elf.splt->contents,
+ abed->plt0_entry, abed->plt_entry_size);
/* Add offset for pushq GOT+8(%rip), since the instruction
uses 6 bytes subtract this value. */
bfd_put_32 (output_bfd,
@@ -4535,20 +4605,20 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd,
- htab->elf.splt->output_section->vma
- htab->elf.splt->output_offset
- 6),
- htab->elf.splt->contents + 2);
- /* Add offset for jmp *GOT+16(%rip). The 12 is the offset to
- the end of the instruction. */
+ htab->elf.splt->contents + abed->plt0_got1_offset);
+ /* Add offset for the PC-relative instruction accessing GOT+16,
+ subtracting the offset to the end of that instruction. */
bfd_put_32 (output_bfd,
(htab->elf.sgotplt->output_section->vma
+ htab->elf.sgotplt->output_offset
+ 16
- htab->elf.splt->output_section->vma
- htab->elf.splt->output_offset
- - 12),
- htab->elf.splt->contents + 8);
+ - abed->plt0_got2_insn_end),
+ htab->elf.splt->contents + abed->plt0_got2_offset);
- elf_section_data (htab->elf.splt->output_section)->this_hdr.sh_entsize =
- PLT_ENTRY_SIZE;
+ elf_section_data (htab->elf.splt->output_section)
+ ->this_hdr.sh_entsize = abed->plt_entry_size;
if (htab->tlsdesc_plt)
{
@@ -4556,8 +4626,7 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd,
htab->elf.sgot->contents + htab->tlsdesc_got);
memcpy (htab->elf.splt->contents + htab->tlsdesc_plt,
- elf_x86_64_plt0_entry,
- PLT_ENTRY_SIZE);
+ abed->plt0_entry, abed->plt_entry_size);
/* Add offset for pushq GOT+8(%rip), since the
instruction uses 6 bytes subtract this value. */
@@ -4569,10 +4638,11 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd,
- htab->elf.splt->output_offset
- htab->tlsdesc_plt
- 6),
- htab->elf.splt->contents + htab->tlsdesc_plt + 2);
- /* Add offset for jmp *GOT+TDG(%rip), where TGD stands for
- htab->tlsdesc_got. The 12 is the offset to the end of
- the instruction. */
+ htab->elf.splt->contents
+ + htab->tlsdesc_plt + abed->plt0_got1_offset);
+ /* Add offset for the PC-relative instruction accessing GOT+TDG,
+ where TGD stands for htab->tlsdesc_got, subtracting the offset
+ to the end of that instruction. */
bfd_put_32 (output_bfd,
(htab->elf.sgot->output_section->vma
+ htab->elf.sgot->output_offset
@@ -4580,8 +4650,9 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd,
- htab->elf.splt->output_section->vma
- htab->elf.splt->output_offset
- htab->tlsdesc_plt
- - 12),
- htab->elf.splt->contents + htab->tlsdesc_plt + 8);
+ - abed->plt0_got2_insn_end),
+ htab->elf.splt->contents
+ + htab->tlsdesc_plt + abed->plt0_got2_offset);
}
}
}
@@ -4661,7 +4732,7 @@ static bfd_vma
elf_x86_64_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);
}
/* Handle an x86-64 specific section when reading an object file. This