include/
[deliverable/binutils-gdb.git] / bfd / elf.c
index 04b689435334e60cdc63c9f2e09114a06efb4772..c57da590e25e372938309f4b3885f067e1c2948a 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -1,6 +1,7 @@
 /* ELF executable support for BFD.
-   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-   2003 Free Software Foundation, Inc.
+
+   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+   2002, 2003, 2004 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
@@ -41,7 +42,7 @@
 #include "libiberty.h"
 
 static int elf_sort_sections (const void *, const void *);
-static bfd_boolean assign_file_positions_except_relocs (bfd *);
+static bfd_boolean assign_file_positions_except_relocs (bfd *, struct bfd_link_info *);
 static bfd_boolean prep_headers (bfd *);
 static bfd_boolean swap_out_syms (bfd *, struct bfd_strtab_hash **, int) ;
 static bfd_boolean elfcore_read_notes (bfd *, file_ptr, bfd_size_type) ;
@@ -291,8 +292,8 @@ bfd_elf_string_from_elf_section (bfd *abfd,
   if (strindex >= hdr->sh_size)
     {
       (*_bfd_error_handler)
-       (_("%s: invalid string offset %u >= %lu for section `%s'"),
-        bfd_archive_filename (abfd), strindex, (unsigned long) hdr->sh_size,
+       (_("%B: invalid string offset %u >= %lu for section `%s'"),
+        abfd, strindex, (unsigned long) hdr->sh_size,
         ((shindex == elf_elfheader(abfd)->e_shstrndx
           && strindex == hdr->sh_name)
          ? ".shstrtab"
@@ -534,8 +535,7 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect)
                      if (idx >= shnum)
                        {
                          ((*_bfd_error_handler)
-                          (_("%s: invalid SHT_GROUP entry"),
-                           bfd_archive_filename (abfd)));
+                          (_("%B: invalid SHT_GROUP entry"), abfd));
                          idx = 0;
                        }
                      dest->shdr = elf_elfsections (abfd)[idx];
@@ -605,15 +605,65 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect)
 
   if (elf_group_name (newsect) == NULL)
     {
-      (*_bfd_error_handler) (_("%s: no group info for section %s"),
-                            bfd_archive_filename (abfd), newsect->name);
+      (*_bfd_error_handler) (_("%B: no group info for section %A"),
+                            abfd, newsect);
     }
   return TRUE;
 }
 
 bfd_boolean
-bfd_elf_discard_group (bfd *abfd ATTRIBUTE_UNUSED, asection *group)
+_bfd_elf_setup_group_pointers (bfd *abfd)
+{
+  unsigned int i;
+  unsigned int num_group = elf_tdata (abfd)->num_group;
+  bfd_boolean result = TRUE;
+
+  if (num_group == (unsigned) -1)
+    return result;
+
+  for (i = 0; i < num_group; i++)
+    {
+      Elf_Internal_Shdr *shdr = elf_tdata (abfd)->group_sect_ptr[i];
+      Elf_Internal_Group *idx = (Elf_Internal_Group *) shdr->contents;
+      unsigned int n_elt = shdr->sh_size / 4;
+
+      while (--n_elt != 0)
+       if ((++idx)->shdr->bfd_section)
+         elf_sec_group (idx->shdr->bfd_section) = shdr->bfd_section;
+       else if (idx->shdr->sh_type == SHT_RELA
+                || idx->shdr->sh_type == SHT_REL)
+         /* We won't include relocation sections in section groups in
+            output object files. We adjust the group section size here
+            so that relocatable link will work correctly when
+            relocation sections are in section group in input object
+            files.  */
+         shdr->bfd_section->size -= 4;
+       else
+         {
+           /* There are some unknown sections in the group.  */
+           (*_bfd_error_handler)
+             (_("%B: unknown [%d] section `%s' in group [%s]"),
+              abfd,
+              (unsigned int) idx->shdr->sh_type,
+              elf_string_from_elf_strtab (abfd, idx->shdr->sh_name),
+              shdr->bfd_section->name);
+           result = FALSE;
+         }
+    }
+  return result;
+}
+
+bfd_boolean
+bfd_elf_is_group_section (bfd *abfd ATTRIBUTE_UNUSED, const asection *sec)
+{
+  return elf_next_in_group (sec) != NULL;
+}
+
+bfd_boolean
+bfd_elf_discard_group (bfd *abfd ATTRIBUTE_UNUSED,
+                      asection *group ATTRIBUTE_UNUSED)
 {
+#if 0
   asection *first = elf_next_in_group (group);
   asection *s = first;
 
@@ -625,6 +675,10 @@ bfd_elf_discard_group (bfd *abfd ATTRIBUTE_UNUSED, asection *group)
       if (s == first)
        break;
     }
+#else
+  /* FIXME: Never used. Remove it!  */
+  abort ();
+#endif
   return TRUE;
 }
 
@@ -651,6 +705,9 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
   if (newsect == NULL)
     return FALSE;
 
+  hdr->bfd_section = newsect;
+  elf_section_data (newsect)->this_hdr = *hdr;
+
   /* Always use the real type/flags.  */
   elf_section_type (newsect) = hdr->sh_type;
   elf_section_flags (newsect) = hdr->sh_flags;
@@ -797,9 +854,6 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
        }
     }
 
-  hdr->bfd_section = newsect;
-  elf_section_data (newsect)->this_hdr = *hdr;
-
   return TRUE;
 }
 
