* elf64-ppc.c (ppc_add_stub): Replace strcpy/strncpy with memcpy.
[deliverable/binutils-gdb.git] / bfd / elf.c
index 7f63b34adcc3bc16c88fe979a92894c6122afc0e..5472a16379bb57fb34ceff1672e92dfe953fcca2 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -50,10 +50,10 @@ static boolean prep_headers PARAMS ((bfd *));
 static boolean swap_out_syms PARAMS ((bfd *, struct bfd_strtab_hash **, int));
 static boolean copy_private_bfd_data PARAMS ((bfd *, bfd *));
 static char *elf_read PARAMS ((bfd *, file_ptr, bfd_size_type));
+static const char *group_signature PARAMS ((bfd *, Elf_Internal_Shdr *));
 static boolean setup_group PARAMS ((bfd *, Elf_Internal_Shdr *, asection *));
 static void merge_sections_remove_hook PARAMS ((bfd *, asection *));
 static void elf_fake_sections PARAMS ((bfd *, asection *, PTR));
-static void set_group_contents PARAMS ((bfd *, asection *, PTR));
 static boolean assign_section_numbers PARAMS ((bfd *));
 static INLINE int sym_is_global PARAMS ((bfd *, asymbol *));
 static boolean elf_map_symbols PARAMS ((bfd *));
@@ -361,6 +361,66 @@ typedef union elf_internal_group {
   unsigned int flags;
 } Elf_Internal_Group;
 
+/* Return the name of the group signature symbol.  Why isn't the
+   signature just a string?  */
+
+static const char *
+group_signature (abfd, ghdr)
+     bfd *abfd;
+     Elf_Internal_Shdr *ghdr;
+{
+  struct elf_backend_data *bed;
+  file_ptr pos;
+  bfd_size_type amt;
+  Elf_Internal_Shdr *hdr;
+  Elf_Internal_Shdr *shndx_hdr;
+  unsigned char esym[sizeof (Elf64_External_Sym)];
+  Elf_External_Sym_Shndx eshndx;
+  Elf_Internal_Sym isym;
+  unsigned int iname;
+  unsigned int shindex;
+
+  /* First we need to ensure the symbol table is available.  */
+  if (! bfd_section_from_shdr (abfd, ghdr->sh_link))
+    return NULL;
+
+  /* Go read the symbol.  */
+  hdr = &elf_tdata (abfd)->symtab_hdr;
+  bed = get_elf_backend_data (abfd);
+  amt = bed->s->sizeof_sym;
+  pos = hdr->sh_offset + ghdr->sh_info * amt;
+  if (bfd_seek (abfd, pos, SEEK_SET) != 0
+      || bfd_bread (esym, amt, abfd) != amt)
+    return NULL;
+
+  /* And possibly the symbol section index extension.  */
+  shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
+  if (elf_elfsections (abfd) != NULL
+      && elf_elfsections (abfd)[shndx_hdr->sh_link] == hdr)
+    {
+      amt = sizeof (Elf_External_Sym_Shndx);
+      pos = shndx_hdr->sh_offset + ghdr->sh_info * amt;
+      if (bfd_seek (abfd, pos, SEEK_SET) != 0
+         || bfd_bread ((PTR) &eshndx, amt, abfd) != amt)
+       return NULL;
+    }
+
+  /* Convert to internal format.  */
+  (*bed->s->swap_symbol_in) (abfd, (const PTR *) &esym, (const PTR *) &eshndx,
+                            &isym);
+
+  /* Look up the symbol name.  */
+  iname = isym.st_name;
+  shindex = hdr->sh_link;
+  if (iname == 0 && ELF_ST_TYPE (isym.st_info) == STT_SECTION)
+    {
+      iname = elf_elfsections (abfd)[isym.st_shndx]->sh_name;
+      shindex = elf_elfheader (abfd)->e_shstrndx;
+    }
+
+  return bfd_elf_string_from_elf_section (abfd, shindex, iname);
+}
+
 /* Set next_in_group list pointer, and group name for NEWSECT.  */
 
 static boolean
@@ -440,6 +500,9 @@ setup_group (abfd, hdr, newsect)
                      if (src == shdr->contents)
                        {
                          dest->flags = idx;
+                         if (shdr->bfd_section != NULL && (idx & GRP_COMDAT))
+                           shdr->bfd_section->flags
+                             |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
                          break;
                        }
                      if (idx >= shnum)
@@ -492,32 +555,22 @@ setup_group (abfd, hdr, newsect)
                  }
                else
                  {
-                   struct elf_backend_data *bed;
-                   file_ptr pos;
-                   unsigned char ename[4];
-                   unsigned long iname;
                    const char *gname;
 
-                   /* Humbug.  Get the name from the group signature
-                      symbol.  Why isn't the signature just a string?
-                      Fortunately, the name index is at the same
-                      place in the external symbol for both 32 and 64
-                      bit ELF.  */
-                   bed = get_elf_backend_data (abfd);
-                   pos = elf_tdata (abfd)->symtab_hdr.sh_offset;
-                   pos += shdr->sh_info * bed->s->sizeof_sym;
-                   if (bfd_seek (abfd, pos, SEEK_SET) != 0
-                       || bfd_bread (ename, (bfd_size_type) 4, abfd) != 4)
+                   gname = group_signature (abfd, shdr);
+                   if (gname == NULL)
                      return false;
-                   iname = H_GET_32 (abfd, ename);
-                   gname = elf_string_from_elf_strtab (abfd, iname);
                    elf_group_name (newsect) = gname;
 
                    /* Start a circular list with one element.  */
                    elf_next_in_group (newsect) = newsect;
                  }
+
+               /* If the group section has been created, point to the
+                  new member.  */
                if (shdr->bfd_section != NULL)
                  elf_next_in_group (shdr->bfd_section) = newsect;
+
                i = num_group - 1;
                break;
              }
@@ -532,6 +585,25 @@ setup_group (abfd, hdr, newsect)
   return true;
 }
 
