windows-nat: Replace __COPY_CONTEXT_SIZE conditional with __CYGWIN__
[deliverable/binutils-gdb.git] / bfd / elf32-i386.c
index 7ef1fc1ec5d73c1ed93b1f705fe104b5993a21ac..f3aee96822f659383c04f06100cff179eec136f2 100644 (file)
@@ -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
-   Free Software Foundation, Inc.
+   Copyright (C) 1993-2015 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
@@ -25,6 +23,7 @@
 #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"
@@ -38,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,
@@ -132,7 +131,9 @@ static reloc_howto_type elf_howto_table[]=
   HOWTO(R_386_TLS_TPOFF32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
        bfd_elf_generic_reloc, "R_386_TLS_TPOFF32",
        TRUE, 0xffffffff, 0xffffffff, FALSE),
-  EMPTY_HOWTO (38),
+  HOWTO(R_386_SIZE32, 0, 2, 32, FALSE, 0, complain_overflow_unsigned,
+       bfd_elf_generic_reloc, "R_386_SIZE32",
+       TRUE, 0xffffffff, 0xffffffff, FALSE),
   HOWTO(R_386_TLS_GOTDESC, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
        bfd_elf_generic_reloc, "R_386_TLS_GOTDESC",
        TRUE, 0xffffffff, 0xffffffff, FALSE),
@@ -311,6 +312,10 @@ elf_i386_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
       TRACE ("BFD_RELOC_386_TLS_TPOFF32");
       return &elf_howto_table[R_386_TLS_TPOFF32 - R_386_tls_offset];
 
+    case BFD_RELOC_SIZE32:
+      TRACE ("BFD_RELOC_SIZE32");
+      return &elf_howto_table[R_386_SIZE32 - R_386_tls_offset];
+
     case BFD_RELOC_386_TLS_GOTDESC:
       TRACE ("BFD_RELOC_386_TLS_GOTDESC");
       return &elf_howto_table[R_386_TLS_GOTDESC - R_386_tls_offset];
@@ -374,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];
 }
 
@@ -418,10 +425,10 @@ elf_i386_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
        return FALSE;
 
       /* pr_cursig */
-      elf_tdata (abfd)->core_signal = bfd_get_32 (abfd, note->descdata + 20);
+      elf_tdata (abfd)->core->signal = bfd_get_32 (abfd, note->descdata + 20);
 
       /* pr_pid */
-      elf_tdata (abfd)->core_lwpid = bfd_get_32 (abfd, note->descdata + 24);
+      elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 24);
 
       /* pr_reg */
       offset = 28;
@@ -436,10 +443,10 @@ elf_i386_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
 
        case 144:               /* Linux/i386 */
          /* pr_cursig */
-         elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12);
+         elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12);
 
          /* pr_pid */
-         elf_tdata (abfd)->core_lwpid = bfd_get_32 (abfd, note->descdata + 24);
+         elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 24);
 
          /* pr_reg */
          offset = 72;
@@ -464,9 +471,9 @@ elf_i386_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
       if (pr_version != 1)
        return FALSE;
 
-      elf_tdata (abfd)->core_program
+      elf_tdata (abfd)->core->program
        = _bfd_elfcore_strndup (abfd, note->descdata + 8, 17);
-      elf_tdata (abfd)->core_command
+      elf_tdata (abfd)->core->command
        = _bfd_elfcore_strndup (abfd, note->descdata + 25, 81);
     }
   else
@@ -477,11 +484,11 @@ elf_i386_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
          return FALSE;
 
        case 124:               /* Linux/i386 elf_prpsinfo.  */
-         elf_tdata (abfd)->core_pid
+         elf_tdata (abfd)->core->pid
            = bfd_get_32 (abfd, note->descdata + 12);
-         elf_tdata (abfd)->core_program
+         elf_tdata (abfd)->core->program
            = _bfd_elfcore_strndup (abfd, note->descdata + 28, 16);
-         elf_tdata (abfd)->core_command
+         elf_tdata (abfd)->core->command
            = _bfd_elfcore_strndup (abfd, note->descdata + 44, 80);
        }
     }
