/* Intel 80386/80486-specific support for 32-bit ELF
Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
- 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
+ 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
#include "bfdlink.h"
#include "libbfd.h"
#include "elf-bfd.h"
+#include "elf-nacl.h"
#include "elf-vxworks.h"
#include "bfd_stdint.h"
#include "objalloc.h"
/* The index of the next unused R_386_TLS_DESC slot in .rel.plt. */
bfd_vma next_tls_desc_index;
+
+ /* The index of the next unused R_386_JUMP_SLOT slot in .rel.plt. */
+ bfd_vma next_jump_slot_index;
+
+ /* The index of the next unused R_386_IRELATIVE slot in .rel.plt. */
+ bfd_vma next_irelative_index;
};
/* Get the i386 ELF linker hash table from a link_info structure. */
ret->sym_cache.abfd = NULL;
ret->srelplt2 = NULL;
ret->tls_module_base = NULL;
+ ret->next_jump_slot_index = 0;
+ ret->next_irelative_index = 0;
ret->loc_hash_table = htab_try_create (1024,
elf_i386_local_htab_hash,
if (htab == NULL)
return FALSE;
- htab->sdynbss = bfd_get_section_by_name (dynobj, ".dynbss");
+ htab->sdynbss = bfd_get_linker_section (dynobj, ".dynbss");
if (!info->shared)
- htab->srelbss = bfd_get_section_by_name (dynobj, ".rel.bss");
+ htab->srelbss = bfd_get_linker_section (dynobj, ".rel.bss");
if (!htab->sdynbss
|| (!info->shared && !htab->srelbss))
return FALSE;
if (!info->no_ld_generated_unwind_info
- && bfd_get_section_by_name (dynobj, ".eh_frame") == NULL
+ && htab->plt_eh_frame == NULL
&& htab->elf.splt != NULL)
{
- flagword flags = get_elf_backend_data (dynobj)->dynamic_sec_flags;
+ flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
+ | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED);
htab->plt_eh_frame
- = bfd_make_section_with_flags (dynobj, ".eh_frame",
- flags | SEC_READONLY);
+ = bfd_make_section_anyway_with_flags (dynobj, ".eh_frame", flags);
if (htab->plt_eh_frame == NULL
|| !bfd_set_section_alignment (dynobj, htab->plt_eh_frame, 2))
return FALSE;
-
- htab->plt_eh_frame->size = sizeof (elf_i386_eh_frame_plt);
- htab->plt_eh_frame->contents
- = bfd_alloc (dynobj, htab->plt_eh_frame->size);
- memcpy (htab->plt_eh_frame->contents, elf_i386_eh_frame_plt,
- sizeof (elf_i386_eh_frame_plt));
}
return TRUE;
_bfd_elf_link_hash_copy_indirect (info, dir, ind);
}
-typedef union
- {
- unsigned char c[2];
- uint16_t i;
- }
-i386_opcode16;
-
/* Return TRUE if the TLS access code sequence support transition
from R_TYPE. */
if (offset + 2 <= sec->size)
{
/* Make sure that it's a call *x@tlsdesc(%rax). */
- static i386_opcode16 call = { { 0xff, 0x10 } };
- return bfd_get_16 (abfd, contents + offset) == call.i;
+ static const unsigned char call[] = { 0xff, 0x10 };
+ return memcmp (contents + offset, call, 2) == 0;
}
return FALSE;
}
}
- if (h->size == 0)
- {
- (*_bfd_error_handler) (_("dynamic variable `%s' is zero size"),
- h->root.root.string);
- return TRUE;
- }
-
/* We must allocate the symbol in our .dynbss section, which will
become part of the .bss section of the executable. There will be
an entry for this symbol in the .dynsym section. The dynamic
/* We must generate a R_386_COPY reloc to tell the dynamic linker to
copy the initial value out of the dynamic object and into the
runtime process image. */
- if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
+ if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
{
htab->srelbss->size += sizeof (Elf32_External_Rel);
h->needs_copy = 1;
/* We also need to make an entry in the .rel.plt section. */
htab->elf.srelplt->size += sizeof (Elf32_External_Rel);
- htab->next_tls_desc_index++;
+ htab->elf.srelplt->reloc_count++;
if (get_elf_i386_backend_data (info->output_bfd)->is_vxworks
&& !info->shared)
/* Set the contents of the .interp section to the interpreter. */
if (info->executable)
{
- s = bfd_get_section_by_name (dynobj, ".interp");
+ s = bfd_get_linker_section (dynobj, ".interp");
if (s == NULL)
abort ();
s->size = sizeof ELF_DYNAMIC_INTERPRETER;
incremented. However, when we reserve space for TLS descriptors,
it's not incremented, so in order to compute the space reserved
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_386_IRELATIVE entries come last. */
if (htab->elf.srelplt)
- htab->sgotplt_jump_table_size = htab->next_tls_desc_index * 4;
+ {
+ htab->next_tls_desc_index = htab->elf.srelplt->reloc_count;
+ htab->sgotplt_jump_table_size = htab->next_tls_desc_index * 4;
+ 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->elf.sgotplt)
{
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 reference to _GLOBAL_OFFSET_TABLE_. */
if ((got == NULL
|| !got->ref_regular_nonweak)
&& (htab->elf.sgotplt->size
htab->elf.sgotplt->size = 0;
}
+
+ if (htab->plt_eh_frame != NULL
+ && htab->elf.splt != NULL
+ && htab->elf.splt->size != 0
+ && !bfd_is_abs_section (htab->elf.splt->output_section)
+ && _bfd_elf_eh_frame_present (info))
+ htab->plt_eh_frame->size = sizeof (elf_i386_eh_frame_plt);
+
/* We now have determined the sizes of the various dynamic sections.
Allocate memory for them. */
relocs = FALSE;
continue;
if (s == htab->elf.splt
- || s == htab->elf.sgot
- || s == htab->elf.sgotplt
- || s == htab->elf.iplt
- || s == htab->elf.igotplt
- || s == htab->sdynbss)
+ || s == htab->elf.sgot)
{
/* Strip this section if we don't need it; see the
comment below. */
if (htab->elf.hplt != NULL)
strip_section = FALSE;
}
+ else if (s == htab->elf.sgotplt
+ || s == htab->elf.iplt
+ || s == htab->elf.igotplt
+ || s == htab->plt_eh_frame
+ || s == htab->sdynbss)
+ {
+ /* Strip these too. */
+ }
else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rel"))
{
if (s->size != 0
}
if (htab->plt_eh_frame != NULL
- && htab->elf.splt != NULL
- && htab->elf.splt->size != 0
- && (htab->elf.splt->flags & SEC_EXCLUDE) == 0)
- bfd_put_32 (dynobj, htab->elf.splt->size,
- htab->plt_eh_frame->contents + PLT_FDE_LEN_OFFSET);
+ && htab->plt_eh_frame->contents != NULL)
+ {
+ memcpy (htab->plt_eh_frame->contents, elf_i386_eh_frame_plt,
+ sizeof (elf_i386_eh_frame_plt));
+ bfd_put_32 (dynobj, htab->elf.splt->size,
+ htab->plt_eh_frame->contents + PLT_FDE_LEN_OFFSET);
+ }
if (htab->elf.dynamic_sections_created)
{
unresolved_reloc, warned);
}
- if (sec != NULL && elf_discarded_section (sec))
+ if (sec != NULL && discarded_section (sec))
RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
- rel, relend, howto, contents);
+ rel, 1, relend, howto, 0, contents);
if (info->relocatable)
continue;
case R_386_32:
/* 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)
{
Elf_Internal_Rela outrel;
return FALSE;
}
else if (!info->executable
+ && !SYMBOLIC_BIND (info, h)
&& h->type == STT_FUNC
&& ELF_ST_VISIBILITY (h->other) == STV_PROTECTED)
{
not process them. */
if (unresolved_reloc
&& !((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)
(_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
if (plt == htab->elf.splt)
{
- plt_index = h->plt.offset / plt_entry_size - 1;
- got_offset = (plt_index + 3) * 4;
+ got_offset = h->plt.offset / plt_entry_size - 1;
+ got_offset = (got_offset + 3) * 4;
}
else
{
- plt_index = h->plt.offset / plt_entry_size;
- got_offset = plt_index * 4;
+ got_offset = h->plt.offset / plt_entry_size;
+ got_offset = got_offset * 4;
}
/* Fill in the entry in the procedure linkage table. */
+ 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
- + 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. */
bfd_put_32 (output_bfd,
(plt->output_section->vma
+ h->root.u.def.section->output_offset),
gotplt->contents + got_offset);
rel.r_info = ELF32_R_INFO (0, R_386_IRELATIVE);
+ /* R_386_IRELATIVE comes last. */
+ plt_index = htab->next_irelative_index--;
}
else
- rel.r_info = ELF32_R_INFO (h->dynindx, R_386_JUMP_SLOT);
+ {
+ rel.r_info = ELF32_R_INFO (h->dynindx, R_386_JUMP_SLOT);
+ plt_index = htab->next_jump_slot_index++;
+ }
loc = relplt->contents + plt_index * sizeof (Elf32_External_Rel);
bfd_elf32_swap_reloc_out (output_bfd, &rel, loc);
+ /* 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
+ + 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);
+ }
+
if (!h->def_regular)
{
/* Mark the symbol as undefined, rather than as defined in
bfd_elf32_swap_reloc_out (output_bfd, &rel, loc);
}
- /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. SYM may
- be NULL for local symbols.
-
- On VxWorks, the _GLOBAL_OFFSET_TABLE_ symbol is not absolute: it
- is relative to the ".got" section. */
- if (sym != NULL
- && (strcmp (h->root.root.string, "_DYNAMIC") == 0
- || (!abed->is_vxworks
- && h == htab->elf.hgot)))
- sym->st_shndx = SHN_ABS;
-
return TRUE;
}
return FALSE;
dynobj = htab->elf.dynobj;
- sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
+ sdyn = bfd_get_linker_section (dynobj, ".dynamic");
abed = get_elf_i386_backend_data (output_bfd);
if (htab->elf.dynamic_sections_created)
}
/* Adjust .eh_frame for .plt section. */
- if (htab->plt_eh_frame != NULL)
+ if (htab->plt_eh_frame != NULL
+ && htab->plt_eh_frame->contents != NULL)
{
if (htab->elf.splt != NULL
&& htab->elf.splt->size != 0
+ PLT_FDE_START_OFFSET);
}
if (htab->plt_eh_frame->sec_info_type
- == ELF_INFO_TYPE_EH_FRAME)
+ == SEC_INFO_TYPE_EH_FRAME)
{
if (! _bfd_elf_write_section_eh_frame (output_bfd, info,
htab->plt_eh_frame,
#include "elf32-target.h"
+/* Native Client support. */
+
+#undef TARGET_LITTLE_SYM
+#define TARGET_LITTLE_SYM bfd_elf32_i386_nacl_vec
+#undef TARGET_LITTLE_NAME
+#define TARGET_LITTLE_NAME "elf32-i386-nacl"
+#undef elf32_bed
+#define elf32_bed elf32_i386_nacl_bed
+
+#undef ELF_MAXPAGESIZE
+#define ELF_MAXPAGESIZE 0x10000
+
+/* Restore defaults. */
+#undef ELF_OSABI
+#undef elf_backend_want_plt_sym
+#define elf_backend_want_plt_sym 0
+#undef elf_backend_post_process_headers
+#define elf_backend_post_process_headers _bfd_elf_set_osabi
+#undef elf_backend_static_tls_alignment
+
+/* NaCl uses substantially different PLT entries for the same effects. */
+
+#undef elf_backend_plt_alignment
+#define elf_backend_plt_alignment 5
+#define NACL_PLT_ENTRY_SIZE 64
+#define NACLMASK 0xe0 /* 32-byte alignment mask. */
+
+static const bfd_byte elf_i386_nacl_plt0_entry[] =
+ {
+ 0xff, 0x35, /* pushl contents of address */
+ 0, 0, 0, 0, /* replaced with address of .got + 4. */
+ 0x8b, 0x0d, /* movl contents of address, %ecx */
+ 0, 0, 0, 0, /* replaced with address of .got + 8. */
+ 0x83, 0xe1, NACLMASK, /* andl $NACLMASK, %ecx */
+ 0xff, 0xe1 /* jmp *%ecx */
+ };
+
+static const bfd_byte elf_i386_nacl_plt_entry[NACL_PLT_ENTRY_SIZE] =
+ {
+ 0x8b, 0x0d, /* movl contents of address, %ecx */
+ 0, 0, 0, 0, /* replaced with GOT slot address. */
+ 0x83, 0xe1, NACLMASK, /* andl $NACLMASK, %ecx */
+ 0xff, 0xe1, /* jmp *%ecx */
+
+ /* Pad to the next 32-byte boundary with nop instructions. */
+ 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+
+ /* Lazy GOT entries point here (32-byte aligned). */
+ 0x68, /* pushl immediate */
+ 0, 0, 0, 0, /* replaced with reloc offset. */
+ 0xe9, /* jmp relative */
+ 0, 0, 0, 0, /* replaced with offset to .plt. */
+
+ /* Pad to the next 32-byte boundary with nop instructions. */
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90
+ };
+
+static const bfd_byte
+elf_i386_nacl_pic_plt0_entry[sizeof (elf_i386_nacl_plt0_entry)] =
+ {
+ 0xff, 0x73, 0x04, /* pushl 4(%ebx) */
+ 0x8b, 0x4b, 0x08, /* mov 0x8(%ebx), %ecx */
+ 0x83, 0xe1, 0xe0, /* and $NACLMASK, %ecx */
+ 0xff, 0xe1, /* jmp *%ecx */
+
+ /* This is expected to be the same size as elf_i386_nacl_plt0_entry,
+ so pad to that size with nop instructions. */
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90
+ };
+
+static const bfd_byte elf_i386_nacl_pic_plt_entry[NACL_PLT_ENTRY_SIZE] =
+ {
+ 0x8b, 0x8b, /* movl offset(%ebx), %ecx */
+ 0, 0, 0, 0, /* replaced with offset of this symbol in .got. */
+ 0x83, 0xe1, 0xe0, /* andl $NACLMASK, %ecx */
+ 0xff, 0xe1, /* jmp *%ecx */
+
+ /* Pad to the next 32-byte boundary with nop instructions. */
+ 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+
+ /* Lazy GOT entries point here (32-byte aligned). */
+ 0x68, /* pushl immediate */
+ 0, 0, 0, 0, /* replaced with offset into relocation table. */
+ 0xe9, /* jmp relative */
+ 0, 0, 0, 0, /* replaced with offset to start of .plt. */
+
+ /* Pad to the next 32-byte boundary with nop instructions. */
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90
+ };
+
+static const bfd_byte elf_i386_nacl_eh_frame_plt[] =
+ {
+#if (PLT_CIE_LENGTH != 20 \
+ || PLT_FDE_LENGTH != 36 \
+ || PLT_FDE_START_OFFSET != 4 + PLT_CIE_LENGTH + 8 \
+ || PLT_FDE_LEN_OFFSET != 4 + PLT_CIE_LENGTH + 12)
+# error "Need elf_i386_backend_data parameters for eh_frame_plt offsets!"
+#endif
+ PLT_CIE_LENGTH, 0, 0, 0, /* CIE length */
+ 0, 0, 0, 0, /* CIE ID */
+ 1, /* CIE version */
+ 'z', 'R', 0, /* Augmentation string */
+ 1, /* Code alignment factor */
+ 0x7c, /* Data alignment factor: -4 */
+ 8, /* Return address column */
+ 1, /* Augmentation size */
+ DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding */
+ DW_CFA_def_cfa, 4, 4, /* DW_CFA_def_cfa: r4 (esp) ofs 4 */
+ DW_CFA_offset + 8, 1, /* DW_CFA_offset: r8 (eip) at cfa-4 */
+ DW_CFA_nop, DW_CFA_nop,
+
+ PLT_FDE_LENGTH, 0, 0, 0, /* FDE length */
+ PLT_CIE_LENGTH + 8, 0, 0, 0, /* CIE pointer */
+ 0, 0, 0, 0, /* R_386_PC32 .plt goes here */
+ 0, 0, 0, 0, /* .plt size goes here */
+ 0, /* Augmentation size */
+ DW_CFA_def_cfa_offset, 8, /* DW_CFA_def_cfa_offset: 8 */
+ DW_CFA_advance_loc + 6, /* DW_CFA_advance_loc: 6 to __PLT__+6 */
+ DW_CFA_def_cfa_offset, 12, /* DW_CFA_def_cfa_offset: 12 */
+ DW_CFA_advance_loc + 58, /* DW_CFA_advance_loc: 58 to __PLT__+64 */
+ DW_CFA_def_cfa_expression, /* DW_CFA_def_cfa_expression */
+ 13, /* Block length */
+ DW_OP_breg4, 4, /* DW_OP_breg4 (esp): 4 */
+ DW_OP_breg8, 0, /* DW_OP_breg8 (eip): 0 */
+ DW_OP_const1u, 63, DW_OP_and, DW_OP_const1u, 37, DW_OP_ge,
+ DW_OP_lit2, DW_OP_shl, DW_OP_plus,
+ DW_CFA_nop, DW_CFA_nop
+ };
+
+static const struct elf_i386_plt_layout elf_i386_nacl_plt =
+ {
+ elf_i386_nacl_plt0_entry, /* plt0_entry */
+ sizeof (elf_i386_nacl_plt0_entry), /* plt0_entry_size */
+ 2, /* plt0_got1_offset */
+ 8, /* plt0_got2_offset */
+ elf_i386_nacl_plt_entry, /* plt_entry */
+ NACL_PLT_ENTRY_SIZE, /* plt_entry_size */
+ 2, /* plt_got_offset */
+ 33, /* plt_reloc_offset */
+ 38, /* plt_plt_offset */
+ 32, /* plt_lazy_offset */
+ elf_i386_nacl_pic_plt0_entry, /* pic_plt0_entry */
+ elf_i386_nacl_pic_plt_entry, /* pic_plt_entry */
+ elf_i386_nacl_eh_frame_plt, /* eh_frame_plt */
+ sizeof (elf_i386_nacl_eh_frame_plt),/* eh_frame_plt_size */
+ };
+
+static const struct elf_i386_backend_data elf_i386_nacl_arch_bed =
+ {
+ &elf_i386_nacl_plt, /* plt */
+ 0x90, /* plt0_pad_byte: nop insn */
+ 0, /* is_vxworks */
+ };
+
+#undef elf_backend_arch_data
+#define elf_backend_arch_data &elf_i386_nacl_arch_bed
+
+#undef elf_backend_modify_segment_map
+#define elf_backend_modify_segment_map nacl_modify_segment_map
+#undef elf_backend_modify_program_headers
+#define elf_backend_modify_program_headers nacl_modify_program_headers
+
+#include "elf32-target.h"
+
+/* Restore defaults. */
+#undef elf_backend_modify_segment_map
+#undef elf_backend_modify_program_headers
+
/* VxWorks support. */
#undef TARGET_LITTLE_SYM
#undef TARGET_LITTLE_NAME
#define TARGET_LITTLE_NAME "elf32-i386-vxworks"
#undef ELF_OSABI
+#undef elf_backend_plt_alignment
+#define elf_backend_plt_alignment 4
static const struct elf_i386_backend_data elf_i386_vxworks_arch_bed =
{