Line 696... |
Line 696... |
yet. */
|
yet. */
|
bfd_vma tlsdesc_plt;
|
bfd_vma tlsdesc_plt;
|
/* The offset into sgot of the GOT entry used by the PLT entry
|
/* The offset into sgot of the GOT entry used by the PLT entry
|
above. */
|
above. */
|
bfd_vma tlsdesc_got;
|
bfd_vma tlsdesc_got;
|
|
|
|
/* The index of the next R_X86_64_JUMP_SLOT entry in .rela.plt. */
|
|
bfd_vma next_jump_slot_index;
|
|
/* The index of the next R_X86_64_IRELATIVE entry in .rela.plt. */
|
|
bfd_vma next_irelative_index;
|
};
|
};
|
|
|
/* Get the x86-64 ELF linker hash table from a link_info structure. */
|
/* Get the x86-64 ELF linker hash table from a link_info structure. */
|
|
|
#define elf_x86_64_hash_table(p) \
|
#define elf_x86_64_hash_table(p) \
|
Line 837... |
Line 842... |
ret->tlsdesc_plt = 0;
|
ret->tlsdesc_plt = 0;
|
ret->tlsdesc_got = 0;
|
ret->tlsdesc_got = 0;
|
ret->tls_ld_got.refcount = 0;
|
ret->tls_ld_got.refcount = 0;
|
ret->sgotplt_jump_table_size = 0;
|
ret->sgotplt_jump_table_size = 0;
|
ret->tls_module_base = NULL;
|
ret->tls_module_base = NULL;
|
|
ret->next_jump_slot_index = 0;
|
|
ret->next_irelative_index = 0;
|
|
|
if (ABI_64_P (abfd))
|
if (ABI_64_P (abfd))
|
{
|
{
|
ret->r_info = elf64_r_info;
|
ret->r_info = elf64_r_info;
|
ret->r_sym = elf64_r_sym;
|
ret->r_sym = elf64_r_sym;
|
Line 1005... |
Line 1012... |
/* Set the right machine number for an x86-64 elf64 file. */
|
/* Set the right machine number for an x86-64 elf64 file. */
|
bfd_default_set_arch_mach (abfd, bfd_arch_i386, bfd_mach_x86_64);
|
bfd_default_set_arch_mach (abfd, bfd_arch_i386, bfd_mach_x86_64);
|
return TRUE;
|
return TRUE;
|
}
|
}
|
|
|
typedef union
|
|
{
|
|
unsigned char c[2];
|
|
uint16_t i;
|
|
}
|
|
x86_64_opcode16;
|
|
|
|
typedef union
|
|
{
|
|
unsigned char c[4];
|
|
uint32_t i;
|
|
}
|
|
x86_64_opcode32;
|
|
|
|
/* Return TRUE if the TLS access code sequence support transition
|
/* Return TRUE if the TLS access code sequence support transition
|
from R_TYPE. */
|
from R_TYPE. */
|
|
|
static bfd_boolean
|
static bfd_boolean
|
elf_x86_64_check_tls_transition (bfd *abfd,
|
elf_x86_64_check_tls_transition (bfd *abfd,
|
Line 1074... |
Line 1067... |
can transit to different access model. For 32bit, only
|
can transit to different access model. For 32bit, only
|
leaq foo@tlsgd(%rip), %rdi
|
leaq foo@tlsgd(%rip), %rdi
|
.word 0x6666; rex64; call __tls_get_addr
|
.word 0x6666; rex64; call __tls_get_addr
|
can transit to different access model. */
|
can transit to different access model. */
|
|
|
static x86_64_opcode32 call = { { 0x66, 0x66, 0x48, 0xe8 } };
|
static const unsigned char call[] = { 0x66, 0x66, 0x48, 0xe8 };
|
|
static const unsigned char leaq[] = { 0x66, 0x48, 0x8d, 0x3d };
|
|
|
if ((offset + 12) > sec->size
|
if ((offset + 12) > sec->size
|
|| bfd_get_32 (abfd, contents + offset + 4) != call.i)
|
|| memcmp (contents + offset + 4, call, 4) != 0)
|
return FALSE;
|
return FALSE;
|
|
|
if (ABI_64_P (abfd))
|
if (ABI_64_P (abfd))
|
{
|
{
|
static x86_64_opcode32 leaq = { { 0x66, 0x48, 0x8d, 0x3d } };
|
|
if (offset < 4
|
if (offset < 4
|
|| bfd_get_32 (abfd, contents + offset - 4) != leaq.i)
|
|| memcmp (contents + offset - 4, leaq, 4) != 0)
|
return FALSE;
|
return FALSE;
|
}
|
}
|
else
|
else
|
{
|
{
|
static x86_64_opcode16 lea = { { 0x8d, 0x3d } };
|
|
if (offset < 3
|
if (offset < 3
|
|| bfd_get_8 (abfd, contents + offset - 3) != 0x48
|
|| memcmp (contents + offset - 3, leaq + 1, 3) != 0)
|
|| bfd_get_16 (abfd, contents + offset - 2) != lea.i)
|
|
return FALSE;
|
return FALSE;
|
}
|
}
|
}
|
}
|
else
|
else
|
{
|
{
|
/* Check transition from LD access model. Only
|
/* Check transition from LD access model. Only
|
leaq foo@tlsld(%rip), %rdi;
|
leaq foo@tlsld(%rip), %rdi;
|
call __tls_get_addr
|
call __tls_get_addr
|
can transit to different access model. */
|
can transit to different access model. */
|
|
|
static x86_64_opcode32 ld = { { 0x48, 0x8d, 0x3d, 0xe8 } };
|
static const unsigned char lea[] = { 0x48, 0x8d, 0x3d };
|
x86_64_opcode32 op;
|
|
|
|
if (offset < 3 || (offset + 9) > sec->size)
|
if (offset < 3 || (offset + 9) > sec->size)
|
return FALSE;
|
return FALSE;
|
|
|
op.i = bfd_get_32 (abfd, contents + offset - 3);
|
if (memcmp (contents + offset - 3, lea, 3) != 0
|
op.c[3] = bfd_get_8 (abfd, contents + offset + 4);
|
|| 0xe8 != *(contents + offset + 4))
|
if (op.i != ld.i)
|
|
return FALSE;
|
return FALSE;
|
}
|
}
|
|
|
r_symndx = htab->r_sym (rel[1].r_info);
|
r_symndx = htab->r_sym (rel[1].r_info);
|
if (r_symndx < symtab_hdr->sh_info)
|
if (r_symndx < symtab_hdr->sh_info)
|
Line 1189... |
Line 1179... |
call *x@tlsdesc(%rax)
|
call *x@tlsdesc(%rax)
|
*/
|
*/
|
if (offset + 2 <= sec->size)
|
if (offset + 2 <= sec->size)
|
{
|
{
|
/* Make sure that it's a call *x@tlsdesc(%rax). */
|
/* Make sure that it's a call *x@tlsdesc(%rax). */
|
static x86_64_opcode16 call = { { 0xff, 0x10 } };
|
static const unsigned char call[] = { 0xff, 0x10 };
|
return bfd_get_16 (abfd, contents + offset) == call.i;
|
return memcmp (contents + offset, call, 2) == 0;
|
}
|
}
|
|
|
return FALSE;
|
return FALSE;
|
|
|
default:
|
default:
|
Line 2682... |
Line 2672... |
|
|
/* For every jump slot reserved in the sgotplt, reloc_count is
|
/* For every jump slot reserved in the sgotplt, reloc_count is
|
incremented. However, when we reserve space for TLS descriptors,
|
incremented. However, when we reserve space for TLS descriptors,
|
it's not incremented, so in order to compute the space reserved
|
it's not incremented, so in order to compute the space reserved
|
for them, it suffices to multiply the reloc count by the jump
|
for them, it suffices to multiply the reloc count by the jump
|
slot size. */
|
slot size.
|
|
|
|
PR ld/13302: We start next_irelative_index at the end of .rela.plt
|
|
so that R_X86_64_IRELATIVE entries come last. */
|
if (htab->elf.srelplt)
|
if (htab->elf.srelplt)
|
|
{
|
htab->sgotplt_jump_table_size
|
htab->sgotplt_jump_table_size
|
= elf_x86_64_compute_jump_table_size (htab);
|
= elf_x86_64_compute_jump_table_size (htab);
|
|
htab->next_irelative_index = htab->elf.srelplt->reloc_count - 1;
|
|
}
|
|
else if (htab->elf.irelplt)
|
|
htab->next_irelative_index = htab->elf.irelplt->reloc_count - 1;
|
|
|
if (htab->tlsdesc_plt)
|
if (htab->tlsdesc_plt)
|
{
|
{
|
/* If we're not using lazy TLS relocations, don't generate the
|
/* If we're not using lazy TLS relocations, don't generate the
|
PLT and GOT entries they require. */
|
PLT and GOT entries they require. */
|
Line 3156... |
Line 3154... |
bfd_set_error (bfd_error_bad_value);
|
bfd_set_error (bfd_error_bad_value);
|
return FALSE;
|
return FALSE;
|
}
|
}
|
|
|
/* Generate dynamic relcoation only when there is a
|
/* Generate dynamic relcoation only when there is a
|
non-GOF reference in a shared object. */
|
non-GOT reference in a shared object. */
|
if (info->shared && h->non_got_ref)
|
if (info->shared && h->non_got_ref)
|
{
|
{
|
Elf_Internal_Rela outrel;
|
Elf_Internal_Rela outrel;
|
asection *sreloc;
|
asection *sreloc;
|
|
bfd_boolean relocate;
|
|
|
/* Need a dynamic relocation to get the real function
|
/* Need a dynamic relocation to get the real function
|
address. */
|
address. */
|
outrel.r_offset = _bfd_elf_section_offset (output_bfd,
|
outrel.r_offset = _bfd_elf_section_offset (output_bfd,
|
info,
|
info,
|
Line 3180... |
Line 3179... |
if (h->dynindx == -1
|
if (h->dynindx == -1
|
|| h->forced_local
|
|| h->forced_local
|
|| info->executable)
|
|| info->executable)
|
{
|
{
|
/* This symbol is resolved locally. */
|
/* This symbol is resolved locally. */
|
outrel.r_info = htab->r_info (0, R_X86_64_IRELATIVE);
|
outrel.r_info = htab->r_info (0, R_X86_64_RELATIVE);
|
outrel.r_addend = (h->root.u.def.value
|
outrel.r_addend = relocation;
|
+ h->root.u.def.section->output_section->vma
|
relocate = FALSE;
|
+ h->root.u.def.section->output_offset);
|
|
}
|
}
|
else
|
else
|
{
|
{
|
outrel.r_info = htab->r_info (h->dynindx, r_type);
|
outrel.r_info = htab->r_info (h->dynindx, r_type);
|
outrel.r_addend = 0;
|
outrel.r_addend = 0;
|
|
relocate = FALSE;
|
}
|
}
|
|
|
sreloc = htab->elf.irelifunc;
|
sreloc = htab->elf.irelifunc;
|
elf_append_rela (output_bfd, sreloc, &outrel);
|
elf_append_rela (output_bfd, sreloc, &outrel);
|
|
|
/* If this reloc is against an external symbol, we
|
/* If this reloc is against an external symbol, we
|
do not want to fiddle with the addend. Otherwise,
|
do not want to fiddle with the addend. Otherwise,
|
we need to include the symbol value so that it
|
we need to include the symbol value so that it
|
becomes an addend for the dynamic reloc. For an
|
becomes an addend for the dynamic reloc. For an
|
internal symbol, we have updated addend. */
|
internal symbol, we have updated addend. */
|
|
if (! relocate)
|
continue;
|
continue;
|
}
|
}
|
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
case R_X86_64_PC32:
|
case R_X86_64_PC32:
|
case R_X86_64_PC64:
|
case R_X86_64_PC64:
|
Line 4101... |
Line 4101... |
/* Dynamic relocs are not propagated for SEC_DEBUGGING sections
|
/* Dynamic relocs are not propagated for SEC_DEBUGGING sections
|
because such sections are not SEC_ALLOC and thus ld.so will
|
because such sections are not SEC_ALLOC and thus ld.so will
|
not process them. */
|
not process them. */
|
if (unresolved_reloc
|
if (unresolved_reloc
|
&& !((input_section->flags & SEC_DEBUGGING) != 0
|
&& !((input_section->flags & SEC_DEBUGGING) != 0
|
&& h->def_dynamic))
|
&& h->def_dynamic)
|
|
&& _bfd_elf_section_offset (output_bfd, info, input_section,
|
|
rel->r_offset) != (bfd_vma) -1)
|
(*_bfd_error_handler)
|
(*_bfd_error_handler)
|
(_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
|
(_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
|
input_bfd,
|
input_bfd,
|
input_section,
|
input_section,
|
(long) rel->r_offset,
|
(long) rel->r_offset,
|
Line 4218... |
Line 4220... |
|
|
For static executables, we don't reserve anything. */
|
For static executables, we don't reserve anything. */
|
|
|
if (plt == htab->elf.splt)
|
if (plt == htab->elf.splt)
|
{
|
{
|
plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
|
got_offset = h->plt.offset / PLT_ENTRY_SIZE - 1;
|
got_offset = (plt_index + 3) * GOT_ENTRY_SIZE;
|
got_offset = (got_offset + 3) * GOT_ENTRY_SIZE;
|
}
|
}
|
else
|
else
|
{
|
{
|
plt_index = h->plt.offset / PLT_ENTRY_SIZE;
|
got_offset = h->plt.offset / PLT_ENTRY_SIZE;
|
got_offset = plt_index * GOT_ENTRY_SIZE;
|
got_offset = got_offset * GOT_ENTRY_SIZE;
|
}
|
}
|
|
|
/* Fill in the entry in the procedure linkage table. */
|
/* Fill in the entry in the procedure linkage table. */
|
memcpy (plt->contents + h->plt.offset, elf_x86_64_plt_entry,
|
memcpy (plt->contents + h->plt.offset, elf_x86_64_plt_entry,
|
PLT_ENTRY_SIZE);
|
PLT_ENTRY_SIZE);
|
Line 4246... |
Line 4248... |
- plt->output_offset
|
- plt->output_offset
|
- h->plt.offset
|
- h->plt.offset
|
- 6),
|
- 6),
|
plt->contents + h->plt.offset + 2);
|
plt->contents + h->plt.offset + 2);
|
|
|
/* Don't fill PLT entry for static executables. */
|
|
if (plt == htab->elf.splt)
|
|
{
|
|
/* Put relocation index. */
|
|
bfd_put_32 (output_bfd, plt_index,
|
|
plt->contents + h->plt.offset + 7);
|
|
/* Put offset for jmp .PLT0. */
|
|
bfd_put_32 (output_bfd, - (h->plt.offset + PLT_ENTRY_SIZE),
|
|
plt->contents + h->plt.offset + 12);
|
|
}
|
|
|
|
/* Fill in the entry in the global offset table, initially this
|
/* 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 pushq instruction in the PLT which is at offset 6. */
|
bfd_put_64 (output_bfd, (plt->output_section->vma
|
bfd_put_64 (output_bfd, (plt->output_section->vma
|
+ plt->output_offset
|
+ plt->output_offset
|
+ h->plt.offset + 6),
|
+ h->plt.offset + 6),
|
Line 4280... |
Line 4271... |
R_X86_64_IRELATIVE instead of R_X86_64_JUMP_SLOT. */
|
R_X86_64_IRELATIVE instead of R_X86_64_JUMP_SLOT. */
|
rela.r_info = htab->r_info (0, R_X86_64_IRELATIVE);
|
rela.r_info = htab->r_info (0, R_X86_64_IRELATIVE);
|
rela.r_addend = (h->root.u.def.value
|
rela.r_addend = (h->root.u.def.value
|
+ h->root.u.def.section->output_section->vma
|
+ h->root.u.def.section->output_section->vma
|
+ h->root.u.def.section->output_offset);
|
+ h->root.u.def.section->output_offset);
|
|
/* R_X86_64_IRELATIVE comes last. */
|
|
plt_index = htab->next_irelative_index--;
|
}
|
}
|
else
|
else
|
{
|
{
|
rela.r_info = htab->r_info (h->dynindx, R_X86_64_JUMP_SLOT);
|
rela.r_info = htab->r_info (h->dynindx, R_X86_64_JUMP_SLOT);
|
rela.r_addend = 0;
|
rela.r_addend = 0;
|
|
plt_index = htab->next_jump_slot_index++;
|
|
}
|
|
|
|
/* Don't fill PLT entry for static executables. */
|
|
if (plt == htab->elf.splt)
|
|
{
|
|
/* Put relocation index. */
|
|
bfd_put_32 (output_bfd, plt_index,
|
|
plt->contents + h->plt.offset + 7);
|
|
/* Put offset for jmp .PLT0. */
|
|
bfd_put_32 (output_bfd, - (h->plt.offset + PLT_ENTRY_SIZE),
|
|
plt->contents + h->plt.offset + 12);
|
}
|
}
|
|
|
bed = get_elf_backend_data (output_bfd);
|
bed = get_elf_backend_data (output_bfd);
|
loc = relplt->contents + plt_index * bed->s->sizeof_rela;
|
loc = relplt->contents + plt_index * bed->s->sizeof_rela;
|
bed->s->swap_reloca_out (output_bfd, &rela, loc);
|
bed->s->swap_reloca_out (output_bfd, &rela, loc);
|