@@ -490,7 +497,7 @@ elf_i386_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
      onto the end of the args in some (at least one anyway)
      implementations, so strip it off if it exists.  */
   {
-    char *command = elf_tdata (abfd)->core_command;
+    char *command = elf_tdata (abfd)->core->command;
     int n = strlen (command);
 
     if (0 < n && command[n - 1] == ' ')
@@ -575,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[] =
@@ -731,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;
@@ -780,6 +812,7 @@ struct elf_i386_link_hash_table
   asection *sdynbss;
   asection *srelbss;
   asection *plt_eh_frame;
+  asection *plt_got;
 
   union
   {
@@ -806,6 +839,12 @@ struct elf_i386_link_hash_table
 
   /* 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.  */
@@ -815,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.  */
 
@@ -843,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;
     }
 
@@ -911,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 *
@@ -924,7 +981,7 @@ elf_i386_link_hash_table_create (bfd *abfd)
   struct elf_i386_link_hash_table *ret;
   bfd_size_type amt = sizeof (struct elf_i386_link_hash_table);
 
-  ret = (struct elf_i386_link_hash_table *) bfd_malloc (amt);
+  ret = (struct elf_i386_link_hash_table *) bfd_zmalloc (amt);
   if (ret == NULL)
     return NULL;
 
@@ -937,16 +994,6 @@ elf_i386_link_hash_table_create (bfd *abfd)
       return NULL;
     }
 
-  ret->sdynbss = NULL;
-  ret->srelbss = NULL;
-  ret->plt_eh_frame = NULL;
-  ret->tls_ldm_got.refcount = 0;
-  ret->next_tls_desc_index = 0;
-  ret->sgotplt_jump_table_size = 0;
-  ret->sym_cache.abfd = NULL;
-  ret->srelplt2 = NULL;
-  ret->tls_module_base = NULL;
-
   ret->loc_hash_table = htab_try_create (1024,
                                         elf_i386_local_htab_hash,
                                         elf_i386_local_htab_eq,
@@ -954,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_generic_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.  */
@@ -992,36 +1025,46 @@ elf_i386_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
   if (htab == NULL)
     return FALSE;
 
-  htab->sdynbss = bfd_get_section_by_name (dynobj, ".dynbss");
-  if (!info->shared)
-    htab->srelbss = bfd_get_section_by_name (dynobj, ".rel.bss");
-
-  if (!htab->sdynbss
-      || (!info->shared && !htab->srelbss))
+  htab->sdynbss = bfd_get_linker_section (dynobj, ".dynbss");
+  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))
     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;
@@ -1077,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)
@@ -1405,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.  */
@@ -1421,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;
@@ -1431,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);
 
@@ -1442,8 +1498,10 @@ 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;
 
       r_symndx = ELF32_R_SYM (rel->r_info);
       r_type = ELF32_R_TYPE (rel->r_info);
@@ -1490,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
@@ -1501,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))
@@ -1513,73 +1573,9 @@ elf_i386_check_relocs (bfd *abfd,
              break;
            }
 