+boolean
+bfd_elf_discard_group (abfd, group)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     asection *group;
+{
+  asection *first = elf_next_in_group (group);
+  asection *s = first;
+
+  while (s != NULL)
+    {
+      s->output_section = bfd_abs_section_ptr;
+      s = elf_next_in_group (s);
+      /* These lists are circular.  */
+      if (s == first)
+       break;
+    }
+  return true;
+}
+
 /* Make a BFD section from an ELF section.  We store a pointer to the
    BFD section in the bfd_section field of the header.  */
 
@@ -591,6 +663,8 @@ _bfd_elf_make_section_from_shdr (abfd, hdr, name)
   if (hdr->sh_flags & SHF_GROUP)
     if (!setup_group (abfd, hdr, newsect))
       return false;
+  if ((hdr->sh_flags & SHF_TLS) != 0)
+    flags |= SEC_THREAD_LOCAL;
 
   /* The debugging sections appear to be recognized only by name, not
      any sort of flag.  */
@@ -618,7 +692,8 @@ _bfd_elf_make_section_from_shdr (abfd, hdr, name)
      The symbols will be defined as weak, so that multiple definitions
      are permitted.  The GNU linker extension is to actually discard
      all but one of the sections.  */
-  if (strncmp (name, ".gnu.linkonce", sizeof ".gnu.linkonce" - 1) == 0)
+  if (strncmp (name, ".gnu.linkonce", sizeof ".gnu.linkonce" - 1) == 0
+      && elf_next_in_group (newsect) == NULL)
     flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
 
   bed = get_elf_backend_data (abfd);
@@ -655,9 +730,9 @@ _bfd_elf_make_section_from_shdr (abfd, hdr, name)
 
                 Note - we used to check the p_paddr field as well, and
                 refuse to set the LMA if it was 0.  This is wrong
-                though as a perfectly valid, initialised segment can
+                though, as a perfectly valid initialised segment can
                 have a p_paddr of zero.  Some architectures, eg ARM,
-                place special significance one the address 0 and
+                place special significance on the address 0 and
                 executables need to be able to have a segment which
                 covers this address.  */
              if (phdr->p_type == PT_LOAD
@@ -665,19 +740,31 @@ _bfd_elf_make_section_from_shdr (abfd, hdr, name)
                  && (hdr->sh_offset + hdr->sh_size
                      <= phdr->p_offset + phdr->p_memsz)
                  && ((flags & SEC_LOAD) == 0
-                     || (phdr->p_offset + phdr->p_filesz
-                         >= hdr->sh_offset + hdr->sh_size)))
+                     || (hdr->sh_offset + hdr->sh_size
+                         <= phdr->p_offset + phdr->p_filesz)))
                {
-                 /* We used to do a relative adjustment here, but
-                    that doesn't work if the segment is packed with
-                    code from multiple VMAs.  Instead we calculate
-                    the LMA absoultely, based on the LMA of the
-                    segment (it is assumed that the segment will
-                    contain sections with contiguous LMAs, even if
-                    the VMAs are not).  */
-                 newsect->lma = phdr->p_paddr
-                   + hdr->sh_offset - phdr->p_offset;
-                 break;
+                 if ((flags & SEC_LOAD) == 0)
+                   newsect->lma = (phdr->p_paddr
+                                   + hdr->sh_addr - phdr->p_vaddr);
+                 else
+                   /* We used to use the same adjustment for SEC_LOAD
+                      sections, but that doesn't work if the segment
+                      is packed with code from multiple VMAs.
+                      Instead we calculate the section LMA based on
+                      the segment LMA.  It is assumed that the
+                      segment will contain sections with contiguous
+                      LMAs, even if the VMAs are not.  */
+                   newsect->lma = (phdr->p_paddr
+                                   + hdr->sh_offset - phdr->p_offset);
+
+                 /* With contiguous segments, we can't tell from file
+                    offsets whether a section with zero size should
+                    be placed at the end of one segment or the
+                    beginning of the next.  Decide based on vaddr.  */
+                 if (hdr->sh_addr >= phdr->p_vaddr
+                     && (hdr->sh_addr + hdr->sh_size
+                         <= phdr->p_vaddr + phdr->p_memsz))
+                   break;
                }
            }
        }
@@ -802,6 +889,19 @@ _bfd_elf_merge_sections (abfd, info)
                         merge_sections_remove_hook);
   return true;
 }
+
+void
+_bfd_elf_link_just_syms (sec, info)
+     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))
+    return;
+
+  elf_section_data (sec)->sec_info_type = ELF_INFO_TYPE_JUST_SYMS;
+}
 \f
 /* Copy the program header and other data from one object module to
    another.  */
@@ -858,6 +958,7 @@ _bfd_elf_print_private_bfd_data (abfd, farg)
            case PT_NOTE: pt = "NOTE"; break;
            case PT_SHLIB: pt = "SHLIB"; break;
            case PT_PHDR: pt = "PHDR"; break;
+           case PT_TLS: pt = "TLS"; break;
            case PT_GNU_EH_FRAME: pt = "EH_FRAME"; break;
            default: sprintf (buf, "0x%lx", p->p_type); pt = buf; break;
            }
@@ -1329,6 +1430,7 @@ _bfd_elf_link_hash_table_init (table, abfd, newfunc)
   table->bucketcount = 0;
   table->needed = NULL;
   table->runpath = NULL;
+  table->loaded = NULL;
   table->hgot = NULL;
   table->stab_info = NULL;
   table->merge_info = NULL;
@@ -1348,13 +1450,13 @@ _bfd_elf_link_hash_table_create (abfd)
   struct elf_link_hash_table *ret;
   bfd_size_type amt = sizeof (struct elf_link_hash_table);
 
