X-Git-Url: http://drtracing.org/?a=blobdiff_plain;ds=sidebyside;f=bfd%2Felf32-i386.c;h=f7a7818248dacb534342318f804f88b269cff9f4;hb=bf64a9511f73684c4880fd1818928fdfa1725c4f;hp=d7f59e5e2545a75b3653f82b205f950cc3a52d06;hpb=d1ec1e40b5b457c92aaa23f7af40e026e4596a99;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index d7f59e5e25..f7a7818248 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -1,7 +1,5 @@ /* 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, 2012, 2013 - Free Software Foundation, Inc. + Copyright (C) 1993-2015 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -39,7 +37,7 @@ static reloc_howto_type elf_howto_table[]= { - HOWTO(R_386_NONE, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, + HOWTO(R_386_NONE, 0, 3, 0, FALSE, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_386_NONE", TRUE, 0x00000000, 0x00000000, FALSE), HOWTO(R_386_32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, @@ -381,7 +379,9 @@ elf_i386_rtype_to_howto (bfd *abfd, unsigned r_type) abfd, (int) r_type); indx = R_386_NONE; } - BFD_ASSERT (elf_howto_table [indx].type == r_type); + /* PR 17512: file: 0f67f69d. */ + if (elf_howto_table [indx].type != r_type) + return NULL; return &elf_howto_table[indx]; } @@ -582,6 +582,24 @@ static const bfd_byte elf_i386_pic_plt_entry[PLT_ENTRY_SIZE] = 0, 0, 0, 0 /* replaced with offset to start of .plt. */ }; +/* Entries in the GOT procedure linkage table look like this. */ + +static const bfd_byte elf_i386_got_plt_entry[8] = +{ + 0xff, 0x25, /* jmp indirect */ + 0, 0, 0, 0, /* replaced with offset of this symbol in .got. */ + 0x66, 0x90 /* xchg %ax,%ax */ +}; + +/* Entries in the PIC GOT procedure linkage table look like this. */ + +static const bfd_byte elf_i386_pic_got_plt_entry[8] = +{ + 0xff, 0xa3, /* jmp *offset(%ebx) */ + 0, 0, 0, 0, /* replaced with offset of this symbol in .got. */ + 0x66, 0x90 /* xchg %ax,%ax */ +}; + /* .eh_frame covering the .plt section. */ static const bfd_byte elf_i386_eh_frame_plt[] = @@ -738,6 +756,13 @@ struct elf_i386_link_hash_entry (GOT_TLS_GD_P (type) || GOT_TLS_GDESC_P (type)) unsigned char tls_type; + /* Symbol is referenced by R_386_GOTOFF relocation. */ + unsigned int gotoff_ref : 1; + + /* Information about the GOT PLT entry. Filled when there are both + GOT and PLT relocations against the same function. */ + union gotplt_union plt_got; + /* Offset of the GOTPLT entry reserved for the TLS descriptor, starting at the end of the jump table. */ bfd_vma tlsdesc_got; @@ -787,6 +812,7 @@ struct elf_i386_link_hash_table asection *sdynbss; asection *srelbss; asection *plt_eh_frame; + asection *plt_got; union { @@ -828,7 +854,7 @@ struct elf_i386_link_hash_table == I386_ELF_DATA ? ((struct elf_i386_link_hash_table *) ((p)->hash)) : NULL) #define elf_i386_compute_jump_table_size(htab) \ - ((htab)->next_tls_desc_index * 4) + ((htab)->elf.srelplt->reloc_count * 4) /* Create an entry in an i386 ELF linker hash table. */ @@ -856,6 +882,8 @@ elf_i386_link_hash_newfunc (struct bfd_hash_entry *entry, eh = (struct elf_i386_link_hash_entry *) entry; eh->dyn_relocs = NULL; eh->tls_type = GOT_UNKNOWN; + eh->gotoff_ref = 0; + eh->plt_got.offset = (bfd_vma) -1; eh->tlsdesc_got = (bfd_vma) -1; } @@ -924,11 +952,27 @@ elf_i386_get_local_sym_hash (struct elf_i386_link_hash_table *htab, ret->elf.indx = sec->id; ret->elf.dynstr_index = ELF32_R_SYM (rel->r_info); ret->elf.dynindx = -1; + ret->plt_got.offset = (bfd_vma) -1; *slot = ret; } return &ret->elf; } +/* Destroy an i386 ELF linker hash table. */ + +static void +elf_i386_link_hash_table_free (bfd *obfd) +{ + struct elf_i386_link_hash_table *htab + = (struct elf_i386_link_hash_table *) obfd->link.hash; + + if (htab->loc_hash_table) + htab_delete (htab->loc_hash_table); + if (htab->loc_hash_memory) + objalloc_free ((struct objalloc *) htab->loc_hash_memory); + _bfd_elf_link_hash_table_free (obfd); +} + /* Create an i386 ELF linker hash table. */ static struct bfd_link_hash_table * @@ -957,28 +1001,14 @@ elf_i386_link_hash_table_create (bfd *abfd) ret->loc_hash_memory = objalloc_create (); if (!ret->loc_hash_table || !ret->loc_hash_memory) { - free (ret); + elf_i386_link_hash_table_free (abfd); return NULL; } + ret->elf.root.hash_table_free = elf_i386_link_hash_table_free; return &ret->elf.root; } -/* Destroy an i386 ELF linker hash table. */ - -static void -elf_i386_link_hash_table_free (struct bfd_link_hash_table *hash) -{ - struct elf_i386_link_hash_table *htab - = (struct elf_i386_link_hash_table *) hash; - - if (htab->loc_hash_table) - htab_delete (htab->loc_hash_table); - if (htab->loc_hash_memory) - objalloc_free ((struct objalloc *) htab->loc_hash_memory); - _bfd_elf_link_hash_table_free (hash); -} - /* Create .plt, .rel.plt, .got, .got.plt, .rel.got, .dynbss, and .rel.bss sections in DYNOBJ, and set up shortcuts to them in our hash table. */ @@ -996,13 +1026,28 @@ elf_i386_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info) return FALSE; htab->sdynbss = bfd_get_linker_section (dynobj, ".dynbss"); - if (!info->shared) - htab->srelbss = bfd_get_linker_section (dynobj, ".rel.bss"); - - if (!htab->sdynbss - || (!info->shared && !htab->srelbss)) + if (!htab->sdynbss) abort (); + if (info->executable) + { + /* Always allow copy relocs for building executables. */ + asection *s = bfd_get_linker_section (dynobj, ".rel.bss"); + if (s == NULL) + { + const struct elf_backend_data *bed = get_elf_backend_data (dynobj); + s = bfd_make_section_anyway_with_flags (dynobj, + ".rel.bss", + (bed->dynamic_sec_flags + | SEC_READONLY)); + if (s == NULL + || ! bfd_set_section_alignment (dynobj, s, + bed->s->log_file_align)) + return FALSE; + } + htab->srelbss = s; + } + if (get_elf_i386_backend_data (dynobj)->is_vxworks && !elf_vxworks_create_dynamic_sections (dynobj, info, &htab->srelplt2)) @@ -1075,6 +1120,10 @@ elf_i386_copy_indirect_symbol (struct bfd_link_info *info, eind->tls_type = GOT_UNKNOWN; } + /* Copy gotoff_ref so that elf_i386_adjust_dynamic_symbol will + generate a R_386_COPY reloc. */ + edir->gotoff_ref |= eind->gotoff_ref; + if (ELIMINATE_COPY_RELOCS && ind->root.type != bfd_link_hash_indirect && dir->dynamic_adjusted) @@ -1403,6 +1452,10 @@ elf_i386_tls_transition (struct bfd_link_info *info, bfd *abfd, return TRUE; } +/* Rename some of the generic section flags to better document how they + are used here. */ +#define need_convert_mov_to_lea sec_flg0 + /* Look through the relocs for a section during the first phase, and calculate needed space in the global offset table, procedure linkage table, and dynamic reloc sections. */ @@ -1419,6 +1472,7 @@ elf_i386_check_relocs (bfd *abfd, const Elf_Internal_Rela *rel; const Elf_Internal_Rela *rel_end; asection *sreloc; + bfd_boolean use_plt_got; if (info->relocatable) return TRUE; @@ -1429,6 +1483,10 @@ elf_i386_check_relocs (bfd *abfd, if (htab == NULL) return FALSE; + use_plt_got = (!get_elf_i386_backend_data (abfd)->is_vxworks + && (get_elf_i386_backend_data (abfd) + == &elf_i386_arch_bed)); + symtab_hdr = &elf_symtab_hdr (abfd); sym_hashes = elf_sym_hashes (abfd); @@ -1440,6 +1498,7 @@ elf_i386_check_relocs (bfd *abfd, unsigned int r_type; unsigned long r_symndx; struct elf_link_hash_entry *h; + struct elf_i386_link_hash_entry *eh; Elf_Internal_Sym *isym; const char *name; bfd_boolean size_reloc; @@ -1489,6 +1548,7 @@ elf_i386_check_relocs (bfd *abfd, h = (struct elf_link_hash_entry *) h->root.u.i.link; } + eh = (struct elf_i386_link_hash_entry *) h; if (h != NULL) { /* Create the ifunc sections for static executables. If we @@ -1500,11 +1560,12 @@ elf_i386_check_relocs (bfd *abfd, default: break; + case R_386_GOTOFF: + eh->gotoff_ref = 1; case R_386_32: case R_386_PC32: case R_386_PLT32: case R_386_GOT32: - case R_386_GOTOFF: if (htab->elf.dynobj == NULL) htab->elf.dynobj = abfd; if (!_bfd_elf_create_ifunc_sections (htab->elf.dynobj, info)) @@ -1756,7 +1817,7 @@ do_size: relocations we need for this symbol. */ if (h != NULL) { - head = &((struct elf_i386_link_hash_entry *) h)->dyn_relocs; + head = &eh->dyn_relocs; } else { @@ -1820,6 +1881,43 @@ do_size: default: break; } + + if (use_plt_got + && h != NULL + && h->plt.refcount > 0 + && h->got.refcount > 0 + && htab->plt_got == NULL) + { + /* Create the GOT procedure linkage table. */ + unsigned int plt_got_align; + const struct elf_backend_data *bed; + + bed = get_elf_backend_data (info->output_bfd); + BFD_ASSERT (sizeof (elf_i386_got_plt_entry) == 8 + && (sizeof (elf_i386_got_plt_entry) + == sizeof (elf_i386_pic_got_plt_entry))); + plt_got_align = 3; + + if (htab->elf.dynobj == NULL) + htab->elf.dynobj = abfd; + htab->plt_got + = bfd_make_section_anyway_with_flags (htab->elf.dynobj, + ".plt.got", + (bed->dynamic_sec_flags + | SEC_ALLOC + | SEC_CODE + | SEC_LOAD + | SEC_READONLY)); + if (htab->plt_got == NULL + || !bfd_set_section_alignment (htab->elf.dynobj, + htab->plt_got, + plt_got_align)) + return FALSE; + } + + if (r_type == R_386_GOT32 + && (h == NULL || h->type != STT_GNU_IFUNC)) + sec->need_convert_mov_to_lea = 1; } return TRUE; @@ -2103,12 +2201,14 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info, only references to the symbol are via the global offset table. For such cases we need not do anything here; the relocations will be handled correctly by relocate_section. */ - if (info->shared) + if (!info->executable) return TRUE; /* If there are no references to this symbol that do not use the - GOT, we don't need to generate a copy reloc. */ - if (!h->non_got_ref) + GOT nor R_386_GOTOFF relocation, we don't need to generate a copy + reloc. */ + eh = (struct elf_i386_link_hash_entry *) h; + if (!h->non_got_ref && !eh->gotoff_ref) return TRUE; /* If -z nocopyreloc was given, we won't generate them either. */ @@ -2122,14 +2222,15 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info, if (htab == NULL) return FALSE; - /* If there aren't any dynamic relocs in read-only sections, then - we can keep the dynamic relocs and avoid the copy reloc. This - doesn't work on VxWorks, where we can not have dynamic relocations - (other than copy and jump slot relocations) in an executable. */ + /* If there aren't any dynamic relocs in read-only sections nor + R_386_GOTOFF relocation, then we can keep the dynamic relocs and + avoid the copy reloc. This doesn't work on VxWorks, where we can + not have dynamic relocations (other than copy and jump slot + relocations) in an executable. */ if (ELIMINATE_COPY_RELOCS + && !eh->gotoff_ref && !get_elf_i386_backend_data (info->output_bfd)->is_vxworks) { - eh = (struct elf_i386_link_hash_entry *) h; for (p = eh->dyn_relocs; p != NULL; p = p->next) { s = p->sec->output_section; @@ -2165,7 +2266,7 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info, s = htab->sdynbss; - return _bfd_elf_adjust_dynamic_copy (h, s); + return _bfd_elf_adjust_dynamic_copy (info, h, s); } /* Allocate space in .plt, .got and associated reloc sections for @@ -2192,6 +2293,24 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) plt_entry_size = GET_PLT_ENTRY_SIZE (info->output_bfd); + /* We can't use the GOT PLT if pointer equality is needed since + finish_dynamic_symbol won't clear symbol value and the dynamic + linker won't update the GOT slot. We will get into an infinite + loop at run-time. */ + if (htab->plt_got != NULL + && h->type != STT_GNU_IFUNC + && !h->pointer_equality_needed + && h->plt.refcount > 0 + && h->got.refcount > 0) + { + /* Don't use the regular PLT if there are both GOT and GOTPLT + reloctions. */ + h->plt.offset = (bfd_vma) -1; + + /* Use the GOT PLT. */ + eh->plt_got.refcount = 1; + } + /* Since STT_GNU_IFUNC symbol must go through PLT, we handle it here if it is defined and referenced in a non-shared object. */ if (h->type == STT_GNU_IFUNC @@ -2200,8 +2319,10 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) plt_entry_size, plt_entry_size, 4); else if (htab->elf.dynamic_sections_created - && h->plt.refcount > 0) + && (h->plt.refcount > 0 || eh->plt_got.refcount > 0)) { + bfd_boolean use_plt_got = eh->plt_got.refcount > 0; + /* Make sure this symbol is output as a dynamic symbol. Undefined weak syms won't yet be marked as dynamic. */ if (h->dynindx == -1 @@ -2215,13 +2336,17 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h)) { asection *s = htab->elf.splt; + asection *got_s = htab->plt_got; /* If this is the first .plt entry, make room for the special first entry. */ if (s->size == 0) s->size = plt_entry_size; - h->plt.offset = s->size; + if (use_plt_got) + eh->plt_got.offset = got_s->size; + else + h->plt.offset = s->size; /* If this symbol is not defined in a regular file, and we are not generating a shared library, then set the symbol to this @@ -2231,20 +2356,36 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) if (! info->shared && !h->def_regular) { - h->root.u.def.section = s; - h->root.u.def.value = h->plt.offset; + if (use_plt_got) + { + /* We need to make a call to the entry of the GOT PLT + instead of regular PLT entry. */ + h->root.u.def.section = got_s; + h->root.u.def.value = eh->plt_got.offset; + } + else + { + h->root.u.def.section = s; + h->root.u.def.value = h->plt.offset; + } } /* Make room for this entry. */ - s->size += plt_entry_size; + if (use_plt_got) + got_s->size += sizeof (elf_i386_got_plt_entry); + else + { + 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. */ - htab->elf.sgotplt->size += 4; + /* We also need to make an entry in the .got.plt section, + which will be placed in the .got section by the linker + script. */ + htab->elf.sgotplt->size += 4; - /* We also need to make an entry in the .rel.plt section. */ - htab->elf.srelplt->size += sizeof (Elf32_External_Rel); - htab->elf.srelplt->reloc_count++; + /* We also need to make an entry in the .rel.plt section. */ + htab->elf.srelplt->size += sizeof (Elf32_External_Rel); + htab->elf.srelplt->reloc_count++; + } if (get_elf_i386_backend_data (info->output_bfd)->is_vxworks && !info->shared) @@ -2368,13 +2509,8 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) { - /* Don't update reloc count if there are any non - pc-relative relocs. */ - if (!h->pointer_equality_needed) - { - p->count -= p->pc_count; - p->pc_count = 0; - } + p->count -= p->pc_count; + p->pc_count = 0; if (p->count == 0) *pp = p->next; else @@ -2501,8 +2637,9 @@ elf_i386_readonly_dynrelocs (struct elf_link_hash_entry *h, void *inf) info->flags |= DF_TEXTREL; - if (info->warn_shared_textrel && info->shared) - info->callbacks->einfo (_("%P: %B: warning: relocation against `%s' in readonly section `%A'.\n"), + if ((info->warn_shared_textrel && info->shared) + || info->error_textrel) + info->callbacks->einfo (_("%P: %B: warning: relocation against `%s' in readonly section `%A'\n"), p->sec->owner, h->root.root.string, p->sec); @@ -2536,10 +2673,10 @@ elf_i386_convert_mov_to_lea (bfd *abfd, asection *sec, if (!is_elf_hash_table (link_info->hash)) return FALSE; - /* Nothing to do if there are no codes, no relocations or no output. */ + /* Nothing to do if there is no need or no output. */ if ((sec->flags & (SEC_CODE | SEC_RELOC)) != (SEC_CODE | SEC_RELOC) - || sec->reloc_count == 0 - || discarded_section (sec)) + || sec->need_convert_mov_to_lea == 0 + || bfd_is_abs_section (sec->output_section)) return TRUE; symtab_hdr = &elf_tdata (abfd)->symtab_hdr; @@ -2586,11 +2723,10 @@ elf_i386_convert_mov_to_lea (bfd *abfd, asection *sec, /* 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) + && irel->r_offset >= 2 + && bfd_get_8 (abfd, contents + irel->r_offset - 2) == 0x8b) { - bfd_put_8 (output_bfd, 0x8d, - contents + irel->r_offset - 2); + bfd_put_8 (abfd, 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) @@ -2615,11 +2751,10 @@ elf_i386_convert_mov_to_lea (bfd *abfd, asection *sec, && 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) + && irel->r_offset >= 2 + && bfd_get_8 (abfd, contents + irel->r_offset - 2) == 0x8b) { - bfd_put_8 (output_bfd, 0x8d, - contents + irel->r_offset - 2); + bfd_put_8 (abfd, 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; @@ -2693,7 +2828,7 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) /* Set up .got offsets for local syms, and space for local dynamic relocs. */ - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) { bfd_signed_vma *local_got; bfd_signed_vma *end_local_got; @@ -2741,8 +2876,9 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) && (info->flags & DF_TEXTREL) == 0) { info->flags |= DF_TEXTREL; - if (info->warn_shared_textrel && info->shared) - info->callbacks->einfo (_("%P: %B: warning: relocation in readonly section `%A'.\n"), + if ((info->warn_shared_textrel && info->shared) + || info->error_textrel) + info->callbacks->einfo (_("%P: %B: warning: relocation in readonly section `%A'\n"), p->sec->owner, p->sec); } } @@ -2890,6 +3026,7 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) else if (s == htab->elf.sgotplt || s == htab->elf.iplt || s == htab->elf.igotplt + || s == htab->plt_got || s == htab->plt_eh_frame || s == htab->sdynbss) { @@ -3039,6 +3176,7 @@ elf_i386_always_size_sections (bfd *output_bfd, tlsbase = (struct elf_link_hash_entry *)bh; tlsbase->def_regular = 1; tlsbase->other = STV_HIDDEN; + tlsbase->root.linker_def = 1; (*bed->elf_backend_hide_symbol) (info, tlsbase, TRUE); } } @@ -3187,15 +3325,17 @@ elf_i386_relocate_section (bfd *output_bfd, reloc_howto_type *howto; unsigned long r_symndx; struct elf_link_hash_entry *h; + struct elf_i386_link_hash_entry *eh; Elf_Internal_Sym *sym; asection *sec; - bfd_vma off, offplt; + bfd_vma off, offplt, plt_offset; bfd_vma relocation; bfd_boolean unresolved_reloc; bfd_reloc_status_type r; unsigned int indx; int tls_type; bfd_vma st_size; + asection *resolved_plt; r_type = ELF32_R_TYPE (rel->r_info); if (r_type == R_386_GNU_VTINHERIT @@ -3599,11 +3739,11 @@ elf_i386_relocate_section (bfd *output_bfd, /* Relocation is relative to the start of the global offset table. */ - /* Check to make sure it isn't a protected function symbol - for shared library since it may not be local when used - as function address. We also need to make sure that a - symbol is defined locally. */ - if (info->shared && h) + /* Check to make sure it isn't a protected function or data + symbol for shared library since it may not be local when + used as function address or with copy relocation. We also + need to make sure that a symbol is referenced locally. */ + if (!info->executable && h) { if (!h->def_regular) { @@ -3631,14 +3771,16 @@ elf_i386_relocate_section (bfd *output_bfd, bfd_set_error (bfd_error_bad_value); return FALSE; } - else if (!info->executable - && !SYMBOLIC_BIND (info, h) - && h->type == STT_FUNC + else if (!SYMBOL_REFERENCES_LOCAL (info, h) + && (h->type == STT_FUNC + || h->type == STT_OBJECT) && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED) { (*_bfd_error_handler) - (_("%B: relocation R_386_GOTOFF against protected function `%s' can not be used when making a shared object"), - input_bfd, h->root.root.string); + (_("%B: relocation R_386_GOTOFF against protected %s `%s' can not be used when making a shared object"), + input_bfd, + h->type == STT_FUNC ? "function" : "data", + h->root.root.string); bfd_set_error (bfd_error_bad_value); return FALSE; } @@ -3669,7 +3811,9 @@ elf_i386_relocate_section (bfd *output_bfd, if (h == NULL) break; - if (h->plt.offset == (bfd_vma) -1 + eh = (struct elf_i386_link_hash_entry *) h; + if ((h->plt.offset == (bfd_vma) -1 + && eh->plt_got.offset == (bfd_vma) -1) || htab->elf.splt == NULL) { /* We didn't make a PLT entry for this symbol. This @@ -3678,9 +3822,20 @@ elf_i386_relocate_section (bfd *output_bfd, break; } - relocation = (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset - + h->plt.offset); + if (h->plt.offset != (bfd_vma) -1) + { + resolved_plt = htab->elf.splt; + plt_offset = h->plt.offset; + } + else + { + resolved_plt = htab->plt_got; + plt_offset = eh->plt_got.offset; + } + + relocation = (resolved_plt->output_section->vma + + resolved_plt->output_offset + + plt_offset); unresolved_reloc = FALSE; break; @@ -4431,6 +4586,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, struct elf_i386_link_hash_table *htab; unsigned plt_entry_size; const struct elf_i386_backend_data *abed; + struct elf_i386_link_hash_entry *eh; htab = elf_i386_hash_table (info); if (htab == NULL) @@ -4439,6 +4595,8 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, abed = get_elf_i386_backend_data (output_bfd); plt_entry_size = GET_PLT_ENTRY_SIZE (output_bfd); + eh = (struct elf_i386_link_hash_entry *) h; + if (h->plt.offset != (bfd_vma) -1) { bfd_vma plt_index; @@ -4603,21 +4761,65 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, plt->contents + h->plt.offset + abed->plt->plt_plt_offset); } + } + else if (eh->plt_got.offset != (bfd_vma) -1) + { + bfd_vma got_offset, plt_offset; + asection *plt, *got, *gotplt; + const bfd_byte *got_plt_entry; + + /* Offset of displacement of the indirect jump. */ + bfd_vma plt_got_offset = 2; + + /* Set the entry in the GOT procedure linkage table. */ + plt = htab->plt_got; + got = htab->elf.sgot; + gotplt = htab->elf.sgotplt; + got_offset = h->got.offset; + + if (got_offset == (bfd_vma) -1 + || plt == NULL + || got == NULL + || gotplt == NULL) + abort (); - if (!h->def_regular) + /* Fill in the entry in the GOT procedure linkage table. */ + if (! info->shared) + { + got_plt_entry = elf_i386_got_plt_entry; + got_offset += got->output_section->vma + got->output_offset; + } + else { - /* Mark the symbol as undefined, rather than as defined in - the .plt section. Leave the value if there were any - relocations where pointer equality matters (this is a clue - for the dynamic linker, to make function pointer - comparisons work between an application and shared - library), otherwise set it to zero. If a function is only - called from a binary, there is no need to slow down - shared libraries because of that. */ - sym->st_shndx = SHN_UNDEF; - if (!h->pointer_equality_needed) - sym->st_value = 0; + got_plt_entry = elf_i386_pic_got_plt_entry; + got_offset += (got->output_section->vma + + got->output_offset + - gotplt->output_section->vma + - gotplt->output_offset); } + + plt_offset = eh->plt_got.offset; + memcpy (plt->contents + plt_offset, got_plt_entry, + sizeof (elf_i386_got_plt_entry)); + bfd_put_32 (output_bfd, got_offset, + plt->contents + plt_offset + plt_got_offset); + } + + if (!h->def_regular + && (h->plt.offset != (bfd_vma) -1 + || eh->plt_got.offset != (bfd_vma) -1)) + { + /* Mark the symbol as undefined, rather than as defined in + the .plt section. Leave the value if there were any + relocations where pointer equality matters (this is a clue + for the dynamic linker, to make function pointer + comparisons work between an application and shared + library), otherwise set it to zero. If a function is only + called from a binary, there is no need to slow down + shared libraries because of that. */ + sym->st_shndx = SHN_UNDEF; + if (!h->pointer_equality_needed) + sym->st_value = 0; } if (h->got.offset != (bfd_vma) -1 @@ -4982,14 +5184,91 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd, return TRUE; } -/* Return address for Ith PLT stub in section PLT, for relocation REL - or (bfd_vma) -1 if it should not be included. */ +/* Return an array of PLT entry symbol values. */ -static bfd_vma -elf_i386_plt_sym_val (bfd_vma i, const asection *plt, - const arelent *rel ATTRIBUTE_UNUSED) +static bfd_vma * +elf_i386_get_plt_sym_val (bfd *abfd, asymbol **dynsyms, asection *plt, + asection *relplt) { - return plt->vma + (i + 1) * GET_PLT_ENTRY_SIZE (plt->owner); + bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean); + arelent *p; + long count, i; + bfd_vma *plt_sym_val; + bfd_vma plt_offset; + bfd_byte *plt_contents; + const struct elf_i386_backend_data *bed + = get_elf_i386_backend_data (abfd); + Elf_Internal_Shdr *hdr; + + /* Get the .plt section contents. */ + plt_contents = (bfd_byte *) bfd_malloc (plt->size); + if (plt_contents == NULL) + return NULL; + if (!bfd_get_section_contents (abfd, (asection *) plt, + plt_contents, 0, plt->size)) + { +bad_return: + free (plt_contents); + return NULL; + } + + slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table; + if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE)) + goto bad_return; + + hdr = &elf_section_data (relplt)->this_hdr; + count = relplt->size / hdr->sh_entsize; + + plt_sym_val = (bfd_vma *) bfd_malloc (sizeof (bfd_vma) * count); + if (plt_sym_val == NULL) + goto bad_return; + + for (i = 0; i < count; i++) + plt_sym_val[i] = -1; + + plt_offset = bed->plt->plt_entry_size; + p = relplt->relocation; + for (i = 0; i < count; i++, p++) + { + long reloc_index; + + /* Skip unknown relocation. PR 17512: file: bc9d6cf5. */ + if (p->howto == NULL) + continue; + + if (p->howto->type != R_386_JUMP_SLOT + && p->howto->type != R_386_IRELATIVE) + continue; + + reloc_index = H_GET_32 (abfd, (plt_contents + plt_offset + + bed->plt->plt_reloc_offset)); + reloc_index /= sizeof (Elf32_External_Rel); + if (reloc_index >= count) + abort (); + plt_sym_val[reloc_index] = plt->vma + plt_offset; + plt_offset += bed->plt->plt_entry_size; + } + + free (plt_contents); + + return plt_sym_val; +} + +/* Similar to _bfd_elf_get_synthetic_symtab. */ + +static long +elf_i386_get_synthetic_symtab (bfd *abfd, + long symcount, + asymbol **syms, + long dynsymcount, + asymbol **dynsyms, + asymbol **ret) +{ + asection *plt = bfd_get_section_by_name (abfd, ".plt"); + return _bfd_elf_ifunc_get_synthetic_symtab (abfd, symcount, syms, + dynsymcount, dynsyms, ret, + plt, + elf_i386_get_plt_sym_val); } /* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */ @@ -5010,22 +5289,23 @@ elf_i386_hash_symbol (struct elf_link_hash_entry *h) static bfd_boolean elf_i386_add_symbol_hook (bfd * abfd, - struct bfd_link_info * info ATTRIBUTE_UNUSED, + struct bfd_link_info * info, Elf_Internal_Sym * sym, const char ** namep ATTRIBUTE_UNUSED, flagword * flagsp ATTRIBUTE_UNUSED, asection ** secp ATTRIBUTE_UNUSED, bfd_vma * valp ATTRIBUTE_UNUSED) { - if ((abfd->flags & DYNAMIC) == 0 - && (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC - || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE)) + if ((ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC + || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE) + && (abfd->flags & DYNAMIC) == 0 + && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour) elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE; return TRUE; } -#define TARGET_LITTLE_SYM bfd_elf32_i386_vec +#define TARGET_LITTLE_SYM i386_elf32_vec #define TARGET_LITTLE_NAME "elf32-i386" #define ELF_ARCH bfd_arch_i386 #define ELF_TARGET_ID I386_ELF_DATA @@ -5039,6 +5319,7 @@ elf_i386_add_symbol_hook (bfd * abfd, #define elf_backend_want_plt_sym 0 #define elf_backend_got_header_size 12 #define elf_backend_plt_alignment 4 +#define elf_backend_extern_protected_data 1 /* Support RELA for objdump of prelink objects. */ #define elf_info_to_howto elf_i386_info_to_howto_rel @@ -5048,9 +5329,9 @@ elf_i386_add_symbol_hook (bfd * abfd, #define bfd_elf32_bfd_is_local_label_name elf_i386_is_local_label_name #define bfd_elf32_bfd_link_hash_table_create elf_i386_link_hash_table_create -#define bfd_elf32_bfd_link_hash_table_free elf_i386_link_hash_table_free #define bfd_elf32_bfd_reloc_type_lookup elf_i386_reloc_type_lookup #define bfd_elf32_bfd_reloc_name_lookup elf_i386_reloc_name_lookup +#define bfd_elf32_get_synthetic_symtab elf_i386_get_synthetic_symtab #define elf_backend_adjust_dynamic_symbol elf_i386_adjust_dynamic_symbol #define elf_backend_relocs_compatible _bfd_elf_relocs_compatible @@ -5070,7 +5351,6 @@ elf_i386_add_symbol_hook (bfd * abfd, #define elf_backend_always_size_sections elf_i386_always_size_sections #define elf_backend_omit_section_dynsym \ ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true) -#define elf_backend_plt_sym_val elf_i386_plt_sym_val #define elf_backend_hash_symbol elf_i386_hash_symbol #define elf_backend_add_symbol_hook elf_i386_add_symbol_hook @@ -5079,7 +5359,7 @@ elf_i386_add_symbol_hook (bfd * abfd, /* FreeBSD support. */ #undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM bfd_elf32_i386_freebsd_vec +#define TARGET_LITTLE_SYM i386_elf32_fbsd_vec #undef TARGET_LITTLE_NAME #define TARGET_LITTLE_NAME "elf32-i386-freebsd" #undef ELF_OSABI @@ -5095,8 +5375,11 @@ elf_i386_fbsd_post_process_headers (bfd *abfd, struct bfd_link_info *info) _bfd_elf_post_process_headers (abfd, info); #ifdef OLD_FREEBSD_ABI_LABEL - /* The ABI label supported by FreeBSD <= 4.0 is quite nonstandard. */ - memcpy (&i_ehdrp->e_ident[EI_ABIVERSION], "FreeBSD", 8); + { + /* The ABI label supported by FreeBSD <= 4.0 is quite nonstandard. */ + Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd); + memcpy (&i_ehdrp->e_ident[EI_ABIVERSION], "FreeBSD", 8); + } #endif } @@ -5112,10 +5395,12 @@ elf_i386_fbsd_post_process_headers (bfd *abfd, struct bfd_link_info *info) /* Solaris 2. */ #undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM bfd_elf32_i386_sol2_vec +#define TARGET_LITTLE_SYM i386_elf32_sol2_vec #undef TARGET_LITTLE_NAME #define TARGET_LITTLE_NAME "elf32-i386-sol2" +#undef elf_backend_post_process_headers + /* Restore default: we cannot use ELFOSABI_SOLARIS, otherwise ELFOSABI_NONE objects won't be recognized. */ #undef ELF_OSABI @@ -5137,10 +5422,51 @@ elf_i386_fbsd_post_process_headers (bfd *abfd, struct bfd_link_info *info) #include "elf32-target.h" +/* Intel MCU support. */ + +static bfd_boolean +elf32_iamcu_elf_object_p (bfd *abfd) +{ + /* Set the right machine number for an IAMCU elf32 file. */ + bfd_default_set_arch_mach (abfd, bfd_arch_iamcu, bfd_mach_i386_iamcu); + return TRUE; +} + +#undef TARGET_LITTLE_SYM +#define TARGET_LITTLE_SYM iamcu_elf32_vec +#undef TARGET_LITTLE_NAME +#define TARGET_LITTLE_NAME "elf32-iamcu" +#undef ELF_ARCH +#define ELF_ARCH bfd_arch_iamcu + +#undef ELF_MACHINE_CODE +#define ELF_MACHINE_CODE EM_IAMCU + +#undef ELF_OSABI + +#undef elf32_bed +#define elf32_bed elf32_iamcu_bed + +#undef elf_backend_object_p +#define elf_backend_object_p elf32_iamcu_elf_object_p + +#undef elf_backend_static_tls_alignment + +#undef elf_backend_want_plt_sym +#define elf_backend_want_plt_sym 0 + +#include "elf32-target.h" + +/* Restore defaults. */ +#undef ELF_ARCH +#define ELF_ARCH bfd_arch_i386 +#undef ELF_MACHINE_CODE +#define ELF_MACHINE_CODE EM_386 + /* Native Client support. */ #undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM bfd_elf32_i386_nacl_vec +#define TARGET_LITTLE_SYM i386_elf32_nacl_vec #undef TARGET_LITTLE_NAME #define TARGET_LITTLE_NAME "elf32-i386-nacl" #undef elf32_bed @@ -5329,7 +5655,7 @@ elf32_i386_nacl_elf_object_p (bfd *abfd) /* VxWorks support. */ #undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM bfd_elf32_i386_vxworks_vec +#define TARGET_LITTLE_SYM i386_elf32_vxworks_vec #undef TARGET_LITTLE_NAME #define TARGET_LITTLE_NAME "elf32-i386-vxworks" #undef ELF_OSABI