-         /* Since STT_GNU_IFUNC symbol must go through PLT, we handle
-            it here if it is defined in a non-shared object.  */
-         if (h->type == STT_GNU_IFUNC
-             && h->def_regular)
-           {
-             /* It is referenced by a non-shared object. */
-             h->ref_regular = 1;
-             h->needs_plt = 1;
-
-             /* STT_GNU_IFUNC symbol must go through PLT.  */
-             h->plt.refcount += 1;
-
-             /* STT_GNU_IFUNC needs dynamic sections.  */
-             if (htab->elf.dynobj == NULL)
-               htab->elf.dynobj = abfd;
-
-             switch (r_type)
-               {
-               default:
-                 if (h->root.root.string)
-                   name = h->root.root.string;
-                 else
-                   name = bfd_elf_sym_name (abfd, symtab_hdr, isym,
-                                            NULL);
-                 (*_bfd_error_handler)
-                   (_("%B: relocation %s against STT_GNU_IFUNC "
-                      "symbol `%s' isn't handled by %s"), abfd,
-                    elf_howto_table[r_type].name,
-                    name, __FUNCTION__);
-                 bfd_set_error (bfd_error_bad_value);
-                 return FALSE;
-
-               case R_386_32:
-                 h->non_got_ref = 1;
-                 h->pointer_equality_needed = 1;
-                 if (info->shared)
-                   {
-                     /* We must copy these reloc types into the
-                        output file.  Create a reloc section in
-                        dynobj and make room for this reloc.  */
-                     sreloc = _bfd_elf_create_ifunc_dyn_reloc
-                       (abfd, info, sec, sreloc,
-                        &((struct elf_i386_link_hash_entry *) h)->dyn_relocs);
-                     if (sreloc == NULL)
-                       return FALSE;
-                   }
-                 break;
-
-               case R_386_PC32:
-                 h->non_got_ref = 1;
-                 break;
-
-               case R_386_PLT32:
-                 break;
-
-               case R_386_GOT32:
-               case R_386_GOTOFF:
-                 h->got.refcount += 1;
-                 if (htab->elf.sgot == NULL
-                     && !_bfd_elf_create_got_section (htab->elf.dynobj,
-                                                      info))
-                   return FALSE;
-                 break;
-               }
-
-             continue;
-           }
+         /* It is referenced by a non-shared object. */
+         h->ref_regular = 1;
+         h->root.non_ir_ref = 1;
        }
 
       if (! elf_i386_tls_transition (info, abfd, sec, NULL,
@@ -1611,6 +1607,10 @@ elf_i386_check_relocs (bfd *abfd,
          h->plt.refcount += 1;
          break;
 
+       case R_386_SIZE32:
+         size_reloc = TRUE;
+         goto do_size;
+
        case R_386_TLS_IE_32:
        case R_386_TLS_IE:
        case R_386_TLS_GOTIE:
@@ -1703,6 +1703,7 @@ elf_i386_check_relocs (bfd *abfd,
                      (_("%B: `%s' accessed both as normal and "
                         "thread local symbol"),
                       abfd, name);
+                   bfd_set_error (bfd_error_bad_value);
                    return FALSE;
                  }
              }
@@ -1757,6 +1758,8 @@ elf_i386_check_relocs (bfd *abfd,
                h->pointer_equality_needed = 1;
            }
 
+         size_reloc = FALSE;
+do_size:
          /* If we are creating a shared library, and this is a reloc
             against a global symbol, or a non PC relative reloc
             against a local symbol, then we need to copy the reloc
@@ -1814,7 +1817,7 @@ elf_i386_check_relocs (bfd *abfd,
                 relocations we need for this symbol.  */
              if (h != NULL)
                {
-                 head = &((struct elf_i386_link_hash_entry *) h)->dyn_relocs;
+                 head = &eh->dyn_relocs;
                }
              else
                {
@@ -1853,7 +1856,8 @@ elf_i386_check_relocs (bfd *abfd,
                }
 
              p->count += 1;
-             if (r_type == R_386_PC32)
+             /* Count size relocation as PC-relative relocation.  */
+             if (r_type == R_386_PC32 || size_reloc)
                p->pc_count += 1;
            }
          break;
@@ -1877,6 +1881,44 @@ elf_i386_check_relocs (bfd *abfd,
        default:
          break;
        }
+
+      if (use_plt_got
+         && h != NULL
+         && h->plt.refcount > 0
+         && (((info->flags & DF_BIND_NOW) && !h->pointer_equality_needed)
+             || 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;
@@ -2019,6 +2061,7 @@ elf_i386_gc_sweep_hook (bfd *abfd,
 
        case R_386_32:
        case R_386_PC32:
+       case R_386_SIZE32:
          if (info->shared
              && (h == NULL || h->type != STT_GNU_IFUNC))
            break;
@@ -2062,10 +2105,44 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info,
 {
   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)
     {
+      /* All local STT_GNU_IFUNC references must be treate as local
+        calls via local PLT.  */
+      if (h->ref_regular
+         && SYMBOL_CALLS_LOCAL (info, h))
+       {
+         bfd_size_type pc_count = 0, 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;
+             count += p->count;
+             if (p->count == 0)
+               *pp = p->next;
+             else
+               pp = &p->next;
+           }
+
+         if (pc_count || count)
+           {
+             h->needs_plt = 1;
+             h->non_got_ref = 1;
+             if (h->plt.refcount <= 0)
+               h->plt.refcount = 1;
+             else
+               h->plt.refcount += 1;
+           }
+       }
+
       if (h->plt.refcount <= 0)
        {
          h->plt.offset = (bfd_vma) -1;
@@ -2125,12 +2202,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.  */
@@ -2144,17 +2223,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)
     {
-      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)
        {
          s = p->sec->output_section;
@@ -2169,13 +2246,6 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info,
        }
     }
 
-  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
@@ -2189,7 +2259,7 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info,
   /* 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;
@@ -2197,7 +2267,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
@@ -2224,15 +2294,48 @@ 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
       && h->def_regular)
     return _bfd_elf_allocate_ifunc_dyn_relocs (info, h, &eh->dyn_relocs,
-                                               plt_entry_size, 4);
+                                               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;
+
+      if ((info->flags & DF_BIND_NOW) && !h->pointer_equality_needed)
+       {
+         /* Don't use the regular PLT for DF_BIND_NOW. */
+         h->plt.offset = (bfd_vma) -1;
+
+         /* Use the GOT PLT.  */
+         h->got.refcount = 1;
+         eh->plt_got.refcount = 1;
+       }
+
+      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
@@ -2246,13 +2349,18 @@ 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
+           {
+             /* 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 this symbol is not defined in a regular file, and we are
             not generating a shared library, then set the symbol to this
@@ -2262,20 +2370,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->next_tls_desc_index++;
+             /* 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)
@@ -2527,8 +2651,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);
 
@@ -2539,6 +2664,151 @@ elf_i386_readonly_dynrelocs (struct elf_link_hash_entry *h, void *inf)
   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 is no need or no output.  */
+  if ((sec->flags & (SEC_CODE | SEC_RELOC)) != (SEC_CODE | SEC_RELOC)
+      || sec->need_convert_mov_to_lea == 0
+      || bfd_is_abs_section (sec->output_section))
+    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
+             && irel->r_offset >= 2
+             && bfd_get_8 (abfd, contents + irel->r_offset - 2) == 0x8b)
+           {
+             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)
+               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)
+         && irel->r_offset >= 2
+         && bfd_get_8 (abfd, contents + irel->r_offset - 2) == 0x8b)
+       {
+         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;
+         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
@@ -2562,7 +2832,7 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
       /* 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;
@@ -2572,7 +2842,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;
@@ -2589,6 +2859,9 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
        {
          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;
@@ -2617,8 +2890,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);
                    }
                }
@@ -2700,21 +2974,26 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
      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)
     {
-      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
@@ -2728,6 +3007,14 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
        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;
@@ -2739,11 +3026,7 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
        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.  */
@@ -2754,6 +3037,15 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
          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_got
+              || 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
@@ -2801,11 +3093,13 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
     }
 
   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)
     {
@@ -2896,6 +3190,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);
        }
     }