-  ret = (struct elf_link_hash_table *) bfd_alloc (abfd, amt);
+  ret = (struct elf_link_hash_table *) bfd_malloc (amt);
   if (ret == (struct elf_link_hash_table *) NULL)
     return NULL;
 
   if (! _bfd_elf_link_hash_table_init (ret, abfd, _bfd_elf_link_hash_newfunc))
     {
-      bfd_release (abfd, ret);
+      free (ret);
       return NULL;
     }
 
@@ -1548,7 +1650,7 @@ bfd_section_from_shdr (abfd, shindex)
   Elf_Internal_Shdr *hdr = elf_elfsections (abfd)[shindex];
   Elf_Internal_Ehdr *ehdr = elf_elfheader (abfd);
   struct elf_backend_data *bed = get_elf_backend_data (abfd);
-  char *name;
+  const char *name;
 
   name = elf_string_from_elf_strtab (abfd, hdr->sh_name);
 
@@ -1563,6 +1665,9 @@ bfd_section_from_shdr (abfd, shindex)
     case SHT_NOBITS:   /* .bss section.  */
     case SHT_HASH:     /* .hash section.  */
     case SHT_NOTE:     /* .note section.  */
+    case SHT_INIT_ARRAY:       /* .init_array section.  */
+    case SHT_FINI_ARRAY:       /* .fini_array section.  */
+    case SHT_PREINIT_ARRAY:    /* .preinit_array section.  */
       return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
 
     case SHT_SYMTAB:           /* A symbol table */
@@ -1789,7 +1894,12 @@ bfd_section_from_shdr (abfd, shindex)
       return true;
 
     case SHT_GROUP:
-      /* Make a section for objcopy and relocatable links.  */
+      /* We need a BFD section for objcopy and relocatable linking,
+        and it's handy to have the signature available as the section
+        name.  */
+      name = group_signature (abfd, hdr);
+      if (name == NULL)
+       return false;
       if (!_bfd_elf_make_section_from_shdr (abfd, hdr, name))
        return false;
       if (hdr->contents != NULL)
@@ -1798,6 +1908,10 @@ bfd_section_from_shdr (abfd, shindex)
          unsigned int n_elt = hdr->sh_size / 4;
          asection *s;
 
+         if (idx->flags & GRP_COMDAT)
+           hdr->bfd_section->flags
+             |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
+
          while (--n_elt != 0)
            if ((s = (++idx)->shdr->bfd_section) != NULL
                && elf_next_in_group (s) != NULL)
@@ -1957,16 +2071,18 @@ _bfd_elf_make_section_from_phdr (abfd, hdr, index, typename)
   asection *newsect;
   char *name;
   char namebuf[64];
+  size_t len;
   int split;
 
   split = ((hdr->p_memsz > 0)
            && (hdr->p_filesz > 0)
            && (hdr->p_memsz > hdr->p_filesz));
   sprintf (namebuf, "%s%d%s", typename, index, split ? "a" : "");
-  name = bfd_alloc (abfd, (bfd_size_type) strlen (namebuf) + 1);
+  len = strlen (namebuf) + 1;
+  name = bfd_alloc (abfd, (bfd_size_type) len);
   if (!name)
     return false;
-  strcpy (name, namebuf);
+  memcpy (name, namebuf, len);
   newsect = bfd_make_section (abfd, name);
   if (newsect == NULL)
     return false;
@@ -1994,10 +2110,11 @@ _bfd_elf_make_section_from_phdr (abfd, hdr, index, typename)
   if (split)
     {
       sprintf (namebuf, "%s%db", typename, index);
-      name = bfd_alloc (abfd, (bfd_size_type) strlen (namebuf) + 1);
+      len = strlen (namebuf) + 1;
+      name = bfd_alloc (abfd, (bfd_size_type) len);
       if (!name)
        return false;
-      strcpy (name, namebuf);
+      memcpy (name, namebuf, len);
       newsect = bfd_make_section (abfd, name);
       if (newsect == NULL)
        return false;
@@ -2177,6 +2294,12 @@ elf_fake_sections (abfd, asect, failedptrarg)
       this_hdr->sh_type = SHT_REL;
       this_hdr->sh_entsize = bed->s->sizeof_rel;
     }
+  else if (strcmp (asect->name, ".init_array") == 0)
+    this_hdr->sh_type = SHT_INIT_ARRAY;
+  else if (strcmp (asect->name, ".fini_array") == 0)
+    this_hdr->sh_type = SHT_FINI_ARRAY;
+  else if (strcmp (asect->name, ".preinit_array") == 0)
+    this_hdr->sh_type = SHT_PREINIT_ARRAY;
   else if (strncmp (asect->name, ".note", 5) == 0)
     this_hdr->sh_type = SHT_NOTE;
   else if (strncmp (asect->name, ".stab", 5) == 0
@@ -2238,8 +2361,10 @@ elf_fake_sections (abfd, asect, failedptrarg)
       if ((asect->flags & SEC_STRINGS) != 0)
        this_hdr->sh_flags |= SHF_STRINGS;
     }
-  if (elf_group_name (asect) != NULL)
+  if ((asect->flags & SEC_GROUP) == 0 && elf_group_name (asect) != NULL)
     this_hdr->sh_flags |= SHF_GROUP;
