#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"
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;
{
struct elf_i386_link_hash_table *htab;
asection *s;
+ struct elf_i386_link_hash_entry *eh;
+ struct elf_dyn_relocs *p;
/* STT_GNU_IFUNC symbol must go through PLT. */
if (h->type == STT_GNU_IFUNC)
{
+ /* Check local STT_GNU_IFUNC calls. */
+ if (h->ref_regular
+ && SYMBOL_CALLS_LOCAL (info, h))
+ {
+ bfd_size_type pc_count = 0;
+ struct elf_dyn_relocs **pp;
+
+ eh = (struct elf_i386_link_hash_entry *) h;
+ for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
+ {
+ pc_count += p->pc_count;
+ p->count -= p->pc_count;
+ p->pc_count = 0;
+ if (p->count == 0)
+ *pp = p->next;
+ else
+ pp = &p->next;
+ }
+
+ if (pc_count)
+ {
+ h->needs_plt = 1;
+ h->plt.refcount += 1;
+ h->non_got_ref = 1;
+ }
+ }
+
if (h->plt.refcount <= 0)
{
h->plt.offset = (bfd_vma) -1;
if (ELIMINATE_COPY_RELOCS
&& !get_elf_i386_backend_data (info->output_bfd)->is_vxworks)
{
- struct elf_i386_link_hash_entry * eh;
- struct elf_dyn_relocs *p;
-
eh = (struct elf_i386_link_hash_entry *) h;
for (p = eh->dyn_relocs; p != NULL; p = p->next)
{
return TRUE;
}
+/* Convert
+ mov foo@GOT(%reg), %reg
+ to
+ lea foo@GOTOFF(%reg), %reg
+ with the local symbol, foo. */
+
+static bfd_boolean
+elf_i386_convert_mov_to_lea (bfd *abfd, asection *sec,
+ struct bfd_link_info *link_info)
+{
+ Elf_Internal_Shdr *symtab_hdr;
+ Elf_Internal_Rela *internal_relocs;
+ Elf_Internal_Rela *irel, *irelend;
+ bfd_byte *contents;
+ struct elf_i386_link_hash_table *htab;
+ bfd_boolean changed_contents;
+ bfd_boolean changed_relocs;
+ bfd_signed_vma *local_got_refcounts;
+
+ /* Don't even try to convert non-ELF outputs. */
+ if (!is_elf_hash_table (link_info->hash))
+ return FALSE;
+
+ /* Nothing to do if there are no codes, no relocations or no output. */
+ if ((sec->flags & (SEC_CODE | SEC_RELOC)) != (SEC_CODE | SEC_RELOC)
+ || sec->reloc_count == 0
+ || discarded_section (sec))
+ return TRUE;
+
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+
+ /* Load the relocations for this section. */
+ internal_relocs = (_bfd_elf_link_read_relocs
+ (abfd, sec, NULL, (Elf_Internal_Rela *) NULL,
+ link_info->keep_memory));
+ if (internal_relocs == NULL)
+ return FALSE;
+
+ htab = elf_i386_hash_table (link_info);
+ changed_contents = FALSE;
+ changed_relocs = FALSE;
+ local_got_refcounts = elf_local_got_refcounts (abfd);
+
+ /* Get the section contents. */
+ if (elf_section_data (sec)->this_hdr.contents != NULL)
+ contents = elf_section_data (sec)->this_hdr.contents;
+ else
+ {
+ if (!bfd_malloc_and_get_section (abfd, sec, &contents))
+ goto error_return;
+ }
+
+ irelend = internal_relocs + sec->reloc_count;
+ for (irel = internal_relocs; irel < irelend; irel++)
+ {
+ unsigned int r_type = ELF32_R_TYPE (irel->r_info);
+ unsigned int r_symndx = ELF32_R_SYM (irel->r_info);
+ unsigned int indx;
+ struct elf_link_hash_entry *h;
+
+ if (r_type != R_386_GOT32)
+ continue;
+
+ /* Get the symbol referred to by the reloc. */
+ if (r_symndx < symtab_hdr->sh_info)
+ {
+ Elf_Internal_Sym *isym;
+
+ isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+ abfd, r_symndx);
+
+ /* STT_GNU_IFUNC must keep R_386_GOT32 relocation. */
+ if (ELF_ST_TYPE (isym->st_info) != STT_GNU_IFUNC
+ && bfd_get_8 (input_bfd,
+ contents + irel->r_offset - 2) == 0x8b)
+ {
+ bfd_put_8 (output_bfd, 0x8d,
+ contents + irel->r_offset - 2);
+ irel->r_info = ELF32_R_INFO (r_symndx, R_386_GOTOFF);
+ if (local_got_refcounts != NULL
+ && local_got_refcounts[r_symndx] > 0)
+ local_got_refcounts[r_symndx] -= 1;
+ changed_contents = TRUE;
+ changed_relocs = TRUE;
+ }
+ continue;
+ }
+
+ indx = r_symndx - symtab_hdr->sh_info;
+ h = elf_sym_hashes (abfd)[indx];
+ BFD_ASSERT (h != NULL);
+
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+ /* STT_GNU_IFUNC must keep R_386_GOT32 relocation. We also avoid
+ optimizing _DYNAMIC since ld.so may use its link-time address. */
+ if (h->def_regular
+ && h->type != STT_GNU_IFUNC
+ && h != htab->elf.hdynamic
+ && SYMBOL_REFERENCES_LOCAL (link_info, h)
+ && bfd_get_8 (input_bfd,
+ contents + irel->r_offset - 2) == 0x8b)
+ {
+ bfd_put_8 (output_bfd, 0x8d,
+ contents + irel->r_offset - 2);
+ irel->r_info = ELF32_R_INFO (r_symndx, R_386_GOTOFF);
+ if (h->got.refcount > 0)
+ h->got.refcount -= 1;
+ changed_contents = TRUE;
+ changed_relocs = TRUE;
+ }
+ }
+
+ if (contents != NULL
+ && elf_section_data (sec)->this_hdr.contents != contents)
+ {
+ if (!changed_contents && !link_info->keep_memory)
+ free (contents);
+ else
+ {
+ /* Cache the section contents for elf_link_input_bfd. */
+ elf_section_data (sec)->this_hdr.contents = contents;
+ }
+ }
+
+ if (elf_section_data (sec)->relocs != internal_relocs)
+ {
+ if (!changed_relocs)
+ free (internal_relocs);
+ else
+ elf_section_data (sec)->relocs = internal_relocs;
+ }
+
+ return TRUE;
+
+ error_return:
+ if (contents != NULL
+ && elf_section_data (sec)->this_hdr.contents != contents)
+ free (contents);
+ if (internal_relocs != NULL
+ && elf_section_data (sec)->relocs != internal_relocs)
+ free (internal_relocs);
+ return FALSE;
+}
+
/* Set the sizes of the dynamic sections. */
static bfd_boolean
/* 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;
{
struct elf_dyn_relocs *p;
+ if (!elf_i386_convert_mov_to_lea (ibfd, s, info))
+ return FALSE;
+
for (p = ((struct elf_dyn_relocs *)
elf_section_data (s)->local_dynrel);
p != NULL;
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.
-
+
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)
if (htab->elf.sgotplt)
{
- struct elf_link_hash_entry *got;
- got = elf_link_hash_lookup (elf_hash_table (info),
- "_GLOBAL_OFFSET_TABLE_",
- 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_. */
- if ((got == NULL
- || !got->ref_regular_nonweak)
+ entries and there is no reference to _GLOBAL_OFFSET_TABLE_. */
+ if ((htab->elf.hgot == NULL
+ || !htab->elf.hgot->ref_regular_nonweak)
&& (htab->elf.sgotplt->size
== get_elf_backend_data (output_bfd)->got_header_size)
&& (htab->elf.splt == NULL
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;
return FALSE;
}
else if (!info->executable
+ && !SYMBOLIC_BIND (info, h)
&& h->type == STT_FUNC
&& ELF_ST_VISIBILITY (h->other) == STV_PROTECTED)
{
|| plt == NULL
|| gotplt == NULL
|| relplt == NULL)
- return FALSE;
+ abort ();
/* Get the index in the procedure linkage table which
corresponds to this symbol. This is the index of this symbol
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,
0x8b, 0x4b, 0x08, /* mov 0x8(%ebx), %ecx */
0x83, 0xe1, 0xe0, /* and $NACLMASK, %ecx */
0xff, 0xe1, /* jmp *%ecx */
- 0x90 /* nop */
+
+ /* 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] =
#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