@@ -3044,14 +3339,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
@@ -3084,6 +3382,7 @@ elf_i386_relocate_section (bfd *output_bfd,
          relocation = (sec->output_section->vma
                        + sec->output_offset
                        + sym->st_value);
+         st_size = sym->st_size;
 
          if (ELF_ST_TYPE (sym->st_info) == STT_SECTION
              && ((sec->flags & SEC_MERGE) != 0
@@ -3171,16 +3470,18 @@ elf_i386_relocate_section (bfd *output_bfd,
       else
        {
          bfd_boolean warned ATTRIBUTE_UNUSED;
+         bfd_boolean ignored ATTRIBUTE_UNUSED;
 
          RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
                                   r_symndx, symtab_hdr, sym_hashes,
                                   h, sec, relocation,
-                                  unresolved_reloc, warned);
+                                  unresolved_reloc, warned, ignored);
+         st_size = h->size;
        }
 
-      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;
@@ -3232,11 +3533,10 @@ elf_i386_relocate_section (bfd *output_bfd,
 
            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;
-                 bfd_byte *loc;
                  asection *sreloc;
                  bfd_vma offset;
 
@@ -3270,10 +3570,7 @@ elf_i386_relocate_section (bfd *output_bfd,
                    outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
 
                  sreloc = htab->elf.irelifunc;
-                 loc = sreloc->contents;
-                 loc += (sreloc->reloc_count++
-                         * sizeof (Elf32_External_Rel));
-                 bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
+                 elf_append_rel (output_bfd, sreloc, &outrel);
 
                  /* If this reloc is against an external symbol, we
                     do not want to fiddle with the addend.  Otherwise,
@@ -3427,7 +3724,6 @@ elf_i386_relocate_section (bfd *output_bfd,
                    {
                      asection *s;
                      Elf_Internal_Rela outrel;
-                     bfd_byte *loc;
 
                      s = htab->elf.srelgot;
                      if (s == NULL)
@@ -3437,9 +3733,7 @@ elf_i386_relocate_section (bfd *output_bfd,
                                         + htab->elf.sgot->output_offset
                                         + off);
                      outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE);
-                     loc = s->contents;
-                     loc += s->reloc_count++ * sizeof (Elf32_External_Rel);
-                     bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
+                     elf_append_rel (output_bfd, s, &outrel);
                    }
 
                  local_got_offsets[r_symndx] |= 1;
@@ -3459,11 +3753,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)
                {
@@ -3491,13 +3785,16 @@ elf_i386_relocate_section (bfd *output_bfd,
                  bfd_set_error (bfd_error_bad_value);
                  return FALSE;
                }
-             else if (!info->executable
-                      && 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;
                }
@@ -3528,7 +3825,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
@@ -3537,12 +3836,28 @@ 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;
 
+       case R_386_SIZE32:
+         /* Set to symbol size.  */
+         relocation = st_size;
+         /* Fall through.  */
+
        case R_386_32:
        case R_386_PC32:
          if ((input_section->flags & SEC_ALLOC) == 0
@@ -3553,7 +3868,7 @@ elf_i386_relocate_section (bfd *output_bfd,
               && (h == NULL
                   || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
                   || h->root.type != bfd_link_hash_undefweak)
-              && (r_type != R_386_PC32
+              && ((r_type != R_386_PC32 && r_type != R_386_SIZE32)
                   || !SYMBOL_CALLS_LOCAL (info, h)))
              || (ELIMINATE_COPY_RELOCS
                  && !info->shared
@@ -3566,7 +3881,6 @@ elf_i386_relocate_section (bfd *output_bfd,
                      || h->root.type == bfd_link_hash_undefined)))
            {
              Elf_Internal_Rela outrel;
-             bfd_byte *loc;
              bfd_boolean skip, relocate;
              asection *sreloc;
 
@@ -3611,10 +3925,7 @@ elf_i386_relocate_section (bfd *output_bfd,
                  goto check_relocation_error;
                }
 
-             loc = sreloc->contents;
-             loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rel);
-
-             bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
+             elf_append_rel (output_bfd, sreloc, &outrel);
 
              /* If this reloc is against an external symbol, we do
                 not want to fiddle with the addend.  Otherwise, we
@@ -3629,7 +3940,6 @@ elf_i386_relocate_section (bfd *output_bfd,
          if (!info->executable)
            {
              Elf_Internal_Rela outrel;
-             bfd_byte *loc;
              asection *sreloc;
 
              outrel.r_offset = rel->r_offset
@@ -3639,9 +3949,7 @@ elf_i386_relocate_section (bfd *output_bfd,
              sreloc = elf_section_data (input_section)->sreloc;
              if (sreloc == NULL)
                abort ();
-             loc = sreloc->contents;
-             loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rel);
-             bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
+             elf_append_rel (output_bfd, sreloc, &outrel);
            }
          /* Fall through */
 
@@ -3867,7 +4175,6 @@ elf_i386_relocate_section (bfd *output_bfd,
          else
            {
              Elf_Internal_Rela outrel;
-             bfd_byte *loc;
              int dr_type;
              asection *sreloc;
 
@@ -3878,6 +4185,7 @@ elf_i386_relocate_section (bfd *output_bfd,
 
              if (GOT_TLS_GDESC_P (tls_type))
                {
+                 bfd_byte *loc;
                  outrel.r_info = ELF32_R_INFO (indx, R_386_TLS_DESC);
                  BFD_ASSERT (htab->sgotplt_jump_table_size + offplt + 8
                              <= htab->elf.sgotplt->size);
@@ -3935,11 +4243,7 @@ elf_i386_relocate_section (bfd *output_bfd,
                            htab->elf.sgot->contents + off);
              outrel.r_info = ELF32_R_INFO (indx, dr_type);
 
-             loc = sreloc->contents;
-             loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rel);
-             BFD_ASSERT (loc + sizeof (Elf32_External_Rel)
-                         <= sreloc->contents + sreloc->size);
-             bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
+             elf_append_rel (output_bfd, sreloc, &outrel);
 
              if (GOT_TLS_GD_P (tls_type))
                {
@@ -3957,11 +4261,7 @@ elf_i386_relocate_section (bfd *output_bfd,
                      outrel.r_info = ELF32_R_INFO (indx,
                                                    R_386_TLS_DTPOFF32);
                      outrel.r_offset += 4;
-                     sreloc->reloc_count++;
-                     loc += sizeof (Elf32_External_Rel);
-                     BFD_ASSERT (loc + sizeof (Elf32_External_Rel)
-                                 <= sreloc->contents + sreloc->size);
-                     bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
+                     elf_append_rel (output_bfd, sreloc, &outrel);
                    }
                }
              else if (tls_type == GOT_TLS_IE_BOTH)
@@ -3973,9 +4273,7 @@ elf_i386_relocate_section (bfd *output_bfd,
                              htab->elf.sgot->contents + off + 4);
                  outrel.r_info = ELF32_R_INFO (indx, R_386_TLS_TPOFF);
                  outrel.r_offset += 4;
-                 sreloc->reloc_count++;
-                 loc += sizeof (Elf32_External_Rel);
-                 bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
+                 elf_append_rel (output_bfd, sreloc, &outrel);
                }
 
            dr_done:
@@ -4157,7 +4455,6 @@ elf_i386_relocate_section (bfd *output_bfd,
          else
            {
              Elf_Internal_Rela outrel;
-             bfd_byte *loc;
 
              if (htab->elf.srelgot == NULL)
                abort ();
@@ -4170,9 +4467,7 @@ elf_i386_relocate_section (bfd *output_bfd,
              bfd_put_32 (output_bfd, 0,
                          htab->elf.sgot->contents + off + 4);
              outrel.r_info = ELF32_R_INFO (0, R_386_TLS_DTPMOD32);
-             loc = htab->elf.srelgot->contents;
-             loc += htab->elf.srelgot->reloc_count++ * sizeof (Elf32_External_Rel);
-             bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
+             elf_append_rel (output_bfd, htab->elf.srelgot, &outrel);
              htab->tls_ldm_got.offset |= 1;
            }
          relocation = htab->elf.sgot->output_section->vma
@@ -4196,7 +4491,6 @@ elf_i386_relocate_section (bfd *output_bfd,
            {
              Elf_Internal_Rela outrel;
              asection *sreloc;
-             bfd_byte *loc;
 
              outrel.r_offset = rel->r_offset
                                + input_section->output_section->vma
@@ -4212,9 +4506,7 @@ elf_i386_relocate_section (bfd *output_bfd,
              sreloc = elf_section_data (input_section)->sreloc;
              if (sreloc == NULL)
                abort ();
-             loc = sreloc->contents;
-             loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rel);
-             bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
+             elf_append_rel (output_bfd, sreloc, &outrel);
              if (indx)
                continue;
              else if (r_type == R_386_TLS_LE_32)
@@ -4308,6 +4600,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)
@@ -4316,6 +4609,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;
@@ -4349,7 +4644,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
          || 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
@@ -4364,13 +4659,13 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
 
       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.  */
@@ -4419,7 +4714,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
                              + got_offset);
              rel.r_info = ELF32_R_INFO (htab->elf.hplt->indx, R_386_32);
              bfd_elf32_swap_reloc_out (output_bfd, &rel,
-             loc + sizeof (Elf32_External_Rel));
+                                       loc + sizeof (Elf32_External_Rel));
            }
        }
       else
@@ -4431,18 +4726,6 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
                       + 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
@@ -4470,34 +4753,94 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
                       + 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);
 
-      if (!h->def_regular)
+      /* Don't fill PLT entry for static executables.  */
+      if (plt == htab->elf.splt)
        {
-         /* 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;
+         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);
        }
     }
+  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 ();
+
+      /* 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
+       {
+         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
       && ! GOT_TLS_GD_ANY_P (elf_i386_hash_entry(h)->tls_type)
       && (elf_i386_hash_entry(h)->tls_type & GOT_TLS_IE) == 0)
     {
       Elf_Internal_Rela rel;
-      bfd_byte *loc;
 
       /* This symbol has an entry in the global offset table.  Set it
         up.  */
@@ -4555,15 +4898,12 @@ do_glob_dat:
          rel.r_info = ELF32_R_INFO (h->dynindx, R_386_GLOB_DAT);
        }
 
-      loc = htab->elf.srelgot->contents;
-      loc += htab->elf.srelgot->reloc_count++ * sizeof (Elf32_External_Rel);
-      bfd_elf32_swap_reloc_out (output_bfd, &rel, loc);
+      elf_append_rel (output_bfd, htab->elf.srelgot, &rel);
     }
 
   if (h->needs_copy)
     {
       Elf_Internal_Rela rel;
-      bfd_byte *loc;
 
       /* This symbol needs a copy reloc.  Set it up.  */
 
@@ -4577,22 +4917,9 @@ do_glob_dat:
                      + h->root.u.def.section->output_section->vma
                      + h->root.u.def.section->output_offset);
       rel.r_info = ELF32_R_INFO (h->dynindx, R_386_COPY);
-      loc = htab->srelbss->contents;
-      loc += htab->srelbss->reloc_count++ * sizeof (Elf32_External_Rel);
-      bfd_elf32_swap_reloc_out (output_bfd, &rel, loc);
+      elf_append_rel (output_bfd, htab->srelbss, &rel);
     }
 
-  /* 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;
 }
 
@@ -4615,7 +4942,9 @@ elf_i386_finish_local_dynamic_symbol (void **slot, void *inf)
    dynamic linker, before writing them out.  */
 
 static enum elf_reloc_type_class
-elf_i386_reloc_type_class (const Elf_Internal_Rela *rela)
+elf_i386_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED,
+                          const asection *rel_sec ATTRIBUTE_UNUSED,
+                          const Elf_Internal_Rela *rela)
 {
   switch (ELF32_R_TYPE (rela->r_info))
     {
@@ -4646,7 +4975,7 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd,
     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)
@@ -4831,7 +5160,8 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd,
     }
 
   /* 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
@@ -4848,7 +5178,7 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd,
                             + 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,
@@ -4868,14 +5198,96 @@ 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)
+{
+  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;
+
+      /* PR binutils/18437: Skip extra relocations in the .rel.plt
+        section.  */
+      if (plt_offset >= plt->size)
+       break;
+    }
+
+  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)
 {
-  return plt->vma + (i + 1) * GET_PLT_ENTRY_SIZE (plt->owner);
+  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.  */
@@ -4896,22 +5308,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
@@ -4925,6 +5338,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
@@ -4934,9 +5348,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
@@ -4956,18 +5370,15 @@ 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
-#undef elf_backend_post_process_headers
-#define        elf_backend_post_process_headers        _bfd_elf_set_osabi
 
 #include "elf32-target.h"
 
 /* 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
@@ -4980,11 +5391,14 @@ elf_i386_add_symbol_hook (bfd * abfd,
 static void
 elf_i386_fbsd_post_process_headers (bfd *abfd, struct bfd_link_info *info)
 {
-  _bfd_elf_set_osabi (abfd, 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
 }
 
@@ -5000,10 +5414,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
@@ -5025,10 +5441,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
@@ -5042,7 +5499,6 @@ elf_i386_fbsd_post_process_headers (bfd *abfd, struct bfd_link_info *info)
 #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.  */
@@ -5093,7 +5549,10 @@ elf_i386_nacl_pic_plt0_entry[sizeof (elf_i386_nacl_plt0_entry)] =
     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] =