+  if ((asect->flags & SEC_THREAD_LOCAL) != 0)
+    this_hdr->sh_flags |= SHF_TLS;
 
   /* Check for processor-specific section types.  */
   if (bed->elf_backend_fake_sections
@@ -2260,35 +2385,47 @@ elf_fake_sections (abfd, asect, failedptrarg)
 
 /* Fill in the contents of a SHT_GROUP section.  */
 
-static void
-set_group_contents (abfd, sec, failedptrarg)
+void
+bfd_elf_set_group_contents (abfd, sec, failedptrarg)
      bfd *abfd;
      asection *sec;
-     PTR failedptrarg ATTRIBUTE_UNUSED;
+     PTR failedptrarg;
 {
   boolean *failedptr = (boolean *) failedptrarg;
   unsigned long symindx;
-  asection *elt;
+  asection *elt, *first;
   unsigned char *loc;
   struct bfd_link_order *l;
+  boolean gas;
 
   if (elf_section_data (sec)->this_hdr.sh_type != SHT_GROUP
       || *failedptr)
     return;
 
-  /* If called from the assembler, swap_out_syms will have set up
-     elf_section_syms;  If called for "ld -r", the symbols won't yet
-     be mapped, so emulate elf_bfd_final_link.  */
-  if (elf_section_syms (abfd) != NULL)
-    symindx = elf_section_syms (abfd)[sec->index]->udata.i;
-  else
-    symindx = elf_section_data (sec)->this_idx;
+  symindx = 0;
+  if (elf_group_id (sec) != NULL)
+    symindx = elf_group_id (sec)->udata.i;
+
+  if (symindx == 0)
+    {
+      /* If called from the assembler, swap_out_syms will have set up
+        elf_section_syms;  If called for "ld -r", use target_index.  */
+      if (elf_section_syms (abfd) != NULL)
+       symindx = elf_section_syms (abfd)[sec->index]->udata.i;
+      else
+       symindx = sec->target_index;
+    }
   elf_section_data (sec)->this_hdr.sh_info = symindx;
 
-  /* Nor will the contents be allocated for "ld -r".  */
+  /* The contents won't be allocated for "ld -r" or objcopy.  */
+  gas = true;
   if (sec->contents == NULL)
     {
+      gas = false;
       sec->contents = bfd_alloc (abfd, sec->_raw_size);
+
+      /* Arrange for the section to be written out.  */
+      elf_section_data (sec)->this_hdr.contents = sec->contents;
       if (sec->contents == NULL)
        {
          *failedptr = true;
@@ -2298,9 +2435,10 @@ set_group_contents (abfd, sec, failedptrarg)
 
   loc = sec->contents + sec->_raw_size;
 
-  /* Get the pointer to the first section in the group that we
-     squirreled away here.  */
-  elt = elf_next_in_group (sec);
+  /* Get the pointer to the first section in the group that gas
+     squirreled away here.  objcopy arranges for this to be set to the
+     start of the input section group.  */
+  first = elt = elf_next_in_group (sec);
 
   /* First element is a flag word.  Rest of section is elf section
      indices for all the sections of the group.  Write them backwards
@@ -2308,9 +2446,20 @@ set_group_contents (abfd, sec, failedptrarg)
      directives, not that it matters.  */
   while (elt != NULL)
     {
+      asection *s;
+      unsigned int idx;
+
       loc -= 4;
-      H_PUT_32 (abfd, elf_section_data (elt)->this_idx, loc);
+      s = elt;
+      if (!gas)
+       s = s->output_section;
+      idx = 0;
+      if (s != NULL)
+       idx = elf_section_data (s)->this_idx;
+      H_PUT_32 (abfd, idx, loc);
       elt = elf_next_in_group (elt);
+      if (elt == first)
+       break;
     }
 
   /* If this is a relocatable link, then the above did nothing because
@@ -2329,10 +2478,16 @@ set_group_contents (abfd, sec, failedptrarg)
        }
       while (elt != elf_next_in_group (l->u.indirect.section));
 
-  loc -= 4;
-  H_PUT_32 (abfd, 0, loc);
+  /* 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)
+    abort ();
 
-  BFD_ASSERT (loc == sec->contents);
+  H_PUT_32 (abfd, sec->flags & SEC_LINK_ONCE ? GRP_COMDAT : 0, loc);
 }
 
 /* Assign all ELF section numbers.  The dummy first section is handled here
@@ -2514,10 +2669,10 @@ assign_section_numbers (abfd)
              char *alc;
 
              len = strlen (sec->name);
-             alc = (char *) bfd_malloc ((bfd_size_type) len - 2);
+             alc = (char *) bfd_malloc ((bfd_size_type) (len - 2));
              if (alc == NULL)
                return false;
-             strncpy (alc, sec->name, len - 3);
+             memcpy (alc, sec->name, len - 3);
              alc[len - 3] = '\0';
              s = bfd_get_section_by_name (abfd, alc);
              free (alc);
@@ -2813,9 +2968,9 @@ _bfd_elf_compute_section_file_positions (abfd, link_info)
        return false;
     }
 
-  if (link_info == NULL || link_info->relocateable)
+  if (link_info == NULL)
     {
-      bfd_map_over_sections (abfd, set_group_contents, &failed);
+      bfd_map_over_sections (abfd, bfd_elf_set_group_contents, &failed);
       if (failed)
        return false;
     }
@@ -2922,6 +3077,8 @@ map_sections_to_segments (abfd)
   asection **hdrpp;
   boolean phdr_in_segment = true;
   boolean writable;
+  int tls_count = 0;
+  asection *first_tls = NULL;
   asection *dynsec, *eh_frame_hdr;
   bfd_size_type amt;
 
@@ -3160,6 +3317,39 @@ map_sections_to_segments (abfd)
          *pm = m;
          pm = &m->next;
        }
+      if (s->flags & SEC_THREAD_LOCAL)
+       {
+         if (! tls_count)
+           first_tls = s;
+         tls_count++;
+       }
+    }
+
+  /* If there are any SHF_TLS output sections, add PT_TLS segment.  */
+  if (tls_count > 0)
+    {
+      int i;
+
+      amt = sizeof (struct elf_segment_map);
+      amt += (tls_count - 1) * sizeof (asection *);
+      m = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
+      if (m == NULL)
+       goto error_return;
+      m->next = NULL;
+      m->p_type = PT_TLS;
+      m->count = tls_count;
+      /* Mandated PF_R.  */
+      m->p_flags = PF_R;
+      m->p_flags_valid = 1;
+      for (i = 0; i < tls_count; ++i)
+       {
+         BFD_ASSERT (first_tls->flags & SEC_THREAD_LOCAL);
+         m->sections[i] = first_tls;
+         first_tls = first_tls->next;
+       }
+
+      *pm = m;
+      pm = &m->next;
     }
 
   /* If there is a .eh_frame_hdr section, throw in a PT_GNU_EH_FRAME
@@ -3274,6 +3464,37 @@ assign_file_positions_for_segments (abfd)
       if (! map_sections_to_segments (abfd))
        return false;
     }
+  else
+    {
+      /* The placement algorithm assumes that non allocated sections are
+        not in PT_LOAD segments.  We ensure this here by removing such
+        sections from the segment map.  */
+      for (m = elf_tdata (abfd)->segment_map;
+          m != NULL;
+          m = m->next)
+       {
+         unsigned int new_count;
+         unsigned int i;
+
+         if (m->p_type != PT_LOAD)
+           continue;
+
+         new_count = 0;
+         for (i = 0; i < m->count; i ++)
+           {
+             if ((m->sections[i]->flags & SEC_ALLOC) != 0)
+               {
+                 if (i != new_count) 
+                   m->sections[new_count] = m->sections[i];
+
+                 new_count ++;
+               }
+           }
+
+         if (new_count != m->count)
+           m->count = new_count;
+       }
+    }
 
   if (bed->elf_backend_modify_segment_map)
     {
@@ -3403,8 +3624,9 @@ assign_file_positions_for_segments (abfd)
 
              if (p->p_vaddr < (bfd_vma) off)
                {
-                 _bfd_error_handler (_("%s: Not enough room for program headers, try linking with -N"),
-                                     bfd_get_filename (abfd));
+                 (*_bfd_error_handler)
+                   (_("%s: Not enough room for program headers, try linking with -N"),
+                    bfd_get_filename (abfd));
                  bfd_set_error (bfd_error_bad_value);
                  return false;
                }
@@ -3584,6 +3806,20 @@ Error: First section in segment (%s) starts at 0x%x whereas the segment starts a
              if ((flags & SEC_LOAD) != 0)
                p->p_filesz += sec->_raw_size;
 
+             if (p->p_type == PT_TLS
+                 && sec->_raw_size == 0
+                 && (sec->flags & SEC_HAS_CONTENTS) == 0)
+               {
+                 struct bfd_link_order *o;
+                 bfd_vma tbss_size = 0;
+
+                 for (o = sec->link_order_head; o != NULL; o = o->next)
+                   if (tbss_size < o->offset + o->size)
+                     tbss_size = o->offset + o->size;
+
+                 p->p_memsz += tbss_size;
+               }
+
              if (align > p->p_align
                  && (p->p_type != PT_LOAD || (abfd->flags & D_PAGED) == 0))
                p->p_align = align;
@@ -3628,6 +3864,11 @@ Error: First section in segment (%s) starts at 0x%x whereas the segment starts a
        }
     }
 
+  /* If additional nonloadable filepos adjustments are required,
+     do them now. */
+  if (bed->set_nonloadable_filepos)
+    (*bed->set_nonloadable_filepos) (abfd, phdrs);
+
   /* Clear out any program headers we allocated but did not use.  */
   for (; count < alloc; count++, p++)
     {
@@ -3718,6 +3959,16 @@ get_program_header_size (abfd)
        }
     }
 
+  for (s = abfd->sections; s != NULL; s = s->next)
+    {
+      if (s->flags & SEC_THREAD_LOCAL)
+       {
+         /* We need a PT_TLS segment.  */
+         ++segs;
+         break;
+       }
+    }
+
   /* Let the backend count up any program headers it might need.  */
   if (bed->elf_backend_additional_program_headers)
     {
@@ -3860,7 +4111,6 @@ prep_headers (abfd)
   Elf_Internal_Ehdr *i_ehdrp;  /* Elf file header, internal form */
   Elf_Internal_Phdr *i_phdrp = 0; /* Program header table, internal form */
   Elf_Internal_Shdr **i_shdrp; /* Section header table, internal form */
-  int count;
   struct elf_strtab_hash *shstrtab;
   struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
@@ -3883,12 +4133,6 @@ prep_headers (abfd)
     bfd_big_endian (abfd) ? ELFDATA2MSB : ELFDATA2LSB;
   i_ehdrp->e_ident[EI_VERSION] = bed->s->ev_current;
 
-  i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_NONE;
-  i_ehdrp->e_ident[EI_ABIVERSION] = 0;
-
-  for (count = EI_PAD; count < EI_NIDENT; count++)
-    i_ehdrp->e_ident[count] = 0;
-
   if ((abfd->flags & DYNAMIC) != 0)
     i_ehdrp->e_type = ET_DYN;
   else if ((abfd->flags & EXEC_P) != 0)
@@ -4183,6 +4427,7 @@ copy_private_bfd_data (ibfd, obfd)
   bfd_vma                   maxpagesize;
   struct elf_segment_map *  phdr_adjust_seg = NULL;
   unsigned int              phdr_adjust_num = 0;
+  struct elf_backend_data * bed;
 
   if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
       || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
@@ -4191,6 +4436,7 @@ copy_private_bfd_data (ibfd, obfd)
   if (elf_tdata (ibfd)->phdr == NULL)
     return true;
 
+  bed = get_elf_backend_data (ibfd);
   iehdr = elf_elfheader (ibfd);
 
   map_first = NULL;
@@ -4218,6 +4464,13 @@ copy_private_bfd_data (ibfd, obfd)
      && (section->lma + section->_raw_size)            \
      <= SEGMENT_END (segment, base))
 
+  /* Returns true if the given section is contained within the
+     given segment.  Filepos addresses are compared in an elf
+     backend function. */
+#define IS_CONTAINED_BY_FILEPOS(sec, seg, bed)         \
+  (bed->is_contained_by_filepos                                \
+   && (*bed->is_contained_by_filepos) (sec, seg))
+
   /* Special case: corefile "NOTE" section containing regs, prpsinfo etc.  */
 #define IS_COREFILE_NOTE(p, s)                          \
            (p->p_type == PT_NOTE                       \
@@ -4246,15 +4499,17 @@ copy_private_bfd_data (ibfd, 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.  */
-#define INCLUDE_SECTION_IN_SEGMENT(section, segment)                   \
+#define INCLUDE_SECTION_IN_SEGMENT(section, segment, bed)              \
   (((((segment->p_paddr                                                        \
        ? IS_CONTAINED_BY_LMA (section, segment, segment->p_paddr)      \
        : IS_CONTAINED_BY_VMA (section, segment))                       \
       || IS_SOLARIS_PT_INTERP (segment, section))                      \
      && (section->flags & SEC_ALLOC) != 0)                             \
-    || IS_COREFILE_NOTE (segment, section))                            \
+    || IS_COREFILE_NOTE (segment, section)                             \
+    || (IS_CONTAINED_BY_FILEPOS (section, segment, bed)                        \
+        && (section->flags & SEC_ALLOC) == 0))                         \
    && section->output_section != NULL                                  \
-   && section->segment_mark == false)
+   && ! section->segment_mark)
 
   /* Returns true iff seg1 starts after the end of seg2.  */
 #define SEGMENT_AFTER_SEGMENT(seg1, seg2)              \
@@ -4352,7 +4607,7 @@ copy_private_bfd_data (ibfd, obfd)
       /* Compute how many sections might be placed into this segment.  */
       section_count = 0;
       for (section = ibfd->sections; section != NULL; section = section->next)
-       if (INCLUDE_SECTION_IN_SEGMENT (section, segment))
+       if (INCLUDE_SECTION_IN_SEGMENT (section, segment, bed))
          ++section_count;
 
       /* Allocate a segment map big enough to contain all of the
@@ -4395,11 +4650,12 @@ copy_private_bfd_data (ibfd, obfd)
        {
          /* Special segments, such as the PT_PHDR segment, may contain
             no sections, but ordinary, loadable segments should contain
-            something.  */
+            something.  They are allowed by the ELF spec however, so only
+            a warning is produced.  */
          if (segment->p_type == PT_LOAD)
-             _bfd_error_handler
-               (_("%s: warning: Empty loadable segment detected\n"),
-                bfd_archive_filename (ibfd));
+           (*_bfd_error_handler)
+             (_("%s: warning: Empty loadable segment detected, is this intentional ?\n"),
+              bfd_archive_filename (ibfd));
 
          map->count = 0;
          *pointer_to_map = map;
@@ -4436,7 +4692,9 @@ copy_private_bfd_data (ibfd, obfd)
         pointers that we are interested in.  As these sections get assigned
         to a segment, they are removed from this array.  */
 
-      amt = (bfd_size_type) section_count * sizeof (asection *);
+      /* Gcc 2.96 miscompiles this code on mips. Don't do casting here
+        to work around this long long bug.  */
+      amt = section_count * sizeof (asection *);
       sections = (asection **) bfd_malloc (amt);
       if (sections == NULL)
        return false;
@@ -4455,7 +4713,7 @@ copy_private_bfd_data (ibfd, obfd)
           section != NULL;
           section = section->next)
        {
-         if (INCLUDE_SECTION_IN_SEGMENT (section, segment))
+         if (INCLUDE_SECTION_IN_SEGMENT (section, segment, bed))
            {
              output_section = section->output_section;
 
@@ -4481,6 +4739,7 @@ copy_private_bfd_data (ibfd, obfd)
              /* Match up the physical address of the segment with the
                 LMA address of the output section.  */
              if (IS_CONTAINED_BY_LMA (output_section, segment, map->p_paddr)
+                 || IS_CONTAINED_BY_FILEPOS (section, segment, bed)
                  || IS_COREFILE_NOTE (segment, section))
                {
                  if (matching_lma == 0)
@@ -4550,7 +4809,7 @@ copy_private_bfd_data (ibfd, obfd)
        }
 
       /* Step Three: Loop over the sections again, this time assigning
-        those that fit to the current segment and remvoing them from the
+        those that fit to the current segment and removing them from the
         sections array; but making sure not to leave large gaps.  Once all
         possible sections have been assigned to the current segment it is
         added to the list of built segments and if sections still remain
@@ -4601,7 +4860,7 @@ copy_private_bfd_data (ibfd, obfd)
                         maxpagesize then we need to start a new segment.  */
                      if ((BFD_ALIGN (prev_sec->lma + prev_sec->_raw_size,
                                      maxpagesize)
-                         < BFD_ALIGN (output_section->lma, maxpagesize))
+                          < BFD_ALIGN (output_section->lma, maxpagesize))
                          || ((prev_sec->lma + prev_sec->_raw_size)
                              > output_section->lma))
                        {
@@ -4714,6 +4973,7 @@ copy_private_bfd_data (ibfd, obfd)
 #undef SEGMENT_END
 #undef IS_CONTAINED_BY_VMA
 #undef IS_CONTAINED_BY_LMA
+#undef IS_CONTAINED_BY_FILEPOS
 #undef IS_COREFILE_NOTE
 #undef IS_SOLARIS_PT_INTERP
 #undef INCLUDE_SECTION_IN_SEGMENT
@@ -4733,6 +4993,7 @@ _bfd_elf_copy_private_section_data (ibfd, isec, obfd, osec)
      asection *osec;
 {
   Elf_Internal_Shdr *ihdr, *ohdr;
+  const struct elf_backend_data *bed = get_elf_backend_data (ibfd);
 
   if (ibfd->xvec->flavour != bfd_target_elf_flavour
       || obfd->xvec->flavour != bfd_target_elf_flavour)
@@ -4742,24 +5003,31 @@ _bfd_elf_copy_private_section_data (ibfd, isec, obfd, osec)
      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)
-    {
-      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;
-       }
+     already been worked out.  The backend function provides a way to 
+     override the test conditions and code path for the call to 
+     copy_private_bfd_data.  */
+  if (bed->copy_private_bfd_data_p)
+    {
+      if ((*bed->copy_private_bfd_data_p) (ibfd, isec, obfd, osec))
+        if (! copy_private_bfd_data (ibfd, obfd))
+          return false;
+    } 
+  else 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;
@@ -4773,6 +5041,12 @@ _bfd_elf_copy_private_section_data (ibfd, isec, obfd, osec)
       || ihdr->sh_type == SHT_GNU_verdef)
     ohdr->sh_info = ihdr->sh_info;
 
+  /* Set things up for objcopy.  The output SHT_GROUP section will
+     have its elf_next_in_group pointing back to the input group
+     members.  */
+  elf_next_in_group (osec) = elf_next_in_group (isec);
+  elf_group_name (osec) = elf_group_name (isec);
+
   elf_section_data (osec)->use_rela_p
     = elf_section_data (isec)->use_rela_p;
 
@@ -4881,10 +5155,9 @@ swap_out_syms (abfd, sttp, relocatable_p)
   if (symtab_shndx_hdr->sh_name != 0)
     {
       amt = (bfd_size_type) (1 + symcount) * sizeof (Elf_External_Sym_Shndx);
-      outbound_shndx = bfd_alloc (abfd, amt);
+      outbound_shndx = bfd_zalloc (abfd, amt);
       if (outbound_shndx == NULL)
        return false;
-      memset (outbound_shndx, 0, (unsigned long) amt);
       symtab_shndx_hdr->contents = outbound_shndx;
       symtab_shndx_hdr->sh_type = SHT_SYMTAB_SHNDX;
       symtab_shndx_hdr->sh_size = amt;
@@ -5018,13 +5291,18 @@ swap_out_syms (abfd, sttp, relocatable_p)
          sym.st_shndx = shndx;
        }
 
-      if ((flags & BSF_FUNCTION) != 0)
+      if ((flags & BSF_THREAD_LOCAL) != 0)
+       type = STT_TLS;
+      else if ((flags & BSF_FUNCTION) != 0)
        type = STT_FUNC;
       else if ((flags & BSF_OBJECT) != 0)
        type = STT_OBJECT;
       else
        type = STT_NOTYPE;
 
+      if (syms[idx]->section->flags & SEC_THREAD_LOCAL)
+       type = STT_TLS;
+
       /* Processor-specific types */
       if (type_ptr != NULL
          && bed->elf_backend_get_symbol_type)
@@ -5101,7 +5379,9 @@ _bfd_elf_get_symtab_upper_bound (abfd)
   Elf_Internal_Shdr *hdr = &elf_tdata (abfd)->symtab_hdr;
 
   symcount = hdr->sh_size / get_elf_backend_data (abfd)->s->sizeof_sym;
-  symtab_size = (symcount - 1 + 1) * (sizeof (asymbol *));
+  symtab_size = (symcount + 1) * (sizeof (asymbol *));
+  if (symcount > 0)
+    symtab_size -= sizeof (asymbol *);
 
   return symtab_size;
 }
