* 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.
This commit is contained in:
Roland McGrath 2012-03-15 16:37:25 +00:00
parent 14dc9ef7d1
commit eed180f84c
2 changed files with 149 additions and 64 deletions

View File

@ -1,3 +1,17 @@
2012-03-15 Roland McGrath <mcgrathr@google.com>
* 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.
2012-03-14 Roland McGrath <mcgrathr@google.com>
* elf32-i386.c (elf_i386_nacl_pic_plt0_entry): Initialize up

View File

@ -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
@ -721,8 +785,8 @@ elf_x86_64_link_hash_newfunc (struct bfd_hash_entry *entry,
if (entry == NULL)
{
entry = (struct bfd_hash_entry *)
bfd_hash_allocate (table,
sizeof (struct elf_x86_64_link_hash_entry));
bfd_hash_allocate (table,
sizeof (struct elf_x86_64_link_hash_entry));
if (entry == NULL)
return entry;
}
@ -839,7 +903,7 @@ elf_x86_64_link_hash_table_create (bfd *abfd)
ret->tls_ld_got.refcount = 0;
ret->sgotplt_jump_table_size = 0;
ret->tls_module_base = NULL;
ret->next_jump_slot_index = 0;
ret->next_jump_slot_index = 0;
ret->next_irelative_index = 0;
if (ABI_64_P (abfd))
@ -1107,7 +1171,7 @@ elf_x86_64_check_tls_transition (bfd *abfd,
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
/* Use strncmp to check __tls_get_addr since __tls_get_addr
may be versioned. */
may be versioned. */
return (h != NULL
&& h->root.root.string != NULL
&& (ELF32_R_TYPE (rel[1].r_info) == R_X86_64_PC32
@ -2007,7 +2071,7 @@ elf_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
if (h != NULL)
{
if (r_type == R_X86_64_GOTPLT64 && h->plt.refcount > 0)
h->plt.refcount -= 1;
h->plt.refcount -= 1;
if (h->got.refcount > 0)
h->got.refcount -= 1;
if (h->type == STT_GNU_IFUNC)
@ -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);
}
}
@ -2702,7 +2768,7 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
FALSE, FALSE, FALSE);
/* Don't allocate .got.plt section if there are no GOT nor PLT
entries and there is no refeence to _GLOBAL_OFFSET_TABLE_. */
entries and there is no refeence to _GLOBAL_OFFSET_TABLE_. */
if ((got == NULL
|| !got->ref_regular_nonweak)
&& (htab->elf.sgotplt->size
@ -2828,7 +2894,7 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
/* If any dynamic relocs apply to a read-only section,
then we need a DT_TEXTREL entry. */
if ((info->flags & DF_TEXTREL) == 0)
elf_link_hash_traverse (&htab->elf,
elf_link_hash_traverse (&htab->elf,
elf_x86_64_readonly_dynrelocs,
info);
@ -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));
@ -3023,7 +3090,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
}
if (r_type != (int) R_X86_64_32
|| ABI_64_P (output_bfd))
|| ABI_64_P (output_bfd))
howto = x86_64_elf_howto_table + r_type;
else
howto = (x86_64_elf_howto_table
@ -3050,7 +3117,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
if (h == NULL)
abort ();
/* Set STT_GNU_IFUNC symbol value. */
/* Set STT_GNU_IFUNC symbol value. */
h->root.u.def.value = sym->st_value;
h->root.u.def.section = sec;
}
@ -3126,7 +3193,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
if (ABI_64_P (output_bfd))
goto do_relocation;
/* FALLTHROUGH */
case R_X86_64_64:
case R_X86_64_64:
if (rel->r_addend != 0)
{
if (h->root.root.string)
@ -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;
}
@ -3226,9 +3293,9 @@ elf_x86_64_relocate_section (bfd *output_bfd,
|| h->forced_local
|| info->symbolic)
{
/* This references the local defitionion. We must
/* This references the local defitionion. We must
initialize this entry in the global offset table.
Since the offset must always be a multiple of 8,
Since the offset must always be a multiple of 8,
we use the least significant bit to record
whether we have initialized it already.
@ -3284,14 +3351,14 @@ elf_x86_64_relocate_section (bfd *output_bfd,
off = h->got.offset;
if (h->needs_plt
&& h->plt.offset != (bfd_vma)-1
&& h->plt.offset != (bfd_vma)-1
&& off == (bfd_vma)-1)
{
/* We can't use h->got.offset here to save
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;
}
@ -3322,7 +3389,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
bfd_put_64 (output_bfd, relocation,
base_got->contents + off);
/* Note that this is harmless for the GOTPLT64 case,
as -1 | 1 still is -1. */
as -1 | 1 still is -1. */
h->got.offset |= 1;
}
}
@ -3420,7 +3487,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
case R_X86_64_PLTOFF64:
/* Relocation is PLT entry relative to GOT. For local
symbols it's the symbol itself relative to GOT. */
if (h != NULL
if (h != NULL
/* See PLT32 handling. */
&& h->plt.offset != (bfd_vma) -1
&& htab->elf.splt != NULL)
@ -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,39 +4276,38 @@ 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);
memcpy (plt->contents + h->plt.offset, abed->plt_entry,
abed->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. */
/* 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
+ got_offset
- plt->output_section->vma
- plt->output_offset
- h->plt.offset
- 6),
plt->contents + h->plt.offset + 2);
(gotplt->output_section->vma
+ gotplt->output_offset
+ got_offset
- plt->output_section->vma
- plt->output_offset
- h->plt.offset
- 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);
@ -4408,7 +4476,7 @@ elf_x86_64_finish_local_dynamic_symbol (void **slot, void *inf)
struct elf_link_hash_entry *h
= (struct elf_link_hash_entry *) *slot;
struct bfd_link_info *info
= (struct bfd_link_info *) inf;
= (struct bfd_link_info *) inf;
return elf_x86_64_finish_dynamic_symbol (info->output_bfd,
info, h, NULL);
@ -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