@@ -5184,15 +5643,38 @@ static const struct elf_i386_backend_data elf_i386_nacl_arch_bed =
     0,                                  /* is_vxworks */
   };
 
+static bfd_boolean
+elf32_i386_nacl_elf_object_p (bfd *abfd)
+{
+  /* Set the right machine number for a NaCl i386 ELF32 file.  */
+  bfd_default_set_arch_mach (abfd, bfd_arch_i386, bfd_mach_i386_i386_nacl);
+  return TRUE;
+}
+
 #undef elf_backend_arch_data
 #define elf_backend_arch_data  &elf_i386_nacl_arch_bed
 
+#undef elf_backend_object_p
+#define elf_backend_object_p                   elf32_i386_nacl_elf_object_p
+#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
+#undef elf_backend_final_write_processing
+#define elf_backend_final_write_processing     nacl_final_write_processing
+
 #include "elf32-target.h"
 
+/* Restore defaults.  */
+#undef elf_backend_object_p
+#undef elf_backend_modify_segment_map
+#undef elf_backend_modify_program_headers
+#undef elf_backend_final_write_processing
+
 /* 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
@@ -5210,7 +5692,6 @@ static const struct elf_i386_backend_data elf_i386_vxworks_arch_bed =
 #define        elf_backend_arch_data   &elf_i386_vxworks_arch_bed
 
 #undef elf_backend_relocs_compatible
-#undef elf_backend_post_process_headers
 #undef elf_backend_add_symbol_hook
 #define elf_backend_add_symbol_hook \
   elf_vxworks_add_symbol_hook
This page took 0.053352 seconds and 4 git commands to generate.