@@ -894,10 +948,31 @@ merge_sections_remove_hook (bfd *abfd ATTRIBUTE_UNUSED,
 bfd_boolean
 _bfd_elf_merge_sections (bfd *abfd, struct bfd_link_info *info)
 {
-  if (!is_elf_hash_table (info))
+  bfd *ibfd;
+  asection *sec;
+
+  if (!is_elf_hash_table (info->hash))
     return FALSE;
-  if (elf_hash_table (info)->merge_info)
-    _bfd_merge_sections (abfd, elf_hash_table (info)->merge_info,
+
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+    if ((ibfd->flags & DYNAMIC) == 0)
+      for (sec = ibfd->sections; sec != NULL; sec = sec->next)
+       if ((sec->flags & SEC_MERGE) != 0
+           && !bfd_is_abs_section (sec->output_section))
+         {
+           struct bfd_elf_section_data *secdata;
+
+           secdata = elf_section_data (sec);
+           if (! _bfd_add_merge_section (abfd,
+                                         &elf_hash_table (info)->merge_info,
+                                         sec, &secdata->sec_info))
+             return FALSE;
+           else if (secdata->sec_info)
+             sec->sec_info_type = ELF_INFO_TYPE_MERGE;
+         }
+
+  if (elf_hash_table (info)->merge_info != NULL)
+    _bfd_merge_sections (abfd, info, elf_hash_table (info)->merge_info,
                         merge_sections_remove_hook);
   return TRUE;
 }
@@ -907,7 +982,7 @@ _bfd_elf_link_just_syms (asection *sec, struct bfd_link_info *info)
 {
   sec->output_section = bfd_abs_section_ptr;
   sec->output_offset = sec->vma;
-  if (!is_elf_hash_table (info))
+  if (!is_elf_hash_table (info->hash))
     return;
 
   sec->sec_info_type = ELF_INFO_TYPE_JUST_SYMS;
@@ -967,6 +1042,7 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
            case PT_TLS: pt = "TLS"; break;
            case PT_GNU_EH_FRAME: pt = "EH_FRAME"; break;
            case PT_GNU_STACK: pt = "STACK"; break;
+           case PT_GNU_RELRO: pt = "RELRO"; break;
            default: sprintf (buf, "0x%lx", p->p_type); pt = buf; break;
            }
          fprintf (f, "%8s off    0x", pt);
@@ -1001,10 +1077,7 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
 
       fprintf (f, _("\nDynamic Section:\n"));
 
-      dynbuf = bfd_malloc (s->_raw_size);
-      if (dynbuf == NULL)
-       goto error_return;
-      if (! bfd_get_section_contents (abfd, s, dynbuf, 0, s->_raw_size))
+      if (!bfd_malloc_and_get_section (abfd, s, &dynbuf))
        goto error_return;
 
       elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
@@ -1016,7 +1089,7 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
       swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in;
 
       extdyn = dynbuf;
-      extdynend = extdyn + s->_raw_size;
+      extdynend = extdyn + s->size;
       for (; extdyn < extdynend; extdyn += extdynsize)
        {
          Elf_Internal_Dyn dyn;
@@ -1318,23 +1391,14 @@ _bfd_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
       /* Set local fields.  */
       ret->indx = -1;
       ret->dynindx = -1;
-      ret->dynstr_index = 0;
-      ret->elf_hash_value = 0;
-      ret->weakdef = NULL;
-      ret->verinfo.verdef = NULL;
-      ret->vtable_entries_size = 0;
-      ret->vtable_entries_used = NULL;
-      ret->vtable_parent = NULL;
-      ret->got = htab->init_refcount;
-      ret->plt = htab->init_refcount;
-      ret->size = 0;
-      ret->type = STT_NOTYPE;
-      ret->other = 0;
+      ret->got = ret->plt = htab->init_refcount;
+      memset (&ret->size, 0, (sizeof (struct elf_link_hash_entry)
+                             - offsetof (struct elf_link_hash_entry, size)));
       /* Assume that we have been called by a non-ELF symbol reader.
          This flag is then reset by the code which reads an ELF input
          file.  This ensures that a symbol created by a non-ELF symbol
          reader will have the flag set correctly.  */
-      ret->elf_link_hash_flags = ELF_LINK_NON_ELF;
+      ret->non_elf = 1;
     }
 
   return entry;
@@ -1354,13 +1418,12 @@ _bfd_elf_link_hash_copy_indirect (const struct elf_backend_data *bed,
   /* Copy down any references that we may have already seen to the
      symbol which just became indirect.  */
 
-  dir->elf_link_hash_flags
-    |= (ind->elf_link_hash_flags & (ELF_LINK_HASH_REF_DYNAMIC
-                                   | ELF_LINK_HASH_REF_REGULAR
-                                   | ELF_LINK_HASH_REF_REGULAR_NONWEAK
-                                   | ELF_LINK_NON_GOT_REF
-                                   | ELF_LINK_HASH_NEEDS_PLT
-                                   | ELF_LINK_POINTER_EQUALITY_NEEDED));
+  dir->ref_dynamic |= ind->ref_dynamic;
+  dir->ref_regular |= ind->ref_regular;
+  dir->ref_regular_nonweak |= ind->ref_regular_nonweak;
+  dir->non_got_ref |= ind->non_got_ref;
+  dir->needs_plt |= ind->needs_plt;
+  dir->pointer_equality_needed |= ind->pointer_equality_needed;
 
   if (ind->root.type != bfd_link_hash_indirect)
     return;
@@ -1402,10 +1465,10 @@ _bfd_elf_link_hash_hide_symbol (struct bfd_link_info *info,
                                bfd_boolean force_local)
 {
   h->plt = elf_hash_table (info)->init_offset;
-  h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
+  h->needs_plt = 0;
   if (force_local)
     {
-      h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
+      h->forced_local = 1;
       if (h->dynindx != -1)
        {
          h->dynindx = -1;
@@ -1440,8 +1503,8 @@ _bfd_elf_link_hash_table_init
   table->bucketcount = 0;
   table->needed = NULL;
   table->hgot = NULL;
-  table->stab_info = NULL;
   table->merge_info = NULL;
+  memset (&table->stab_info, 0, sizeof (table->stab_info));
   memset (&table->eh_info, 0, sizeof (table->eh_info));
   table->dynlocal = NULL;
   table->runpath = NULL;
@@ -1478,8 +1541,7 @@ _bfd_elf_link_hash_table_create (bfd *abfd)
 
 /* This is a hook for the ELF emulation code in the generic linker to
    tell the backend linker what file name to use for the DT_NEEDED
-   entry for a dynamic object.  The generic linker passes name as an
-   empty string to indicate that no DT_NEEDED entry should be made.  */
+   entry for a dynamic object.  */
 
 void
 bfd_elf_set_dt_needed_name (bfd *abfd, const char *name)
@@ -1489,12 +1551,24 @@ bfd_elf_set_dt_needed_name (bfd *abfd, const char *name)
     elf_dt_name (abfd) = name;
 }
 
+int
+bfd_elf_get_dyn_lib_class (bfd *abfd)
+{
+  int lib_class;
+  if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
+      && bfd_get_format (abfd) == bfd_object)
+    lib_class = elf_dyn_lib_class (abfd);
+  else
+    lib_class = 0;
+  return lib_class;
+}
+
 void
-bfd_elf_set_dt_needed_soname (bfd *abfd, const char *name)
+bfd_elf_set_dyn_lib_class (bfd *abfd, int lib_class)
 {
   if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
       && bfd_get_format (abfd) == bfd_object)
-    elf_dt_soname (abfd) = name;
+    elf_dyn_lib_class (abfd) = lib_class;
 }
 
 /* Get the list of DT_NEEDED entries for a link.  This is a hook for
@@ -1504,7 +1578,7 @@ struct bfd_link_needed_list *
 bfd_elf_get_needed_list (bfd *abfd ATTRIBUTE_UNUSED,
                         struct bfd_link_info *info)
 {
-  if (! is_elf_hash_table (info))
+  if (! is_elf_hash_table (info->hash))
     return NULL;
   return elf_hash_table (info)->needed;
 }
@@ -1516,7 +1590,7 @@ struct bfd_link_needed_list *
 bfd_elf_get_runpath_list (bfd *abfd ATTRIBUTE_UNUSED,
                          struct bfd_link_info *info)
 {
-  if (! is_elf_hash_table (info))
+  if (! is_elf_hash_table (info->hash))
     return NULL;
   return elf_hash_table (info)->runpath;
 }
@@ -1556,14 +1630,10 @@ bfd_elf_get_bfd_needed_list (bfd *abfd,
     return TRUE;
 
   s = bfd_get_section_by_name (abfd, ".dynamic");
-  if (s == NULL || s->_raw_size == 0)
+  if (s == NULL || s->size == 0)
     return TRUE;
 
-  dynbuf = bfd_malloc (s->_raw_size);
-  if (dynbuf == NULL)
-    goto error_return;
-
-  if (! bfd_get_section_contents (abfd, s, dynbuf, 0, s->_raw_size))
+  if (!bfd_malloc_and_get_section (abfd, s, &dynbuf))
     goto error_return;
 
   elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
@@ -1576,7 +1646,7 @@ bfd_elf_get_bfd_needed_list (bfd *abfd,
   swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in;
 
   extdyn = dynbuf;
-  extdynend = extdyn + s->_raw_size;
+  extdynend = extdyn + s->size;
   for (; extdyn < extdynend; extdyn += extdynsize)
     {
       Elf_Internal_Dyn dyn;
@@ -1823,8 +1893,8 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
            || hdr->sh_link >= num_sec)
          {
            ((*_bfd_error_handler)
-            (_("%s: invalid link %lu for reloc section %s (index %u)"),
-             bfd_archive_filename (abfd), hdr->sh_link, name, shindex));
+            (_("%B: invalid link %lu for reloc section %s (index %u)"),
+             abfd, hdr->sh_link, name, shindex));
            return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
          }
 
@@ -1945,8 +2015,10 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
            hdr->bfd_section->flags
              |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
 
+         /* We try to keep the same section order as it comes in.  */
+         idx += n_elt;
          while (--n_elt != 0)
-           if ((s = (++idx)->shdr->bfd_section) != NULL
+           if ((s = (--idx)->shdr->bfd_section) != NULL
                && elf_next_in_group (s) != NULL)
              {
                elf_next_in_group (hdr->bfd_section) = s;
@@ -2022,6 +2094,7 @@ bfd_section_from_elf_index (bfd *abfd, unsigned int index)
 static struct bfd_elf_special_section const special_sections[] =
 {
   { ".bss",            4, -2, SHT_NOBITS,   SHF_ALLOC + SHF_WRITE },
+  { ".gnu.linkonce.b",15, -2, SHT_NOBITS,   SHF_ALLOC + SHF_WRITE },
   { ".comment",        8,  0, SHT_PROGBITS, 0 },
   { ".data",           5, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
   { ".data1",          6,  0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
@@ -2054,6 +2127,7 @@ static struct bfd_elf_special_section const special_sections[] =
   { ".gnu.version",   12,  0, SHT_GNU_versym, 0 },
   { ".gnu.version_d", 14,  0, SHT_GNU_verdef, 0 },
   { ".gnu.version_r", 14,  0, SHT_GNU_verneed, 0 },
+  { ".note.GNU-stack",15,  0, SHT_PROGBITS, 0 },
   { ".note",           5, -1, SHT_NOTE,     0 },
   { ".rela",           5, -1, SHT_RELA,     0 },
   { ".rel",            4, -1, SHT_REL,      0 },
@@ -2205,7 +2279,7 @@ _bfd_elf_make_section_from_phdr (bfd *abfd,
     return FALSE;
   newsect->vma = hdr->p_vaddr;
   newsect->lma = hdr->p_paddr;
-  newsect->_raw_size = hdr->p_filesz;
+  newsect->size = hdr->p_filesz;
   newsect->filepos = hdr->p_offset;
   newsect->flags |= SEC_HAS_CONTENTS;
   newsect->alignment_power = bfd_log2 (hdr->p_align);
@@ -2238,7 +2312,7 @@ _bfd_elf_make_section_from_phdr (bfd *abfd,
        return FALSE;
       newsect->vma = hdr->p_vaddr + hdr->p_filesz;
       newsect->lma = hdr->p_paddr + hdr->p_filesz;
-      newsect->_raw_size = hdr->p_memsz - hdr->p_filesz;
+      newsect->size = hdr->p_memsz - hdr->p_filesz;
       if (hdr->p_type == PT_LOAD)
        {
          newsect->flags |= SEC_ALLOC;
@@ -2291,6 +2365,9 @@ bfd_section_from_phdr (bfd *abfd, Elf_Internal_Phdr *hdr, int index)
     case PT_GNU_STACK:
       return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "stack");
 
+    case PT_GNU_RELRO:
+      return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "relro");
+
     default:
       /* Check for any processor-specific program segment types.
          If no handler for them, default to making "segment" sections.  */
@@ -2373,7 +2450,7 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg)
     this_hdr->sh_addr = 0;
 
   this_hdr->sh_offset = 0;
-  this_hdr->sh_size = asect->_raw_size;
+  this_hdr->sh_size = asect->size;
   this_hdr->sh_link = 0;
   this_hdr->sh_addralign = 1 << asect->alignment_power;
   /* The sh_entsize and sh_info fields may have been set already by
@@ -2386,7 +2463,31 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg)
      asect->flags.  */
   if (this_hdr->sh_type == SHT_NULL)
     {
-      if ((asect->flags & SEC_ALLOC) != 0
+      if ((asect->flags & SEC_GROUP) != 0)
+       {
+         /* We also need to mark SHF_GROUP here for relocatable
+            link.  */
+         struct bfd_link_order *l;
+         asection *elt;
+
+         for (l = asect->link_order_head; l != NULL; l = l->next)
+           if (l->type == bfd_indirect_link_order
+               && (elt = elf_next_in_group (l->u.indirect.section)) != NULL)
+             do
+               {
+                 /* The name is not important. Anything will do.  */
+                 elf_group_name (elt->output_section) = "G";
+                 elf_section_flags (elt->output_section) |= SHF_GROUP;
+
+                 elt = elf_next_in_group (elt);
+                 /* During a relocatable link, the lists are
+                    circular.  */
+               }
+             while (elt != elf_next_in_group (l->u.indirect.section));
+
+         this_hdr->sh_type = SHT_GROUP;
+       }
+      else if ((asect->flags & SEC_ALLOC) != 0
          && (((asect->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0)
              || (asect->flags & SEC_NEVER_LOAD) != 0))
        this_hdr->sh_type = SHT_NOBITS;
@@ -2481,7 +2582,7 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg)
   if ((asect->flags & SEC_THREAD_LOCAL) != 0)
     {
       this_hdr->sh_flags |= SHF_TLS;
-      if (asect->_raw_size == 0 && (asect->flags & SEC_HAS_CONTENTS) == 0)
+      if (asect->size == 0 && (asect->flags & SEC_HAS_CONTENTS) == 0)
        {
          struct bfd_link_order *o;
 
@@ -2547,7 +2648,7 @@ bfd_elf_set_group_contents (bfd *abfd, asection *sec, void *failedptrarg)
   if (sec->contents == NULL)
     {
       gas = FALSE;
-      sec->contents = bfd_alloc (abfd, sec->_raw_size);
+      sec->contents = bfd_alloc (abfd, sec->size);
 
       /* Arrange for the section to be written out.  */
       elf_section_data (sec)->this_hdr.contents = sec->contents;
@@ -2558,7 +2659,7 @@ bfd_elf_set_group_contents (bfd *abfd, asection *sec, void *failedptrarg)
        }
     }
 
-  loc = sec->contents + sec->_raw_size;
+  loc = sec->contents + sec->size;
 
   /* Get the pointer to the first section in the group that gas
      squirreled away here.  objcopy arranges for this to be set to the
@@ -2603,13 +2704,7 @@ bfd_elf_set_group_contents (bfd *abfd, asection *sec, void *failedptrarg)
        }
       while (elt != elf_next_in_group (l->u.indirect.section));
 
-  /* With ld -r, merging SHT_GROUP sections results in wasted space
-     due to allowing for the flag word on each input.  We may well
-     duplicate entries too.  */
-  while ((loc -= 4) > sec->contents)
-    H_PUT_32 (abfd, 0, loc);
-
-  if (loc != sec->contents)
+  if ((loc -= 4) != sec->contents)
     abort ();
 
   H_PUT_32 (abfd, sec->flags & SEC_LINK_ONCE ? GRP_COMDAT : 0, loc);
@@ -2727,6 +2822,7 @@ assign_section_numbers (bfd *abfd)
       i_shdrp[t->strtab_section] = &t->strtab_hdr;
       t->symtab_hdr.sh_link = t->strtab_section;
     }
+
   for (sec = abfd->sections; sec; sec = sec->next)
     {
       struct bfd_elf_section_data *d = elf_section_data (sec);
@@ -2755,6 +2851,56 @@ assign_section_numbers (bfd *abfd)
          d->rel_hdr2->sh_info = d->this_idx;
        }
 
+      /* We need to set up sh_link for SHF_LINK_ORDER.  */
+      if ((d->this_hdr.sh_flags & SHF_LINK_ORDER) != 0)
+       {
+         s = elf_linked_to_section (sec);
+         if (s)
+           d->this_hdr.sh_link = elf_section_data (s)->this_idx;
+         else
+           {
+             struct bfd_link_order *p;
+
+             /* Find out what the corresponding section in output
+                is.  */
+             for (p = sec->link_order_head; p != NULL; p = p->next)
+               {
+                 s = p->u.indirect.section;
+                 if (p->type == bfd_indirect_link_order
+                     && (bfd_get_flavour (s->owner)
+                         == bfd_target_elf_flavour))
+                   {
+                     Elf_Internal_Shdr ** const elf_shdrp
+                       = elf_elfsections (s->owner);
+                     int elfsec
+                       = _bfd_elf_section_from_bfd_section (s->owner, s);
+                     elfsec = elf_shdrp[elfsec]->sh_link;
+                     /* PR 290:
+                        The Intel C compiler generates SHT_IA_64_UNWIND with
+                        SHF_LINK_ORDER.  But it doesn't set theh sh_link or
+                        sh_info fields.  Hence we could get the situation
+                        where elfsec is 0.  */
+                     if (elfsec == 0)
+                       {
+                         const struct elf_backend_data *bed
+                           = get_elf_backend_data (abfd);
+                         if (bed->link_order_error_handler)
+                           bed->link_order_error_handler
+                             (_("%B: warning: sh_link not set for section `%S'"),
+                              abfd, s);
+                       }
+                     else
+                       {
+                         s = elf_shdrp[elfsec]->bfd_section->output_section;
+                         BFD_ASSERT (s != NULL);
+                         d->this_hdr.sh_link = elf_section_data (s)->this_idx;
+                       }
+                     break;
+                   }
+               }
+           }
+       }
+
       switch (d->this_hdr.sh_type)
        {
        case SHT_REL:
@@ -3103,7 +3249,7 @@ _bfd_elf_compute_section_file_positions (bfd *abfd,
   /* sh_offset is set in assign_file_positions_except_relocs.  */
   shstrtab_hdr->sh_addralign = 1;
 
-  if (!assign_file_positions_except_relocs (abfd))
+  if (!assign_file_positions_except_relocs (abfd, link_info))
     return FALSE;
 
   if (link_info == NULL && bfd_get_symcount (abfd) > 0)
@@ -3173,6 +3319,25 @@ make_mapping (bfd *abfd,
   return m;
 }
 
+/* Create the PT_DYNAMIC segment, which includes DYNSEC.  Returns NULL
+   on failure.  */
+
+struct elf_segment_map *
+_bfd_elf_make_dynamic_segment (bfd *abfd, asection *dynsec)
+{
+  struct elf_segment_map *m;
+
+  m = bfd_zalloc (abfd, sizeof (struct elf_segment_map));
+  if (m == NULL)
+    return NULL;
+  m->next = NULL;
+  m->p_type = PT_DYNAMIC;
+  m->count = 1;
+  m->sections[0] = dynsec;
+  
+  return m;
+}
+
 /* Set up a mapping from BFD sections to program segments.  */
 
 static bfd_boolean
@@ -3186,6 +3351,7 @@ map_sections_to_segments (bfd *abfd)
   struct elf_segment_map **pm;
   struct elf_segment_map *m;
   asection *last_hdr;
+  bfd_vma last_size;
   unsigned int phdr_index;
   bfd_vma maxpagesize;
   asection **hdrpp;
@@ -3265,6 +3431,7 @@ map_sections_to_segments (bfd *abfd)
      segment when the start of the second section can be placed within
      a few bytes of the end of the first section.  */
   last_hdr = NULL;
+  last_size = 0;
   phdr_index = 0;
   maxpagesize = get_elf_backend_data (abfd)->maxpagesize;
   writable = FALSE;
@@ -3313,18 +3480,19 @@ map_sections_to_segments (bfd *abfd)
              segment.  */
          new_segment = TRUE;
        }
-      else if (BFD_ALIGN (last_hdr->lma + last_hdr->_raw_size, maxpagesize)
+      else if (BFD_ALIGN (last_hdr->lma + last_size, maxpagesize)
               < BFD_ALIGN (hdr->lma, maxpagesize))
        {
          /* If putting this section in this segment would force us to
              skip a page in the segment, then we need a new segment.  */
          new_segment = TRUE;
        }
-      else if ((last_hdr->flags & SEC_LOAD) == 0
-              && (hdr->flags & SEC_LOAD) != 0)
+      else if ((last_hdr->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) == 0
+              && (hdr->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) != 0)
        {
          /* We don't want to put a loadable section after a
-             nonloadable section in the same segment.  */
+             nonloadable section in the same segment.
+             Consider .tbss sections as loadable for this purpose.  */
          new_segment = TRUE;
        }
       else if ((abfd->flags & D_PAGED) == 0)
@@ -3336,7 +3504,7 @@ map_sections_to_segments (bfd *abfd)
        }
       else if (! writable
               && (hdr->flags & SEC_READONLY) == 0
-              && (((last_hdr->lma + last_hdr->_raw_size - 1)
+              && (((last_hdr->lma + last_size - 1)
                    & ~(maxpagesize - 1))
                   != (hdr->lma & ~(maxpagesize - 1))))
        {
@@ -3360,6 +3528,11 @@ map_sections_to_segments (bfd *abfd)
          if ((hdr->flags & SEC_READONLY) == 0)
            writable = TRUE;
          last_hdr = hdr;
+         /* .tbss sections effectively have zero size.  */
+         if ((hdr->flags & (SEC_THREAD_LOCAL | SEC_LOAD)) != SEC_THREAD_LOCAL)
+           last_size = hdr->size;
+         else
+           last_size = 0;
          continue;
        }
 
@@ -3379,6 +3552,11 @@ map_sections_to_segments (bfd *abfd)
        writable = FALSE;
 
       last_hdr = hdr;
+      /* .tbss sections effectively have zero size.  */
+      if ((hdr->flags & (SEC_THREAD_LOCAL | SEC_LOAD)) != SEC_THREAD_LOCAL)
+       last_size = hdr->size;
+      else
+       last_size = 0;
       phdr_index = i;
       phdr_in_segment = FALSE;
     }
@@ -3397,15 +3575,9 @@ map_sections_to_segments (bfd *abfd)
   /* If there is a .dynamic section, throw in a PT_DYNAMIC segment.  */
   if (dynsec != NULL)
     {
-      amt = sizeof (struct elf_segment_map);
-      m = bfd_zalloc (abfd, amt);
+      m = _bfd_elf_make_dynamic_segment (abfd, dynsec);
       if (m == NULL)
        goto error_return;
-      m->next = NULL;
-      m->p_type = PT_DYNAMIC;
-      m->count = 1;
-      m->sections[0] = dynsec;
-
       *pm = m;
       pm = &m->next;
     }
@@ -3501,6 +3673,21 @@ map_sections_to_segments (bfd *abfd)
       pm = &m->next;
     }
 
+  if (elf_tdata (abfd)->relro)
+    {
+      amt = sizeof (struct elf_segment_map);
+      m = bfd_zalloc (abfd, amt);
+      if (m == NULL)
+       goto error_return;
+      m->next = NULL;
+      m->p_type = PT_GNU_RELRO;
+      m->p_flags = PF_R;
+      m->p_flags_valid = 1;
+
+      *pm = m;
+      pm = &m->next;
+    }
+
   free (sections);
   sections = NULL;
 
@@ -3560,8 +3747,8 @@ elf_sort_sections (const void *arg1, const void *arg2)
   /* Sort by size, to put zero sized sections
      before others at the same address.  */
 
-  size1 = (sec1->flags & SEC_LOAD) ? sec1->_raw_size : 0;
-  size2 = (sec2->flags & SEC_LOAD) ? sec2->_raw_size : 0;
+  size1 = (sec1->flags & SEC_LOAD) ? sec1->size : 0;
+  size2 = (sec2->flags & SEC_LOAD) ? sec2->size : 0;
 
   if (size1 < size2)
     return -1;
@@ -3571,12 +3758,41 @@ elf_sort_sections (const void *arg1, const void *arg2)
   return sec1->target_index - sec2->target_index;
 }
 
+/* Ian Lance Taylor writes:
+
+   We shouldn't be using % with a negative signed number.  That's just
+   not good.  We have to make sure either that the number is not
+   negative, or that the number has an unsigned type.  When the types
+   are all the same size they wind up as unsigned.  When file_ptr is a
+   larger signed type, the arithmetic winds up as signed long long,
+   which is wrong.
+
+   What we're trying to say here is something like ``increase OFF by
+   the least amount that will cause it to be equal to the VMA modulo
+   the page size.''  */
+/* In other words, something like:
+
+   vma_offset = m->sections[0]->vma % bed->maxpagesize;
+   off_offset = off % bed->maxpagesize;
+   if (vma_offset < off_offset)
+     adjustment = vma_offset + bed->maxpagesize - off_offset;
+   else
+     adjustment = vma_offset - off_offset;
+     
+   which can can be collapsed into the expression below.  */
+
+static file_ptr
+vma_page_aligned_bias (bfd_vma vma, ufile_ptr off, bfd_vma maxpagesize)
+{
+  return ((vma - off) % maxpagesize);
+}
+
 /* Assign file positions to the sections based on the mapping from
    sections to segments.  This function also sets up some fields in
    the file header, and writes out the program headers.  */
 
 static bfd_boolean
-assign_file_positions_for_segments (bfd *abfd)
+assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info)
 {
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
   unsigned int count;
@@ -3628,7 +3844,7 @@ assign_file_positions_for_segments (bfd *abfd)
 
   if (bed->elf_backend_modify_segment_map)
     {
-      if (! (*bed->elf_backend_modify_segment_map) (abfd))
+      if (! (*bed->elf_backend_modify_segment_map) (abfd, link_info))
        return FALSE;
     }
 
@@ -3698,7 +3914,8 @@ assign_file_positions_for_segments (bfd *abfd)
          && (m->sections[0]->flags & SEC_ALLOC) != 0)
        {
          if ((abfd->flags & D_PAGED) != 0)
-           off += (m->sections[0]->vma - off) % bed->maxpagesize;
+           off += vma_page_aligned_bias (m->sections[0]->vma, off,
+                                         bed->maxpagesize);
          else
            {
              bfd_size_type align;
@@ -3713,9 +3930,22 @@ assign_file_positions_for_segments (bfd *abfd)
                    align = secalign;
                }
 
-             off += (m->sections[0]->vma - off) % (1 << align);
+             off += vma_page_aligned_bias (m->sections[0]->vma, off,
+                                           1 << align);
            }
        }
+      /* Make sure the .dynamic section is the first section in the
+        PT_DYNAMIC segment.  */
+      else if (p->p_type == PT_DYNAMIC
+              && m->count > 1
+              && strcmp (m->sections[0]->name, ".dynamic") != 0)
+       {
+         _bfd_error_handler
+           (_("%s: The first section in the PT_DYNAMIC segment is not the .dynamic section"),
+            bfd_get_filename (abfd));
+         bfd_set_error (bfd_error_bad_value);
+         return FALSE;
+       }
 
       if (m->count == 0)
        p->p_vaddr = 0;
@@ -3875,9 +4105,11 @@ assign_file_positions_for_segments (bfd *abfd)
                     not have the SEC_LOAD case just above, and then
                     this was necessary, but now I'm not sure.  */
                  if ((abfd->flags & D_PAGED) != 0)
-                   adjust = (sec->vma - voff) % bed->maxpagesize;
+                   adjust = vma_page_aligned_bias (sec->vma, voff,
+                                                   bed->maxpagesize);
                  else
-                   adjust = (sec->vma - voff) % align;
+                   adjust = vma_page_aligned_bias (sec->vma, voff,
+                                                   align);
                }
              else
                adjust = 0;
@@ -3908,12 +4140,12 @@ Error: First section in segment (%s) starts at 0x%x whereas the segment starts a
                  contents.  */
              if ((flags & SEC_LOAD) != 0
                  || (flags & SEC_HAS_CONTENTS) != 0)
-               off += sec->_raw_size;
+               off += sec->size;
 
              if ((flags & SEC_ALLOC) != 0
                  && ((flags & SEC_LOAD) != 0
                      || (flags & SEC_THREAD_LOCAL) == 0))
-               voff += sec->_raw_size;
+               voff += sec->size;
            }
 
          if (p->p_type == PT_NOTE && bfd_get_format (abfd) == bfd_core)
@@ -3923,15 +4155,15 @@ Error: First section in segment (%s) starts at 0x%x whereas the segment starts a
              if (i == 0)
                {
                  sec->filepos = off;
-                 p->p_filesz = sec->_raw_size;
-                 off += sec->_raw_size;
+                 p->p_filesz = sec->size;
+                 off += sec->size;
                  voff = off;
                }
              else
                {
                  /* Fake sections -- don't need to be written.  */
                  sec->filepos = 0;
-                 sec->_raw_size = 0;
+                 sec->size = 0;
                  flags = sec->flags = 0;
                }
              p->p_memsz = 0;
@@ -3942,13 +4174,13 @@ Error: First section in segment (%s) starts at 0x%x whereas the segment starts a
              if ((sec->flags & SEC_LOAD) != 0
                  || (sec->flags & SEC_THREAD_LOCAL) == 0
                  || p->p_type == PT_TLS)
-             p->p_memsz += sec->_raw_size;
+             p->p_memsz += sec->size;
 
              if ((flags & SEC_LOAD) != 0)
-               p->p_filesz += sec->_raw_size;
+               p->p_filesz += sec->size;
 
              if (p->p_type == PT_TLS
-                 && sec->_raw_size == 0
+                 && sec->size == 0
                  && (sec->flags & SEC_HAS_CONTENTS) == 0)
                {
                  struct bfd_link_order *o;
@@ -3986,6 +4218,22 @@ Error: First section in segment (%s) starts at 0x%x whereas the segment starts a
       if (p->p_type != PT_LOAD && m->count > 0)
        {
          BFD_ASSERT (! m->includes_filehdr && ! m->includes_phdrs);
+         /* If the section has not yet been assigned a file position,
+            do so now.  The ARM BPABI requires that .dynamic section
+            not be marked SEC_ALLOC because it is not part of any
+            PT_LOAD segment, so it will not be processed above.  */
+         if (p->p_type == PT_DYNAMIC && m->sections[0]->filepos == 0)
+           {
+             unsigned int i;
+             Elf_Internal_Shdr ** const i_shdrpp = elf_elfsections (abfd);
+
+             i = 1;
+             while (i_shdrpp[i]->bfd_section != m->sections[0])
+               ++i;
+             off = (_bfd_elf_assign_file_position_for_section 
+                    (i_shdrpp[i], off, TRUE));
+             p->p_filesz = m->sections[0]->size;
+           }
          p->p_offset = m->sections[0]->filepos;
        }
       if (m->count == 0)
@@ -4002,6 +4250,37 @@ Error: First section in segment (%s) starts at 0x%x whereas the segment starts a
              if (! m->p_paddr_valid)
                p->p_paddr = phdrs_paddr;
            }
+         else if (p->p_type == PT_GNU_RELRO)
+           {
+             Elf_Internal_Phdr *lp;
+
+             for (lp = phdrs; lp < phdrs + count; ++lp)
+               {
+                 if (lp->p_type == PT_LOAD
+                     && lp->p_vaddr <= link_info->relro_end
+                     && lp->p_vaddr >= link_info->relro_start
+                     && lp->p_vaddr + lp->p_filesz
+                        >= link_info->relro_end)
+                   break;
+               }
+
+             if (lp < phdrs + count
+                 && link_info->relro_end > lp->p_vaddr)
+               {
+                 p->p_vaddr = lp->p_vaddr;
+                 p->p_paddr = lp->p_paddr;
+                 p->p_offset = lp->p_offset;
+                 p->p_filesz = link_info->relro_end - lp->p_vaddr;
+                 p->p_memsz = p->p_filesz;
+                 p->p_align = 1;
+                 p->p_flags = (lp->p_flags & ~PF_W);
+               }
+             else
+               {
+                 memset (p, 0, sizeof *p);
+                 p->p_type = PT_NULL;
+               }
+           }
        }
     }
 
@@ -4089,6 +4368,12 @@ get_program_header_size (bfd *abfd)
       ++segs;
     }
 
+  if (elf_tdata (abfd)->relro)
+    {
+      /* We need a PT_GNU_RELRO segment.  */
+      ++segs;
+    }
+
   for (s = abfd->sections; s != NULL; s = s->next)
     {
       if ((s->flags & SEC_LOAD) != 0
@@ -4128,15 +4413,19 @@ get_program_header_size (bfd *abfd)
    _bfd_elf_compute_section_file_positions.  All the section sizes and
    VMAs must be known before this is called.
 
-   We do not consider reloc sections at this point, unless they form
-   part of the loadable image.  Reloc sections are assigned file
-   positions in assign_file_positions_for_relocs, which is called by
-   write_object_contents and final_link.
+   Reloc sections come in two flavours: Those processed specially as
+   "side-channel" data attached to a section to which they apply, and
+   those that bfd doesn't process as relocations.  The latter sort are
+   stored in a normal bfd section by bfd_section_from_shdr.   We don't
+   consider the former sort here, unless they form part of the loadable
+   image.  Reloc sections not assigned here will be handled later by
+   assign_file_positions_for_relocs.
 
    We also don't set the positions of the .symtab and .strtab here.  */
 
 static bfd_boolean
-assign_file_positions_except_relocs (bfd *abfd)
+assign_file_positions_except_relocs (bfd *abfd,
+                                    struct bfd_link_info *link_info)
 {
   struct elf_obj_tdata * const tdata = elf_tdata (abfd);
   Elf_Internal_Ehdr * const i_ehdrp = elf_elfheader (abfd);
@@ -4162,8 +4451,8 @@ assign_file_positions_except_relocs (bfd *abfd)
          Elf_Internal_Shdr *hdr;
 
          hdr = *hdrpp;
-         if (hdr->sh_type == SHT_REL
-             || hdr->sh_type == SHT_RELA
+         if (((hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA)
+              && hdr->bfd_section == NULL)
              || i == tdata->symtab_section
              || i == tdata->symtab_shndx_section
              || i == tdata->strtab_section)
@@ -4187,7 +4476,7 @@ assign_file_positions_except_relocs (bfd *abfd)
 
       /* Assign file positions for the loaded sections based on the
          assignment of sections to segments.  */
-      if (! assign_file_positions_for_segments (abfd))
+      if (! assign_file_positions_for_segments (abfd, link_info))
        return FALSE;
 
       /* Assign file positions for the other sections.  */
@@ -4210,14 +4499,16 @@ assign_file_positions_except_relocs (bfd *abfd)
                 ? "*unknown*"
                 : hdr->bfd_section->name)));
              if ((abfd->flags & D_PAGED) != 0)
-               off += (hdr->sh_addr - off) % bed->maxpagesize;
+               off += vma_page_aligned_bias (hdr->sh_addr, off,
+                                             bed->maxpagesize);
              else
-               off += (hdr->sh_addr - off) % hdr->sh_addralign;
+               off += vma_page_aligned_bias (hdr->sh_addr, off,
+                                             hdr->sh_addralign);
              off = _bfd_elf_assign_file_position_for_section (hdr, off,
                                                               FALSE);
            }
-         else if (hdr->sh_type == SHT_REL
-                  || hdr->sh_type == SHT_RELA
+         else if (((hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA)
+                   && hdr->bfd_section == NULL)
                   || hdr == i_shdrpp[tdata->symtab_section]
                   || hdr == i_shdrpp[tdata->symtab_shndx_section]
                   || hdr == i_shdrpp[tdata->strtab_section])
@@ -4516,8 +4807,8 @@ _bfd_elf_symbol_from_bfd_symbol (bfd *abfd, asymbol **asym_ptr_ptr)
       /* This case can occur when using --strip-symbol on a symbol
          which is used in a relocation entry.  */
       (*_bfd_error_handler)
-       (_("%s: symbol `%s' required but not present"),
-        bfd_archive_filename (abfd), bfd_asymbol_name (asym_ptr));
+       (_("%B: symbol `%s' required but not present"),
+        abfd, bfd_asymbol_name (asym_ptr));
       bfd_set_error (bfd_error_no_symbols);
       return -1;
     }
@@ -4578,7 +4869,7 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
 #define SECTION_SIZE(section, segment)                                 \
   (((section->flags & (SEC_HAS_CONTENTS | SEC_THREAD_LOCAL))           \
     != SEC_THREAD_LOCAL || segment->p_type == PT_TLS)                  \
-   ? section->_raw_size : 0)
+   ? section->size : 0)
 
   /* Returns TRUE if the given section is contained within
      the given segment.  VMA addresses are compared.  */
@@ -4600,7 +4891,7 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
    && bfd_get_format (ibfd) == bfd_core                                        \
    && s->vma == 0 && s->lma == 0                                       \
    && (bfd_vma) s->filepos >= p->p_offset                              \
-   && ((bfd_vma) s->filepos + s->_raw_size                             \
+   && ((bfd_vma) s->filepos + s->size                          \
        <= p->p_offset + p->p_filesz))
 
   /* The complicated case when p_vaddr is 0 is to handle the Solaris
@@ -4612,9 +4903,9 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
    && p->p_memsz == 0                                                  \
    && p->p_filesz > 0                                                  \
    && (s->flags & SEC_HAS_CONTENTS) != 0                               \
-   && s->_raw_size > 0                                                 \
+   && s->size > 0                                                      \
    && (bfd_vma) s->filepos >= p->p_offset                              \
-   && ((bfd_vma) s->filepos + s->_raw_size                             \
+   && ((bfd_vma) s->filepos + s->size                          \
        <= p->p_offset + p->p_filesz))
 
   /* Decide if the given section should be included in the given segment.
@@ -4624,8 +4915,9 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
        2. It is an allocated segment,
        3. There is an output section associated with it,
        4. The section has not already been allocated to a previous segment.
-       5. PT_TLS segment includes only SHF_TLS sections.
-       6. SHF_TLS sections are only in PT_TLS or PT_LOAD segments.  */
+       5. PT_GNU_STACK segments do not include any sections.
+       6. PT_TLS segment includes only SHF_TLS sections.
+       7. SHF_TLS sections are only in PT_TLS or PT_LOAD segments.  */
 #define INCLUDE_SECTION_IN_SEGMENT(section, segment, bed)              \
   ((((segment->p_paddr                                                 \
       ? IS_CONTAINED_BY_LMA (section, segment, segment->p_paddr)       \
@@ -4633,6 +4925,7 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
      && (section->flags & SEC_ALLOC) != 0)                             \
     || IS_COREFILE_NOTE (segment, section))                            \
    && section->output_section != NULL                                  \
+   && segment->p_type != PT_GNU_STACK                                  \
    && (segment->p_type != PT_TLS                                       \
        || (section->flags & SEC_THREAD_LOCAL))                         \
    && (segment->p_type == PT_LOAD                                      \
@@ -4676,7 +4969,7 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
          if (IS_SOLARIS_PT_INTERP (segment, section))
            {
              /* Mininal change so that the normal section to segment
-                assigment code will work.  */
+                assignment code will work.  */
              segment->p_vaddr = section->vma;
              break;
            }
@@ -4802,8 +5095,8 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
             a warning is produced.  */
          if (segment->p_type == PT_LOAD)
            (*_bfd_error_handler)
-             (_("%s: warning: Empty loadable segment detected, is this intentional ?\n"),
-              bfd_archive_filename (ibfd));
+             (_("%B: warning: Empty loadable segment detected, is this intentional ?\n"),
+              ibfd);
 
          map->count = 0;
          *pointer_to_map = map;
@@ -5010,10 +5303,10 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
                      /* If the gap between the end of the previous section
                         and the start of this section is more than
                         maxpagesize then we need to start a new segment.  */
-                     if ((BFD_ALIGN (prev_sec->lma + prev_sec->_raw_size,
+                     if ((BFD_ALIGN (prev_sec->lma + prev_sec->size,
                                      maxpagesize)
                           < BFD_ALIGN (output_section->lma, maxpagesize))
-                         || ((prev_sec->lma + prev_sec->_raw_size)
+                         || ((prev_sec->lma + prev_sec->size)
                              > output_section->lma))
                        {
                          if (suggested_lma == 0)
@@ -5150,24 +5443,6 @@ _bfd_elf_copy_private_section_data (bfd *ibfd,
       || obfd->xvec->flavour != bfd_target_elf_flavour)
     return TRUE;
 
-  if (elf_tdata (obfd)->segment_map == NULL && elf_tdata (ibfd)->phdr != NULL)
-    {
-       asection *s;
-
-       /* Only set up the segments if there are no more SEC_ALLOC
-          sections.  FIXME: This won't do the right thing if objcopy is
-          used to remove the last SEC_ALLOC section, since objcopy
-          won't call this routine in that case.  */
-       for (s = isec->next; s != NULL; s = s->next)
-         if ((s->flags & SEC_ALLOC) != 0)
-           break;
-       if (s == NULL)
-         {
-           if (! copy_private_bfd_data (ibfd, obfd))
-             return FALSE;
-         }
-    }
-
   ihdr = &elf_section_data (isec)->this_hdr;
   ohdr = &elf_section_data (osec)->this_hdr;
 
@@ -5190,6 +5465,29 @@ _bfd_elf_copy_private_section_data (bfd *ibfd,
   return TRUE;
 }
 
+/* Copy private header information.  */
+
+bfd_boolean
+_bfd_elf_copy_private_header_data (bfd *ibfd, bfd *obfd)
+{
+  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+    return TRUE;
+
+  /* Copy over private BFD data if it has not already been copied.
+     This must be done here, rather than in the copy_private_bfd_data
+     entry point, because the latter is called after the section
+     contents have been set, which means that the program headers have
+     already been worked out.  */
+  if (elf_tdata (obfd)->segment_map == NULL && elf_tdata (ibfd)->phdr != NULL)
+    {
+      if (! copy_private_bfd_data (ibfd, obfd))
+       return FALSE;
+    }
+
+  return TRUE;
+}
+
 /* Copy private symbol information.  If this symbol is in a section
    which we did not map into a BFD section, try to map the section
    index correctly.  We use special macro definitions for the mapped
@@ -5258,6 +5556,7 @@ swap_out_syms (bfd *abfd,
   char *outbound_shndx;
   int idx;
   bfd_size_type amt;
+  bfd_boolean name_local_sections;
 
   if (!elf_map_symbols (abfd))
     return FALSE;
@@ -5323,6 +5622,10 @@ swap_out_syms (bfd *abfd,
       outbound_shndx += sizeof (Elf_External_Sym_Shndx);
   }
 
+  name_local_sections
+    = (bed->elf_backend_name_local_section_symbols
+       && bed->elf_backend_name_local_section_symbols (abfd));
+
   syms = bfd_get_outsymbols (abfd);
   for (idx = 0; idx < symcount; idx++)
     {
@@ -5332,7 +5635,8 @@ swap_out_syms (bfd *abfd,
       flagword flags = syms[idx]->flags;
       int type;
 
-      if ((flags & (BSF_SECTION_SYM | BSF_GLOBAL)) == BSF_SECTION_SYM)
+      if (!name_local_sections
+         && (flags & (BSF_SECTION_SYM | BSF_GLOBAL)) == BSF_SECTION_SYM)
        {
          /* Local section symbols have no name.  */
          sym.st_name = 0;
@@ -5638,7 +5942,7 @@ _bfd_elf_get_dynamic_reloc_upper_bound (bfd *abfd)
     if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd)
        && (elf_section_data (s)->this_hdr.sh_type == SHT_REL
            || elf_section_data (s)->this_hdr.sh_type == SHT_RELA))
-      ret += ((s->_raw_size / elf_section_data (s)->this_hdr.sh_entsize)
+      ret += ((s->size / elf_section_data (s)->this_hdr.sh_entsize)
              * sizeof (arelent *));
 
   return ret;
@@ -5681,7 +5985,7 @@ _bfd_elf_canonicalize_dynamic_reloc (bfd *abfd,
 
          if (! (*slurp_relocs) (abfd, s, syms, TRUE))
            return -1;
-         count = s->_raw_size / elf_section_data (s)->this_hdr.sh_entsize;
+         count = s->size / elf_section_data (s)->this_hdr.sh_entsize;
          p = s->relocation;
          for (i = 0; i < count; i++)
            *storage++ = p++;
@@ -6215,8 +6519,8 @@ _bfd_elf_validate_reloc (bfd *abfd, arelent *areloc)
 
  fail:
   (*_bfd_error_handler)
-    (_("%s: unsupported relocation type %s"),
-     bfd_archive_filename (abfd), areloc->howto->name);
+    (_("%B: unsupported relocation type %s"),
+     abfd, areloc->howto->name);
   bfd_set_error (bfd_error_bad_value);
   return FALSE;
 }
@@ -6283,7 +6587,7 @@ elfcore_maybe_make_sect (bfd *abfd, char *name, asection *sect)
   if (sect2 == NULL)
     return FALSE;
 
-  sect2->_raw_size = sect->_raw_size;
+  sect2->size = sect->size;
   sect2->filepos = sect->filepos;
   sect2->flags = sect->flags;
   sect2->alignment_power = sect->alignment_power;
@@ -6320,7 +6624,7 @@ _bfd_elfcore_make_pseudosection (bfd *abfd,
   sect = bfd_make_section_anyway (abfd, threaded_name);
   if (sect == NULL)
     return FALSE;
-  sect->_raw_size = size;
+  sect->size = size;
   sect->filepos = filepos;
   sect->flags = SEC_HAS_CONTENTS;
   sect->alignment_power = 2;
@@ -6339,14 +6643,14 @@ _bfd_elfcore_make_pseudosection (bfd *abfd,
 static bfd_boolean
 elfcore_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
 {
-  size_t raw_size;
+  size_t size;
   int offset;
 
   if (note->descsz == sizeof (prstatus_t))
     {
       prstatus_t prstat;
 
-      raw_size = sizeof (prstat.pr_reg);
+      size = sizeof (prstat.pr_reg);
       offset   = offsetof (prstatus_t, pr_reg);
       memcpy (&prstat, note->descdata, sizeof (prstat));
 
@@ -6372,7 +6676,7 @@ elfcore_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
       /* 64-bit host, 32-bit corefile */
       prstatus32_t prstat;
 
-      raw_size = sizeof (prstat.pr_reg);
+      size = sizeof (prstat.pr_reg);
       offset   = offsetof (prstatus32_t, pr_reg);
       memcpy (&prstat, note->descdata, sizeof (prstat));
 
@@ -6402,7 +6706,7 @@ elfcore_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
 
   /* Make a ".reg/999" section and a ".reg" section.  */
   return _bfd_elfcore_make_pseudosection (abfd, ".reg",
-                                         raw_size, note->descpos + offset);
+                                         size, note->descpos + offset);
 }
 #endif /* defined (HAVE_PRSTATUS_T) */
 
@@ -6606,13 +6910,13 @@ elfcore_grok_lwpstatus (bfd *abfd, Elf_Internal_Note *note)
     return FALSE;
 
 #if defined (HAVE_LWPSTATUS_T_PR_CONTEXT)
-  sect->_raw_size = sizeof (lwpstat.pr_context.uc_mcontext.gregs);
+  sect->size = sizeof (lwpstat.pr_context.uc_mcontext.gregs);
   sect->filepos = note->descpos
     + offsetof (lwpstatus_t, pr_context.uc_mcontext.gregs);
 #endif
 
 #if defined (HAVE_LWPSTATUS_T_PR_REG)
-  sect->_raw_size = sizeof (lwpstat.pr_reg);
+  sect->size = sizeof (lwpstat.pr_reg);
   sect->filepos = note->descpos + offsetof (lwpstatus_t, pr_reg);
 #endif
 
@@ -6636,13 +6940,13 @@ elfcore_grok_lwpstatus (bfd *abfd, Elf_Internal_Note *note)
     return FALSE;
 
 #if defined (HAVE_LWPSTATUS_T_PR_CONTEXT)
-  sect->_raw_size = sizeof (lwpstat.pr_context.uc_mcontext.fpregs);
+  sect->size = sizeof (lwpstat.pr_context.uc_mcontext.fpregs);
   sect->filepos = note->descpos
     + offsetof (lwpstatus_t, pr_context.uc_mcontext.fpregs);
 #endif
 
 #if defined (HAVE_LWPSTATUS_T_PR_FPREG)
-  sect->_raw_size = sizeof (lwpstat.pr_fpreg);
+  sect->size = sizeof (lwpstat.pr_fpreg);
   sect->filepos = note->descpos + offsetof (lwpstatus_t, pr_fpreg);
 #endif
 
@@ -6691,7 +6995,7 @@ elfcore_grok_win32pstatus (bfd *abfd, Elf_Internal_Note *note)
       if (sect == NULL)
        return FALSE;
 
-      sect->_raw_size = sizeof (pstatus.data.thread_info.thread_context);
+      sect->size = sizeof (pstatus.data.thread_info.thread_context);
       sect->filepos = (note->descpos
                       + offsetof (struct win32_pstatus,
                                   data.thread_info.thread_context));
@@ -6719,7 +7023,7 @@ elfcore_grok_win32pstatus (bfd *abfd, Elf_Internal_Note *note)
       if (sect == NULL)
        return FALSE;
 
-      sect->_raw_size = note->descsz;
+      sect->size = note->descsz;
       sect->filepos = note->descpos;
       sect->flags = SEC_HAS_CONTENTS;
       sect->alignment_power = 2;
@@ -6795,7 +7099,7 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
 
        if (sect == NULL)
          return FALSE;
-       sect->_raw_size = note->descsz;
+       sect->size = note->descsz;
        sect->filepos = note->descpos;
        sect->flags = SEC_HAS_CONTENTS;
        sect->alignment_power = 1 + bfd_get_arch_size (abfd) / 32;
@@ -6948,7 +7252,7 @@ elfcore_grok_nto_status (bfd *abfd, Elf_Internal_Note *note, pid_t *tid)
   if (sect == NULL)
     return FALSE;
 
-  sect->_raw_size       = note->descsz;
+  sect->size            = note->descsz;
   sect->filepos         = note->descpos;
   sect->flags           = SEC_HAS_CONTENTS;
   sect->alignment_power = 2;
@@ -6975,7 +7279,7 @@ elfcore_grok_nto_gregs (bfd *abfd, Elf_Internal_Note *note, pid_t tid)
   if (sect == NULL)
     return FALSE;
 
-  sect->_raw_size       = note->descsz;
+  sect->size            = note->descsz;
   sect->filepos         = note->descpos;
   sect->flags           = SEC_HAS_CONTENTS;
   sect->alignment_power = 2;
@@ -7386,9 +7690,18 @@ _bfd_elf_rela_local_sym (bfd *abfd,
       rel->r_addend =
        _bfd_merged_section_offset (abfd, psec,
                                    elf_section_data (sec)->sec_info,
-                                   sym->st_value + rel->r_addend,
-                                   0);
-      sec = *psec;
+                                   sym->st_value + rel->r_addend);
+      if (sec != *psec)
+       {
+         /* If we have changed the section, and our original section is
+            marked with SEC_EXCLUDE, it means that the original
+            SEC_MERGE section has been completely subsumed in some
+            other SEC_MERGE section.  In this case, we need to leave
+            some info around for --emit-relocs.  */
+         if ((sec->flags & SEC_EXCLUDE) != 0)
+           sec->kept_section = *psec;
+         sec = *psec;
+       }
       rel->r_addend -= relocation;
       rel->r_addend += sec->output_section->vma + sec->output_offset;
     }
@@ -7408,24 +7721,20 @@ _bfd_elf_rel_local_sym (bfd *abfd,
 
   return _bfd_merged_section_offset (abfd, psec,
                                     elf_section_data (sec)->sec_info,
-                                    sym->st_value + addend, 0);
+                                    sym->st_value + addend);
 }
 
 bfd_vma
 _bfd_elf_section_offset (bfd *abfd,
-                        struct bfd_link_info *info,
+                        struct bfd_link_info *info ATTRIBUTE_UNUSED,
                         asection *sec,
                         bfd_vma offset)
 {
-  struct bfd_elf_section_data *sec_data;
-
-  sec_data = elf_section_data (sec);
   switch (sec->sec_info_type)
     {
     case ELF_INFO_TYPE_STABS:
-      return _bfd_stab_section_offset (abfd,
-                                      &elf_hash_table (info)->merge_info,
-                                      sec, &sec_data->sec_info, offset);
+      return _bfd_stab_section_offset (sec, elf_section_data (sec)->sec_info,
+                                      offset);
     case ELF_INFO_TYPE_EH_FRAME:
       return _bfd_elf_eh_frame_section_offset (abfd, sec, offset);
     default:
@@ -7456,3 +7765,296 @@ bfd_elf_bfd_from_remote_memory
   return (*get_elf_backend_data (templ)->elf_backend_bfd_from_remote_memory)
     (templ, ehdr_vma, loadbasep, target_read_memory);
 }
+\f
+long
+_bfd_elf_get_synthetic_symtab (bfd *abfd,
+                              long symcount ATTRIBUTE_UNUSED,
+                              asymbol **syms ATTRIBUTE_UNUSED,
+                              long dynsymcount ATTRIBUTE_UNUSED,
+                              asymbol **dynsyms,
+                              asymbol **ret)
+{
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  asection *relplt;
+  asymbol *s;
+  const char *relplt_name;
+  bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
+  arelent *p;
+  long count, i, n;
+  size_t size;
+  Elf_Internal_Shdr *hdr;
+  char *names;
+  asection *plt;
+
+  if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0)
+    return 0;
+
+  *ret = NULL;
+  if (!bed->plt_sym_val)
+    return 0;
+
+  relplt_name = bed->relplt_name;
+  if (relplt_name == NULL)
+    relplt_name = bed->default_use_rela_p ? ".rela.plt" : ".rel.plt";
+  relplt = bfd_get_section_by_name (abfd, relplt_name);
+  if (relplt == NULL)
+    return 0;
+
+  hdr = &elf_section_data (relplt)->this_hdr;
+  if (hdr->sh_link != elf_dynsymtab (abfd)
+      || (hdr->sh_type != SHT_REL && hdr->sh_type != SHT_RELA))
+    return 0;
+
+  plt = bfd_get_section_by_name (abfd, ".plt");
+  if (plt == NULL)
+    return 0;
+
+  slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
+  if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE))
+    return -1;
+
+  count = relplt->size / hdr->sh_entsize;
+  size = count * sizeof (asymbol);
+  p = relplt->relocation;
+  for (i = 0; i < count; i++, s++, p++)
+    size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
+
+  s = *ret = bfd_malloc (size);
+  if (s == NULL)
+    return -1;
+
+  names = (char *) (s + count);
+  p = relplt->relocation;
+  n = 0;
+  for (i = 0; i < count; i++, s++, p++)
+    {
+      size_t len;
+      bfd_vma addr;
+
+      addr = bed->plt_sym_val (i, plt, p);
+      if (addr == (bfd_vma) -1)
+       continue;
+
+      *s = **p->sym_ptr_ptr;
+      s->section = plt;
+      s->value = addr - plt->vma;
+      s->name = names;
+      len = strlen ((*p->sym_ptr_ptr)->name);
+      memcpy (names, (*p->sym_ptr_ptr)->name, len);
+      names += len;
+      memcpy (names, "@plt", sizeof ("@plt"));
+      names += sizeof ("@plt");
+      ++n;
+    }
+
+  return n;
+}
+
+/* Sort symbol by binding and section. We want to put definitions
+   sorted by section at the beginning.  */
+
+static int
+elf_sort_elf_symbol (const void *arg1, const void *arg2)
+{
+  const Elf_Internal_Sym *s1;
+  const Elf_Internal_Sym *s2;
+  int shndx;
+
+  /* Make sure that undefined symbols are at the end.  */
+  s1 = (const Elf_Internal_Sym *) arg1;
+  if (s1->st_shndx == SHN_UNDEF)
+    return 1;
+  s2 = (const Elf_Internal_Sym *) arg2;
+  if (s2->st_shndx == SHN_UNDEF)
+    return -1;
+
+  /* Sorted by section index.  */
+  shndx = s1->st_shndx - s2->st_shndx;
+  if (shndx != 0)
+    return shndx;
+
+  /* Sorted by binding.  */
+  return ELF_ST_BIND (s1->st_info)  - ELF_ST_BIND (s2->st_info);
+}
+
+struct elf_symbol
+{
+  Elf_Internal_Sym *sym;
+  const char *name;
+};
+
+static int
+elf_sym_name_compare (const void *arg1, const void *arg2)
+{
+  const struct elf_symbol *s1 = (const struct elf_symbol *) arg1;
+  const struct elf_symbol *s2 = (const struct elf_symbol *) arg2;
+  return strcmp (s1->name, s2->name);
+}
+
+/* Check if 2 sections define the same set of local and global
+   symbols.  */
+
+bfd_boolean
+bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2)
+{
+  bfd *bfd1, *bfd2;
+  const struct elf_backend_data *bed1, *bed2;
+  Elf_Internal_Shdr *hdr1, *hdr2;
+  bfd_size_type symcount1, symcount2;
+  Elf_Internal_Sym *isymbuf1, *isymbuf2;
+  Elf_Internal_Sym *isymstart1 = NULL, *isymstart2 = NULL, *isym;
+  Elf_Internal_Sym *isymend;
+  struct elf_symbol *symp, *symtable1 = NULL, *symtable2 = NULL;
+  bfd_size_type count1, count2, i;
+  int shndx1, shndx2;
+  bfd_boolean result;
+
+  bfd1 = sec1->owner;
+  bfd2 = sec2->owner;
+
+  /* If both are .gnu.linkonce sections, they have to have the same
+     section name.  */
+  if (strncmp (sec1->name, ".gnu.linkonce",
+              sizeof ".gnu.linkonce" - 1) == 0
+      && strncmp (sec2->name, ".gnu.linkonce",
+                 sizeof ".gnu.linkonce" - 1) == 0)
+    return strcmp (sec1->name + sizeof ".gnu.linkonce",
+                  sec2->name + sizeof ".gnu.linkonce") == 0;
+
+  /* Both sections have to be in ELF.  */
+  if (bfd_get_flavour (bfd1) != bfd_target_elf_flavour
+      || bfd_get_flavour (bfd2) != bfd_target_elf_flavour)
+    return FALSE;
+
+  if (elf_section_type (sec1) != elf_section_type (sec2))
+    return FALSE;
+
+  if ((elf_section_flags (sec1) & SHF_GROUP) != 0
+      && (elf_section_flags (sec2) & SHF_GROUP) != 0)
+    {
+      /* If both are members of section groups, they have to have the
+        same group name.  */
+      if (strcmp (elf_group_name (sec1), elf_group_name (sec2)) != 0)
+       return FALSE;
+    }
+
+  shndx1 = _bfd_elf_section_from_bfd_section (bfd1, sec1);
+  shndx2 = _bfd_elf_section_from_bfd_section (bfd2, sec2);
+  if (shndx1 == -1 || shndx2 == -1)
+    return FALSE;
+
+  bed1 = get_elf_backend_data (bfd1);
+  bed2 = get_elf_backend_data (bfd2);
+  hdr1 = &elf_tdata (bfd1)->symtab_hdr;
+  symcount1 = hdr1->sh_size / bed1->s->sizeof_sym;
+  hdr2 = &elf_tdata (bfd2)->symtab_hdr;
+  symcount2 = hdr2->sh_size / bed2->s->sizeof_sym;
+
+  if (symcount1 == 0 || symcount2 == 0)
+    return FALSE;
+
+  isymbuf1 = bfd_elf_get_elf_syms (bfd1, hdr1, symcount1, 0,
+                                  NULL, NULL, NULL);
+  isymbuf2 = bfd_elf_get_elf_syms (bfd2, hdr2, symcount2, 0,
+                                  NULL, NULL, NULL);
+
+  result = FALSE;
+  if (isymbuf1 == NULL || isymbuf2 == NULL)
+    goto done;
+
+  /* Sort symbols by binding and section. Global definitions are at
+     the beginning.  */
+  qsort (isymbuf1, symcount1, sizeof (Elf_Internal_Sym),
+        elf_sort_elf_symbol);
+  qsort (isymbuf2, symcount2, sizeof (Elf_Internal_Sym),
+        elf_sort_elf_symbol);
+
+  /* Count definitions in the section.  */
+  count1 = 0;
+  for (isym = isymbuf1, isymend = isym + symcount1;
+       isym < isymend; isym++)
+    {
+      if (isym->st_shndx == (unsigned int) shndx1)
+       {
+         if (count1 == 0)
+           isymstart1 = isym;
+         count1++;
+       }
+
+      if (count1 && isym->st_shndx != (unsigned int) shndx1)
+       break;
+    }
+
+  count2 = 0;
+  for (isym = isymbuf2, isymend = isym + symcount2;
+       isym < isymend; isym++)
+    {
+      if (isym->st_shndx == (unsigned int) shndx2)
+       {
+         if (count2 == 0)
+           isymstart2 = isym;
+         count2++;
+       }
+
+      if (count2 && isym->st_shndx != (unsigned int) shndx2)
+       break;
+    }
+
+  if (count1 == 0 || count2 == 0 || count1 != count2)
+    goto done;
+
+  symtable1 = bfd_malloc (count1 * sizeof (struct elf_symbol));
+  symtable2 = bfd_malloc (count1 * sizeof (struct elf_symbol));
+
+  if (symtable1 == NULL || symtable2 == NULL)
+    goto done;
+
+  symp = symtable1;
+  for (isym = isymstart1, isymend = isym + count1;
+       isym < isymend; isym++)
+    {
+      symp->sym = isym;
+      symp->name = bfd_elf_string_from_elf_section (bfd1,
+                                                   hdr1->sh_link,
+                                                   isym->st_name);
+      symp++;
+    }
+  symp = symtable2;
+  for (isym = isymstart2, isymend = isym + count1;
+       isym < isymend; isym++)
+    {
+      symp->sym = isym;
+      symp->name = bfd_elf_string_from_elf_section (bfd2,
+                                                   hdr2->sh_link,
+                                                   isym->st_name);
+      symp++;
+    }
+  
+  /* Sort symbol by name.  */
+  qsort (symtable1, count1, sizeof (struct elf_symbol),
+        elf_sym_name_compare);
+  qsort (symtable2, count1, sizeof (struct elf_symbol),
+        elf_sym_name_compare);
+
+  for (i = 0; i < count1; i++)
+    /* Two symbols must have the same binding, type and name.  */
+    if (symtable1 [i].sym->st_info != symtable2 [i].sym->st_info
+       || symtable1 [i].sym->st_other != symtable2 [i].sym->st_other
+       || strcmp (symtable1 [i].name, symtable2 [i].name) != 0)
+      goto done;
+
+  result = TRUE;
+
+done:
+  if (symtable1)
+    free (symtable1);
+  if (symtable2)
+    free (symtable2);
+  if (isymbuf1)
+    free (isymbuf1);
+  if (isymbuf2)
+    free (isymbuf2);
+
+  return result;
+}
This page took 0.044896 seconds and 4 git commands to generate.