@@ -5121,7 +5401,9 @@ _bfd_elf_get_dynamic_symtab_upper_bound (abfd)
     }
 
   symcount = hdr->sh_size / get_elf_backend_data (abfd)->s->sizeof_sym;
-  symtab_size = (symcount - 1 + 1) * (sizeof (asymbol *));
+  symtab_size = (symcount + 1) * (sizeof (asymbol *));
+  if (symcount > 0)
+    symtab_size -= sizeof (asymbol *);
 
   return symtab_size;
 }
@@ -5686,8 +5968,8 @@ _bfd_elf_set_section_contents (abfd, section, location, offset, count)
   bfd_signed_vma pos;
 
   if (! abfd->output_has_begun
-      && ! _bfd_elf_compute_section_file_positions
-      (abfd, (struct bfd_link_info *) NULL))
+      && ! (_bfd_elf_compute_section_file_positions
+           (abfd, (struct bfd_link_info *) NULL)))
     return false;
 
   hdr = &elf_section_data (section)->this_hdr;
@@ -5910,15 +6192,17 @@ _bfd_elfcore_make_pseudosection (abfd, name, size, filepos)
 {
   char buf[100];
   char *threaded_name;
+  size_t len;
   asection *sect;
 
   /* Build the section name.  */
 
   sprintf (buf, "%s/%d", name, elfcore_make_pid (abfd));
-  threaded_name = bfd_alloc (abfd, (bfd_size_type) strlen (buf) + 1);
+  len = strlen (buf) + 1;
+  threaded_name = bfd_alloc (abfd, (bfd_size_type) len);
   if (threaded_name == NULL)
     return false;
-  strcpy (threaded_name, buf);
+  memcpy (threaded_name, buf, len);
 
   sect = bfd_make_section (abfd, threaded_name);
   if (sect == NULL)
@@ -6203,6 +6487,7 @@ elfcore_grok_lwpstatus (abfd, note)
   lwpstatus_t lwpstat;
   char buf[100];
   char *name;
+  size_t len;
   asection *sect;
 
   if (note->descsz != sizeof (lwpstat)
@@ -6220,10 +6505,11 @@ elfcore_grok_lwpstatus (abfd, note)
   /* Make a ".reg/999" section.  */
 
   sprintf (buf, ".reg/%d", elfcore_make_pid (abfd));
-  name = bfd_alloc (abfd, (bfd_size_type) strlen (buf) + 1);
+  len = strlen (buf) + 1;
+  name = bfd_alloc (abfd, (bfd_size_type) len);
   if (name == NULL)
     return false;
-  strcpy (name, buf);
+  memcpy (name, buf, len);
 
   sect = bfd_make_section (abfd, name);
   if (sect == NULL)
@@ -6249,10 +6535,11 @@ elfcore_grok_lwpstatus (abfd, note)
   /* Make a ".reg2/999" section */
 
   sprintf (buf, ".reg2/%d", elfcore_make_pid (abfd));
-  name = bfd_alloc (abfd, (bfd_size_type) strlen (buf) + 1);
+  len = strlen (buf) + 1;
+  name = bfd_alloc (abfd, (bfd_size_type) len);
   if (name == NULL)
     return false;
-  strcpy (name, buf);
+  memcpy (name, buf, len);
 
   sect = bfd_make_section (abfd, name);
   if (sect == NULL)
@@ -6284,6 +6571,7 @@ elfcore_grok_win32pstatus (abfd, note)
 {
   char buf[30];
   char *name;
+  size_t len;
   asection *sect;
   win32_pstatus_t pstatus;
 
@@ -6304,11 +6592,12 @@ elfcore_grok_win32pstatus (abfd, note)
       /* Make a ".reg/999" section.  */
       sprintf (buf, ".reg/%d", pstatus.data.thread_info.tid);
 
-      name = bfd_alloc (abfd, (bfd_size_type) strlen (buf) + 1);
+      len = strlen (buf) + 1;
+      name = bfd_alloc (abfd, (bfd_size_type) len);
       if (name == NULL)
        return false;
 
-      strcpy (name, buf);
+      memcpy (name, buf, len);
 
       sect = bfd_make_section (abfd, name);
       if (sect == NULL)
@@ -6330,11 +6619,12 @@ elfcore_grok_win32pstatus (abfd, note)
       /* Make a ".module/xxxxxxxx" section.  */
       sprintf (buf, ".module/%08x", pstatus.data.module_info.base_address);
 
-      name = bfd_alloc (abfd, (bfd_size_type) strlen (buf) + 1);
+      len = strlen (buf) + 1;
+      name = bfd_alloc (abfd, (bfd_size_type) len);
       if (name == NULL)
        return false;
 
-      strcpy (name, buf);
+      memcpy (name, buf, len);
 
       sect = bfd_make_section (abfd, name);
 
@@ -6425,7 +6715,7 @@ elfcore_netbsd_get_lwpid (note, lwpidp)
   cp = strchr (note->namedata, '@');
   if (cp != NULL)
     {
-      *lwpidp = atoi(cp);
+      *lwpidp = atoi(cp + 1);
       return true;
     }
   return false;
@@ -6536,16 +6826,30 @@ elfcore_write_note (abfd, buf, bufsiz, name, type, input, size)
      bfd  *abfd;
      char *buf;
      int  *bufsiz;
-     char *name;
+     const char *name;
      int  type;
-     void *input;
+     const PTR input;
      int  size;
 {
   Elf_External_Note *xnp;
-  int namesz = strlen (name);
-  int newspace = BFD_ALIGN (sizeof (Elf_External_Note) + size + namesz - 1, 4);
+  size_t namesz;
+  size_t pad;
+  size_t newspace;
   char *p, *dest;
 
+  namesz = 0;
+  pad = 0;
+  if (name != NULL)
+    {
+      struct elf_backend_data *bed;
+
+      namesz = strlen (name) + 1;
+      bed = get_elf_backend_data (abfd);
+      pad = -namesz & (bed->s->file_align - 1);
+    }
+
+  newspace = sizeof (Elf_External_Note) - 1 + namesz + pad + size;
+
   p = realloc (buf, *bufsiz + newspace);
   dest = p + *bufsiz;
   *bufsiz += newspace;
@@ -6553,8 +6857,18 @@ elfcore_write_note (abfd, buf, bufsiz, name, type, input, size)
   H_PUT_32 (abfd, namesz, xnp->namesz);
   H_PUT_32 (abfd, size, xnp->descsz);
   H_PUT_32 (abfd, type, xnp->type);
-  strcpy (xnp->name, name);
-  memcpy (xnp->name + BFD_ALIGN (namesz, 4), input, size);
+  dest = xnp->name;
+  if (name != NULL)
+    {
+      memcpy (dest, name, namesz);
+      dest += namesz;
+      while (pad != 0)
+       {
+         *dest++ = '\0';
+         --pad;
+       }
+    }
+  memcpy (dest, input, size);
   return p;
 }
 
@@ -6564,8 +6878,8 @@ elfcore_write_prpsinfo (abfd, buf, bufsiz, fname, psargs)
      bfd  *abfd;
      char *buf;
      int  *bufsiz;
-     char *fname; 
-     char *psargs;
+     const char *fname; 
+     const char *psargs;
 {
   int note_type;
   char *note_name = "CORE";
@@ -6594,7 +6908,7 @@ elfcore_write_prstatus (abfd, buf, bufsiz, pid, cursig, gregs)
      int *bufsiz;
      long pid;
      int cursig;
-     void *gregs;
+     const PTR gregs;
 {
   prstatus_t prstat;
   char *note_name = "CORE";
@@ -6616,7 +6930,7 @@ elfcore_write_lwpstatus (abfd, buf, bufsiz, pid, cursig, gregs)
      int *bufsiz;
      long pid;
      int cursig;
-     void *gregs;
+     const PTR gregs;
 {
   lwpstatus_t lwpstat;
   char *note_name = "CORE";
@@ -6648,7 +6962,7 @@ elfcore_write_pstatus (abfd, buf, bufsiz, pid, cursig, gregs)
      int *bufsiz;
      long pid;
      int cursig;
-     void *gregs;
+     const PTR gregs;
 {
   pstatus_t pstat;
   char *note_name = "CORE";
@@ -6666,7 +6980,7 @@ elfcore_write_prfpreg (abfd, buf, bufsiz, fpregs, size)
      bfd  *abfd;
      char *buf;
      int  *bufsiz;
-     void *fpregs;
+     const PTR fpregs;
      int size;
 {
   char *note_name = "CORE";
@@ -6679,7 +6993,7 @@ elfcore_write_prxfpreg (abfd, buf, bufsiz, xfpregs, size)
      bfd  *abfd;
      char *buf;
      int  *bufsiz;
-     void *xfpregs;
+     const PTR xfpregs;
      int size;
 {
   char *note_name = "LINUX";
This page took 0.038299 seconds and 4 git commands to generate.