PR binutils/15106
[deliverable/binutils-gdb.git] / bfd / elf.c
index 9c9ba754022f8a31f2992d57a279aee2e73de060..380f6eff2a696f8e0b628efb53c3740e97c4a4d8 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -1,7 +1,8 @@
 /* ELF executable support for BFD.
 
    Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
-   2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
+   2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
+   2013
    Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -44,6 +45,7 @@ SECTION
 #include "elf-bfd.h"
 #include "libiberty.h"
 #include "safe-ctype.h"
+#include "elf-linux-psinfo.h"
 
 #ifdef CORE_HEADER
 #include CORE_HEADER
@@ -545,9 +547,9 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect)
       shnum = elf_numsections (abfd);
       num_group = 0;
 
-#define IS_VALID_GROUP_SECTION_HEADER(shdr)            \
+#define IS_VALID_GROUP_SECTION_HEADER(shdr, minsize)   \
        (   (shdr)->sh_type == SHT_GROUP                \
-        && (shdr)->sh_size >= (2 * GRP_ENTRY_SIZE)     \
+        && (shdr)->sh_size >= minsize                  \
         && (shdr)->sh_entsize == GRP_ENTRY_SIZE        \
         && ((shdr)->sh_size % GRP_ENTRY_SIZE) == 0)
 
@@ -555,7 +557,7 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect)
        {
          Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[i];
 
-         if (IS_VALID_GROUP_SECTION_HEADER (shdr))
+         if (IS_VALID_GROUP_SECTION_HEADER (shdr, 2 * GRP_ENTRY_SIZE))
            num_group += 1;
        }
 
@@ -581,7 +583,7 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect)
            {
              Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[i];
 
-             if (IS_VALID_GROUP_SECTION_HEADER (shdr))
+             if (IS_VALID_GROUP_SECTION_HEADER (shdr, 2 * GRP_ENTRY_SIZE))
                {
                  unsigned char *src;
                  Elf_Internal_Group *dest;
@@ -880,45 +882,25 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
     {
       /* The debugging sections appear to be recognized only by name,
         not any sort of flag.  Their SEC_ALLOC bits are cleared.  */
-      static const struct
-       {
-         const char *name;
-         int len;
-       } debug_sections [] =
-       {
-         { STRING_COMMA_LEN ("debug") },       /* 'd' */
-         { NULL,                0  },  /* 'e' */
-         { NULL,                0  },  /* 'f' */
-         { STRING_COMMA_LEN ("gnu.linkonce.wi.") },    /* 'g' */
-         { NULL,                0  },  /* 'h' */
-         { NULL,                0  },  /* 'i' */
-         { NULL,                0  },  /* 'j' */
-         { NULL,                0  },  /* 'k' */
-         { STRING_COMMA_LEN ("line") },        /* 'l' */
-         { NULL,                0  },  /* 'm' */
-         { NULL,                0  },  /* 'n' */
-         { NULL,                0  },  /* 'o' */
-         { NULL,                0  },  /* 'p' */
-         { NULL,                0  },  /* 'q' */
-         { NULL,                0  },  /* 'r' */
-         { STRING_COMMA_LEN ("stab") },        /* 's' */
-         { NULL,                0  },  /* 't' */
-         { NULL,                0  },  /* 'u' */
-         { NULL,                0  },  /* 'v' */
-         { NULL,                0  },  /* 'w' */
-         { NULL,                0  },  /* 'x' */
-         { NULL,                0  },  /* 'y' */
-         { STRING_COMMA_LEN ("zdebug") }       /* 'z' */
-       };
-
       if (name [0] == '.')
        {
-         int i = name [1] - 'd';
-         if (i >= 0
-             && i < (int) ARRAY_SIZE (debug_sections)
-             && debug_sections [i].name != NULL
-             && strncmp (&name [1], debug_sections [i].name,
-                         debug_sections [i].len) == 0)
+         const char *p;
+         int n;
+         if (name[1] == 'd')
+           p = ".debug", n = 6;
+         else if (name[1] == 'g' && name[2] == 'n')
+           p = ".gnu.linkonce.wi.", n = 17;
+         else if (name[1] == 'g' && name[2] == 'd')
+           p = ".gdb_index", n = 11; /* yes we really do mean 11.  */
+         else if (name[1] == 'l')
+           p = ".line", n = 5;
+         else if (name[1] == 's')
+           p = ".stab", n = 5;
+         else if (name[1] == 'z')
+           p = ".zdebug", n = 7;
+         else
+           p = NULL, n = 0;
+         if (p != NULL && strncmp (name, p, n) == 0)
            flags |= SEC_DEBUGGING;
        }
     }
@@ -1025,7 +1007,7 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
       else
        {
          /* Normal section.  Check if we should compress.  */
-         if ((abfd->flags & BFD_COMPRESS))
+         if ((abfd->flags & BFD_COMPRESS) && newsect->size != 0)
            action = compress;
        }
 
@@ -1038,7 +1020,7 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
          if (!bfd_init_section_compress_status (abfd, newsect))
            {
              (*_bfd_error_handler)
-               (_("%B: unable to initialize commpress status for section %s"),
+               (_("%B: unable to initialize compress status for section %s"),
                 abfd, name);
              return FALSE;
            }
@@ -1058,7 +1040,7 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
          if (!bfd_init_section_decompress_status (abfd, newsect))
            {
              (*_bfd_error_handler)
-               (_("%B: unable to initialize decommpress status for section %s"),
+               (_("%B: unable to initialize decompress status for section %s"),
                 abfd, name);
              return FALSE;
            }
@@ -1646,7 +1628,15 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
       if (hdr->sh_entsize != bed->s->sizeof_sym)
        return FALSE;
       if (hdr->sh_info * hdr->sh_entsize > hdr->sh_size)
-       return FALSE;
+       {
+         if (hdr->sh_size != 0)
+           return FALSE;
+         /* Some assemblers erroneously set sh_info to one with a
+            zero sh_size.  ld sees this as a global symbol count
+            of (unsigned) -1.  Fix it here.  */
+         hdr->sh_info = 0;
+         return TRUE;
+       }
       BFD_ASSERT (elf_onesymtab (abfd) == 0);
       elf_onesymtab (abfd) = shindex;
       elf_tdata (abfd)->symtab_hdr = *hdr;
@@ -1699,6 +1689,16 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
 
       if (hdr->sh_entsize != bed->s->sizeof_sym)
        return FALSE;
+      if (hdr->sh_info * hdr->sh_entsize > hdr->sh_size)
+       {
+         if (hdr->sh_size != 0)
+           return FALSE;
+         /* Some linkers erroneously set sh_info to one with a
+            zero sh_size.  ld sees this as a global symbol count
+            of (unsigned) -1.  Fix it here.  */
+         hdr->sh_info = 0;
+         return TRUE;
+       }
       BFD_ASSERT (elf_dynsymtab (abfd) == 0);
       elf_dynsymtab (abfd) = shindex;
       elf_tdata (abfd)->dynsymtab_hdr = *hdr;
@@ -1911,7 +1911,7 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
       return TRUE;
 
     case SHT_GROUP:
-      if (! IS_VALID_GROUP_SECTION_HEADER (hdr))
+      if (! IS_VALID_GROUP_SECTION_HEADER (hdr, GRP_ENTRY_SIZE))
        return FALSE;
       if (!_bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
        return FALSE;
@@ -2063,6 +2063,9 @@ static const struct bfd_elf_special_section special_sections_d[] =
 {
   { STRING_COMMA_LEN (".data"),         -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
   { STRING_COMMA_LEN (".data1"),         0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
+  /* There are more DWARF sections than these, but they needn't be added here
+     unless you have to cope with broken compilers that don't emit section
+     attributes or you want to help the user writing assembler.  */
   { STRING_COMMA_LEN (".debug"),         0, SHT_PROGBITS, 0 },
   { STRING_COMMA_LEN (".debug_line"),    0, SHT_PROGBITS, 0 },
   { STRING_COMMA_LEN (".debug_info"),    0, SHT_PROGBITS, 0 },
@@ -2527,7 +2530,7 @@ _bfd_elf_init_reloc_shdr (bfd *abfd,
   rel_hdr = bfd_zalloc (abfd, amt);
   reldata->hdr = rel_hdr;
 
-  amt = sizeof ".rela" + strlen (asect->name);      
+  amt = sizeof ".rela" + strlen (asect->name);
   name = (char *) bfd_alloc (abfd, amt);
   if (name == NULL)
     return FALSE;
@@ -2996,6 +2999,13 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
       _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->strtab_hdr.sh_name);
     }
 
+  if (section_number >= SHN_LORESERVE)
+    {
+      _bfd_error_handler (_("%B: too many sections: %u"),
+                         abfd, section_number);
+      return FALSE;
+    }
+
   _bfd_elf_strtab_finalize (elf_shstrtab (abfd));
   t->shstrtab_hdr.sh_size = _bfd_elf_strtab_size (elf_shstrtab (abfd));
 
@@ -3071,7 +3081,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
              if (link_info != NULL)
                {
                  /* Check discarded linkonce section.  */
-                 if (elf_discarded_section (s))
+                 if (discarded_section (s))
                    {
                      asection *kept;
                      (*_bfd_error_handler)
@@ -3225,9 +3235,6 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
   return TRUE;
 }
 
-/* Map symbol from it's internal number to the external number, moving
-   all local symbols to be at the head of the list.  */
-
 static bfd_boolean
 sym_is_global (bfd *abfd, asymbol *sym)
 {
@@ -3242,17 +3249,29 @@ sym_is_global (bfd *abfd, asymbol *sym)
 }
 
 /* Don't output section symbols for sections that are not going to be
-   output.  */
+   output, that are duplicates or there is no BFD section.  */
 
 static bfd_boolean
 ignore_section_sym (bfd *abfd, asymbol *sym)
 {
-  return ((sym->flags & BSF_SECTION_SYM) != 0
-         && !(sym->section->owner == abfd
+  elf_symbol_type *type_ptr;
+
+  if ((sym->flags & BSF_SECTION_SYM) == 0)
+    return FALSE;
+
+  type_ptr = elf_symbol_from (abfd, sym);
+  return ((type_ptr != NULL
+          && type_ptr->internal_elf_sym.st_shndx != 0
+          && bfd_is_abs_section (sym->section))
+         || !(sym->section->owner == abfd
               || (sym->section->output_section->owner == abfd
-                  && sym->section->output_offset == 0)));
+                  && sym->section->output_offset == 0)
+              || bfd_is_abs_section (sym->section)));
 }
 
+/* Map symbol from it's internal number to the external number, moving
+   all local symbols to be at the head of the list.  */
+
 static bfd_boolean
 elf_map_symbols (bfd *abfd)
 {
@@ -3294,7 +3313,8 @@ elf_map_symbols (bfd *abfd)
 
       if ((sym->flags & BSF_SECTION_SYM) != 0
          && sym->value == 0
-         && !ignore_section_sym (abfd, sym))
+         && !ignore_section_sym (abfd, sym)
+         && !bfd_is_abs_section (sym->section))
        {
          asection *sec = sym->section;
 
@@ -3308,12 +3328,10 @@ elf_map_symbols (bfd *abfd)
   /* Classify all of the symbols.  */
   for (idx = 0; idx < symcount; idx++)
     {
-      if (ignore_section_sym (abfd, syms[idx]))
-       continue;
-      if (!sym_is_global (abfd, syms[idx]))
-       num_locals++;
-      else
+      if (sym_is_global (abfd, syms[idx]))
        num_globals++;
+      else if (!ignore_section_sym (abfd, syms[idx]))
+       num_locals++;
     }
 
   /* We will be adding a section symbol for each normal BFD section.  Most
@@ -3343,12 +3361,12 @@ elf_map_symbols (bfd *abfd)
       asymbol *sym = syms[idx];
       unsigned int i;
 
-      if (ignore_section_sym (abfd, sym))
-       continue;
-      if (!sym_is_global (abfd, sym))
+      if (sym_is_global (abfd, sym))
+       i = num_locals + num_globals2++;
+      else if (!ignore_section_sym (abfd, sym))
        i = num_locals2++;
       else
-       i = num_locals + num_globals2++;
+       continue;
       new_syms[i] = sym;
       sym->udata.i = i + 1;
     }
@@ -3744,6 +3762,10 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
   bfd_boolean no_user_phdrs;
 
   no_user_phdrs = elf_tdata (abfd)->segment_map == NULL;
+
+  if (info != NULL)
+    info->user_phdrs = !no_user_phdrs;
+
   if (no_user_phdrs && bfd_count_sections (abfd) != 0)
     {
       asection *s;
@@ -3854,6 +3876,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
 
          if (phdr_size == (bfd_size_type) -1)
            phdr_size = get_program_header_size (abfd, info);
+         phdr_size += bed->s->sizeof_ehdr;
          if ((abfd->flags & D_PAGED) == 0
              || (sections[0]->lma & addr_mask) < phdr_size
              || ((sections[0]->lma & addr_mask) % maxpagesize
@@ -4120,7 +4143,14 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
          m->next = NULL;
          m->p_type = PT_GNU_STACK;
          m->p_flags = elf_tdata (abfd)->stack_flags;
+         m->p_align = bed->stack_align;
          m->p_flags_valid = 1;
+         m->p_align_valid = m->p_align != 0;
+         if (info->stacksize > 0)
+           {
+             m->p_size = info->stacksize;
+             m->p_size_valid = 1;
+           }
 
          *pm = m;
          pm = &m->next;
@@ -4130,18 +4160,25 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
        {
          for (m = mfirst; m != NULL; m = m->next)
            {
-             if (m->p_type == PT_LOAD)
+             if (m->p_type == PT_LOAD
+                 && m->count != 0
+                 && m->sections[0]->vma >= info->relro_start
+                 && m->sections[0]->vma < info->relro_end)
                {
-                 asection *last = m->sections[m->count - 1];
-                 bfd_vma vaddr = m->sections[0]->vma;
-                 bfd_vma filesz = last->vma - vaddr + last->size;
+                 i = m->count;
+                 while (--i != (unsigned) -1)
+                   if ((m->sections[i]->flags & (SEC_LOAD | SEC_HAS_CONTENTS))
+                       == (SEC_LOAD | SEC_HAS_CONTENTS))
+                     break;
+
+                 if (i == (unsigned) -1)
+                   continue;
 
-                 if (vaddr < info->relro_end
-                     && vaddr >= info->relro_start
-                     && (vaddr + filesz) >= info->relro_end)
+                 if (m->sections[i]->vma + m->sections[i]->size
+                     >= info->relro_end)
                    break;
                }
-             }
+           }
 
          /* Make a PT_GNU_RELRO segment only when it isn't empty.  */
          if (m != NULL)
@@ -4351,7 +4388,7 @@ assign_file_positions_for_load_sections (bfd *abfd,
       elf_elfheader (abfd)->e_phoff = 0;
       elf_elfheader (abfd)->e_phentsize = 0;
     }
-  
+
   elf_elfheader (abfd)->e_phnum = alloc;
 
   if (elf_tdata (abfd)->program_header_size == (bfd_size_type) -1)
@@ -4546,8 +4583,6 @@ assign_file_positions_for_load_sections (bfd *abfd,
          p->p_memsz = bed->s->sizeof_ehdr;
          if (m->count > 0)
            {
-             BFD_ASSERT (p->p_type == PT_LOAD);
-
              if (p->p_vaddr < (bfd_vma) off)
                {
                  (*_bfd_error_handler)
@@ -4574,7 +4609,6 @@ assign_file_positions_for_load_sections (bfd *abfd,
 
              if (m->count > 0)
                {
-                 BFD_ASSERT (p->p_type == PT_LOAD);
                  p->p_vaddr -= off - p->p_offset;
                  if (!m->p_paddr_valid)
                    p->p_paddr -= off - p->p_offset;
@@ -4797,6 +4831,7 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
   Elf_Internal_Phdr *phdrs;
   Elf_Internal_Phdr *p;
   struct elf_segment_map *m;
+  struct elf_segment_map *hdrs_segment;
   bfd_vma filehdr_vaddr, filehdr_paddr;
   bfd_vma phdrs_vaddr, phdrs_paddr;
   file_ptr off;
@@ -4820,12 +4855,13 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
        BFD_ASSERT (hdr->sh_offset == hdr->bfd_section->filepos);
       else if ((hdr->sh_flags & SHF_ALLOC) != 0)
        {
-         (*_bfd_error_handler)
-           (_("%B: warning: allocated section `%s' not in segment"),
-            abfd,
-            (hdr->bfd_section == NULL
-             ? "*unknown*"
-             : hdr->bfd_section->name));
+         if (hdr->sh_size != 0)
+           (*_bfd_error_handler)
+             (_("%B: warning: allocated section `%s' not in segment"),
+              abfd,
+              (hdr->bfd_section == NULL
+               ? "*unknown*"
+               : hdr->bfd_section->name));
          /* We don't need to page align empty sections.  */
          if ((abfd->flags & D_PAGED) != 0 && hdr->sh_size != 0)
            off += vma_page_aligned_bias (hdr->sh_addr, off,
@@ -4853,6 +4889,7 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
   filehdr_paddr = 0;
   phdrs_vaddr = bed->maxpagesize + bed->s->sizeof_ehdr;
   phdrs_paddr = 0;
+  hdrs_segment = NULL;
   phdrs = elf_tdata (abfd)->phdr;
   for (m = elf_tdata (abfd)->segment_map, p = phdrs;
        m != NULL;
@@ -4873,12 +4910,59 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
          phdrs_paddr = p->p_paddr;
          if (m->includes_filehdr)
            {
+             hdrs_segment = m;
              phdrs_vaddr += bed->s->sizeof_ehdr;
              phdrs_paddr += bed->s->sizeof_ehdr;
            }
        }
     }
 
+  if (hdrs_segment != NULL && link_info != NULL)
+    {
+      /* There is a segment that contains both the file headers and the
+        program headers, so provide a symbol __ehdr_start pointing there.
+        A program can use this to examine itself robustly.  */
+
+      struct elf_link_hash_entry *hash
+       = elf_link_hash_lookup (elf_hash_table (link_info), "__ehdr_start",
+                               FALSE, FALSE, TRUE);
+      /* If the symbol was referenced and not defined, define it.  */
+      if (hash != NULL
+         && (hash->root.type == bfd_link_hash_new
+             || hash->root.type == bfd_link_hash_undefined
+             || hash->root.type == bfd_link_hash_undefweak
+             || hash->root.type == bfd_link_hash_common))
+       {
+         asection *s = NULL;
+         if (hdrs_segment->count != 0)
+           /* The segment contains sections, so use the first one.  */
+           s = hdrs_segment->sections[0];
+         else
+           /* Use the first (i.e. lowest-addressed) section in any segment.  */
+           for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
+             if (m->count != 0)
+               {
+                 s = m->sections[0];
+                 break;
+               }
+
+         if (s != NULL)
+           {
+             hash->root.u.def.value = filehdr_vaddr - s->vma;
+             hash->root.u.def.section = s;
+           }
+         else
+           {
+             hash->root.u.def.value = filehdr_vaddr;
+             hash->root.u.def.section = bfd_abs_section_ptr;
+           }
+
+         hash->root.type = bfd_link_hash_defined;
+         hash->def_regular = 1;
+         hash->non_elf = 0;
+       }
+    }
+
   for (m = elf_tdata (abfd)->segment_map, p = phdrs;
        m != NULL;
        m = m->next, p++)
@@ -4886,21 +4970,27 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
       if (p->p_type == PT_GNU_RELRO)
        {
          const Elf_Internal_Phdr *lp;
-
-         BFD_ASSERT (!m->includes_filehdr && !m->includes_phdrs);
+         struct elf_segment_map *lm;
 
          if (link_info != NULL)
            {
              /* During linking the range of the RELRO segment is passed
                 in link_info.  */
-             for (lp = phdrs; lp < phdrs + count; ++lp)
+             for (lm = elf_tdata (abfd)->segment_map, lp = phdrs;
+                  lm != NULL;
+                  lm = lm->next, lp++)
                {
                  if (lp->p_type == PT_LOAD
-                     && lp->p_vaddr >= link_info->relro_start
                      && lp->p_vaddr < link_info->relro_end
-                     && lp->p_vaddr + lp->p_filesz >= link_info->relro_end)
+                     && lp->p_vaddr + lp->p_filesz >= link_info->relro_end
+                     && lm->count != 0
+                     && lm->sections[0]->vma >= link_info->relro_start)
                    break;
                }
+
+             /* PR ld/14207.  If the RELRO segment doesn't fit in the
+                LOAD segment, it should be removed.  */
+             BFD_ASSERT (lm != NULL);
            }
          else
            {
@@ -4926,8 +5016,15 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
              else
                abort ();
              p->p_memsz = p->p_filesz;
-             p->p_align = 1;
-             p->p_flags = (lp->p_flags & ~PF_W);
+             /* Preserve the alignment and flags if they are valid. The
+                gold linker generates RW/4 for the PT_GNU_RELRO section.
+                It is better for objcopy/strip to honor these attributes
+                otherwise gdb will choke when using separate debug files.
+              */
+             if (!m->p_align_valid)
+               p->p_align = 1;
+             if (!m->p_flags_valid)
+               p->p_flags = (lp->p_flags & ~PF_W);
            }
          else
            {
@@ -4935,6 +5032,11 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
              p->p_type = PT_NULL;
            }
        }
+      else if (p->p_type == PT_GNU_STACK)
+       {
+         if (m->p_size_valid)
+           p->p_memsz = m->p_size;
+       }
       else if (m->count != 0)
        {
          if (p->p_type != PT_LOAD
@@ -5427,7 +5529,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
        1. It is within the address space of the segment -- we use the LMA
          if that is set for the segment and the VMA otherwise,
        2. It is an allocated section or a NOTE section in a PT_NOTE
-         segment.         
+         segment.
        3. There is an output section associated with it,
        4. The section has not already been allocated to a previous segment.
        5. PT_GNU_STACK segments do not include any sections.
@@ -5944,7 +6046,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
                 and carry on looping.  */
              amt = sizeof (struct elf_segment_map);
              amt += ((bfd_size_type) section_count - 1) * sizeof (asection *);
-             map = (struct elf_segment_map *) bfd_alloc (obfd, amt);
+             map = (struct elf_segment_map *) bfd_zalloc (obfd, amt);
              if (map == NULL)
                {
                  free (sections);
@@ -6079,12 +6181,15 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd)
       map->p_align_valid = 1;
       map->p_vaddr_offset = 0;
 
-      if (map->p_type == PT_GNU_RELRO)
+      if (map->p_type == PT_GNU_RELRO
+         || map->p_type == PT_GNU_STACK)
        {
          /* The PT_GNU_RELRO segment may contain the first a few
             bytes in the .got.plt section even if the whole .got.plt
             section isn't in the PT_GNU_RELRO segment.  We won't
-            change the size of the PT_GNU_RELRO segment.  */
+            change the size of the PT_GNU_RELRO segment.
+            Similarly, PT_GNU_STACK size is significant on uclinux
+            systems.    */
          map->p_size = segment->p_memsz;
          map->p_size_valid = 1;
        }
@@ -6147,7 +6252,7 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd)
       if (map->includes_filehdr && lowest_section != NULL)
        /* We need to keep the space used by the headers fixed.  */
        map->header_size = lowest_section->vma - segment->p_vaddr;
-      
+
       if (!map->includes_phdrs
          && !map->includes_filehdr
          && map->p_paddr_valid)
@@ -6254,6 +6359,26 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
     }
 
 rewrite:
+  if (ibfd->xvec == obfd->xvec)
+    {
+      /* When rewriting program header, set the output maxpagesize to
+        the maximum alignment of input PT_LOAD segments.  */
+      Elf_Internal_Phdr *segment;
+      unsigned int i;
+      unsigned int num_segments = elf_elfheader (ibfd)->e_phnum;
+      bfd_vma maxpagesize = 0;
+
+      for (i = 0, segment = elf_tdata (ibfd)->phdr;
+          i < num_segments;
+          i++, segment++)
+       if (segment->p_type == PT_LOAD
+           && maxpagesize < segment->p_align)
+         maxpagesize = segment->p_align;
+
+      if (maxpagesize != get_elf_backend_data (obfd)->maxpagesize)
+       bfd_emul_set_maxpagesize (bfd_get_target (obfd), maxpagesize);
+    }
+
   return rewrite_elf_program_header (ibfd, obfd);
 }
 
@@ -6668,6 +6793,7 @@ swap_out_syms (bfd *abfd,
                  shndx = elf_tdata (abfd)->symtab_shndx_section;
                  break;
                default:
+                 shndx = SHN_ABS;
                  break;
                }
            }
@@ -7260,7 +7386,7 @@ error_return_verdef:
       Elf_Internal_Verdef *iverdef;
       Elf_Internal_Verdaux *iverdaux;
 
-      iverdef = &elf_tdata (abfd)->verdef[freeidx - 1];;
+      iverdef = &elf_tdata (abfd)->verdef[freeidx - 1];
 
       iverdef->vd_version = VER_DEF_CURRENT;
       iverdef->vd_flags = 0;
@@ -7378,74 +7504,94 @@ elf_find_function (bfd *abfd,
                   const char **filename_ptr,
                   const char **functionname_ptr)
 {
-  const char *filename;
-  asymbol *func, *file;
-  bfd_vma low_func;
-  asymbol **p;
-  /* ??? Given multiple file symbols, it is impossible to reliably
-     choose the right file name for global symbols.  File symbols are
-     local symbols, and thus all file symbols must sort before any
-     global symbols.  The ELF spec may be interpreted to say that a
-     file symbol must sort before other local symbols, but currently
-     ld -r doesn't do this.  So, for ld -r output, it is possible to
-     make a better choice of file name for local symbols by ignoring
-     file symbols appearing after a given local symbol.  */
-  enum { nothing_seen, symbol_seen, file_after_symbol_seen } state;
-  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  struct elf_find_function_cache
+  {
+    asection *last_section;
+    asymbol *func;
+    const char *filename;
+    bfd_size_type func_size;
+  } *cache;
 
   if (symbols == NULL)
     return FALSE;
 
-  filename = NULL;
-  func = NULL;
-  file = NULL;
-  low_func = 0;
-  state = nothing_seen;
-
-  for (p = symbols; *p != NULL; p++)
+  cache = elf_tdata (abfd)->elf_find_function_cache;
+  if (cache == NULL)
     {
-      elf_symbol_type *q;
-      unsigned int type;
-      asection *code_sec;
-      bfd_vma code_off;
-
-      q = (elf_symbol_type *) *p;
+      cache = bfd_zalloc (abfd, sizeof (*cache));
+      elf_tdata (abfd)->elf_find_function_cache = cache;
+      if (cache == NULL)
+       return FALSE;
+    }
+  if (cache->last_section != section
+      || cache->func == NULL
+      || offset < cache->func->value
+      || offset >= cache->func->value + cache->func_size)
+    {
+      asymbol *file;
+      bfd_vma low_func;
+      asymbol **p;
+      /* ??? Given multiple file symbols, it is impossible to reliably
+        choose the right file name for global symbols.  File symbols are
+        local symbols, and thus all file symbols must sort before any
+        global symbols.  The ELF spec may be interpreted to say that a
+        file symbol must sort before other local symbols, but currently
+        ld -r doesn't do this.  So, for ld -r output, it is possible to
+        make a better choice of file name for local symbols by ignoring
+        file symbols appearing after a given local symbol.  */
+      enum { nothing_seen, symbol_seen, file_after_symbol_seen } state;
+      const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+      file = NULL;
+      low_func = 0;
+      state = nothing_seen;
+      cache->filename = NULL;
+      cache->func = NULL;
+      cache->func_size = 0;
+      cache->last_section = section;
+
+      for (p = symbols; *p != NULL; p++)
+       {
+         asymbol *sym = *p;
+         bfd_vma code_off;
+         bfd_size_type size;
+
+         if ((sym->flags & BSF_FILE) != 0)
+           {
+             file = sym;
+             if (state == symbol_seen)
+               state = file_after_symbol_seen;
+             continue;
+           }
 
-      type = ELF_ST_TYPE (q->internal_elf_sym.st_info);
-      switch (type)
-       {
-       case STT_FILE:
-         file = &q->symbol;
-         if (state == symbol_seen)
-           state = file_after_symbol_seen;
-         continue;
-       default:
-         if (bed->maybe_function_sym (q, &code_sec, &code_off)
-             && code_sec == section
-             && code_off >= low_func
-             && code_off <= offset)
+         size = bed->maybe_function_sym (sym, section, &code_off);
+         if (size != 0
+             && code_off <= offset
+             && (code_off > low_func
+                 || (code_off == low_func
+                     && size > cache->func_size)))
            {
-             func = (asymbol *) q;
+             cache->func = sym;
+             cache->func_size = size;
+             cache->filename = NULL;
              low_func = code_off;
-             filename = NULL;
              if (file != NULL
-                 && (ELF_ST_BIND (q->internal_elf_sym.st_info) == STB_LOCAL
+                 && ((sym->flags & BSF_LOCAL) != 0
                      || state != file_after_symbol_seen))
-               filename = bfd_asymbol_name (file);
+               cache->filename = bfd_asymbol_name (file);
            }
-         break;
+         if (state == nothing_seen)
+           state = symbol_seen;
        }
-      if (state == nothing_seen)
-       state = symbol_seen;
     }
 
-  if (func == NULL)
+  if (cache->func == NULL)
     return FALSE;
 
   if (filename_ptr)
-    *filename_ptr = filename;
+    *filename_ptr = cache->filename;
   if (functionname_ptr)
-    *functionname_ptr = bfd_asymbol_name (func);
+    *functionname_ptr = bfd_asymbol_name (cache->func);
 
   return TRUE;
 }
@@ -7461,6 +7607,23 @@ _bfd_elf_find_nearest_line (bfd *abfd,
                            const char **filename_ptr,
                            const char **functionname_ptr,
                            unsigned int *line_ptr)
+{
+  return _bfd_elf_find_nearest_line_discriminator (abfd, section, symbols,
+                                                   offset, filename_ptr,
+                                                   functionname_ptr,
+                                                   line_ptr,
+                                                   NULL);
+}
+
+bfd_boolean
+_bfd_elf_find_nearest_line_discriminator (bfd *abfd,
+                                          asection *section,
+                                          asymbol **symbols,
+                                          bfd_vma offset,
+                                          const char **filename_ptr,
+                                          const char **functionname_ptr,
+                                          unsigned int *line_ptr,
+                                          unsigned int *discriminator_ptr)
 {
   bfd_boolean found;
 
@@ -7479,7 +7642,7 @@ _bfd_elf_find_nearest_line (bfd *abfd,
   if (_bfd_dwarf2_find_nearest_line (abfd, dwarf_debug_sections,
                                      section, symbols, offset,
                                     filename_ptr, functionname_ptr,
-                                    line_ptr, 0,
+                                    line_ptr, discriminator_ptr, 0,
                                     &elf_tdata (abfd)->dwarf2_find_line_info))
     {
       if (!*functionname_ptr)
@@ -7514,9 +7677,20 @@ _bfd_elf_find_nearest_line (bfd *abfd,
 bfd_boolean
 _bfd_elf_find_line (bfd *abfd, asymbol **symbols, asymbol *symbol,
                    const char **filename_ptr, unsigned int *line_ptr)
+{
+  return _bfd_elf_find_line_discriminator (abfd, symbols, symbol,
+                                          filename_ptr, line_ptr,
+                                           NULL);
+}
+
+bfd_boolean
+_bfd_elf_find_line_discriminator (bfd *abfd, asymbol **symbols, asymbol *symbol,
+                                  const char **filename_ptr,
+                                  unsigned int *line_ptr,
+                                  unsigned int *discriminator_ptr)
 {
   return _bfd_dwarf2_find_line (abfd, symbols, symbol,
-                               filename_ptr, line_ptr, 0,
+                               filename_ptr, line_ptr, discriminator_ptr, 0,
                                &elf_tdata (abfd)->dwarf2_find_line_info);
 }
 
@@ -8001,6 +8175,24 @@ elfcore_grok_arm_vfp (bfd *abfd, Elf_Internal_Note *note)
   return elfcore_make_note_pseudosection (abfd, ".reg-arm-vfp", note);
 }
 
+static bfd_boolean
+elfcore_grok_aarch_tls (bfd *abfd, Elf_Internal_Note *note)
+{
+  return elfcore_make_note_pseudosection (abfd, ".reg-aarch-tls", note);
+}
+
+static bfd_boolean
+elfcore_grok_aarch_hw_break (bfd *abfd, Elf_Internal_Note *note)
+{
+  return elfcore_make_note_pseudosection (abfd, ".reg-aarch-hw-break", note);
+}
+
+static bfd_boolean
+elfcore_grok_aarch_hw_watch (bfd *abfd, Elf_Internal_Note *note)
+{
+  return elfcore_make_note_pseudosection (abfd, ".reg-aarch-hw-watch", note);
+}
+
 #if defined (HAVE_PRPSINFO_T)
 typedef prpsinfo_t   elfcore_psinfo_t;
 #if defined (HAVE_PRPSINFO32_T)                /* Sparc64 cross Sparc32 */
@@ -8441,6 +8633,27 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
       else
        return TRUE;
 
+    case NT_ARM_TLS:
+      if (note->namesz == 6
+         && strcmp (note->namedata, "LINUX") == 0)
+       return elfcore_grok_aarch_tls (abfd, note);
+      else
+       return TRUE;
+
+    case NT_ARM_HW_BREAK:
+      if (note->namesz == 6
+         && strcmp (note->namedata, "LINUX") == 0)
+       return elfcore_grok_aarch_hw_break (abfd, note);
+      else
+       return TRUE;
+
+    case NT_ARM_HW_WATCH:
+      if (note->namesz == 6
+         && strcmp (note->namedata, "LINUX") == 0)
+       return elfcore_grok_aarch_hw_watch (abfd, note);
+      else
+       return TRUE;
+
     case NT_PRPSINFO:
     case NT_PSINFO:
       if (bed->elf_backend_grok_psinfo)
@@ -8465,6 +8678,14 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
 
        return TRUE;
       }
+
+    case NT_FILE:
+      return elfcore_make_note_pseudosection (abfd, ".note.linuxcore.file",
+                                             note);
+
+    case NT_SIGINFO:
+      return elfcore_make_note_pseudosection (abfd, ".note.linuxcore.siginfo",
+                                             note);
     }
 }
 
@@ -8949,6 +9170,34 @@ elfcore_write_prpsinfo (bfd  *abfd,
   return NULL;
 }
 
+char *
+elfcore_write_linux_prpsinfo32
+  (bfd *abfd, char *buf, int *bufsiz,
+   const struct elf_internal_linux_prpsinfo *prpsinfo)
+{
+  struct elf_external_linux_prpsinfo32 data;
+
+  memset (&data, 0, sizeof (data));
+  LINUX_PRPSINFO32_SWAP_FIELDS (abfd, prpsinfo, data);
+
+  return elfcore_write_note (abfd, buf, bufsiz, "CORE", NT_PRPSINFO,
+                            &data, sizeof (data));
+}
+
+char *
+elfcore_write_linux_prpsinfo64
+  (bfd *abfd, char *buf, int *bufsiz,
+   const struct elf_internal_linux_prpsinfo *prpsinfo)
+{
+  struct elf_external_linux_prpsinfo64 data;
+
+  memset (&data, 0, sizeof (data));
+  LINUX_PRPSINFO64_SWAP_FIELDS (abfd, prpsinfo, data);
+
+  return elfcore_write_note (abfd, buf, bufsiz,
+                            "CORE", NT_PRPSINFO, &data, sizeof (data));
+}
+
 char *
 elfcore_write_prstatus (bfd *abfd,
                        char *buf,
@@ -9236,6 +9485,42 @@ elfcore_write_arm_vfp (bfd *abfd,
                             note_name, NT_ARM_VFP, arm_vfp, size);
 }
 
+char *
+elfcore_write_aarch_tls (bfd *abfd,
+                      char *buf,
+                      int *bufsiz,
+                      const void *aarch_tls,
+                      int size)
+{
+  char *note_name = "LINUX";
+  return elfcore_write_note (abfd, buf, bufsiz,
+                            note_name, NT_ARM_TLS, aarch_tls, size);
+}
+
+char *
+elfcore_write_aarch_hw_break (bfd *abfd,
+                           char *buf,
+                           int *bufsiz,
+                           const void *aarch_hw_break,
+                           int size)
+{
+  char *note_name = "LINUX";
+  return elfcore_write_note (abfd, buf, bufsiz,
+                            note_name, NT_ARM_HW_BREAK, aarch_hw_break, size);
+}
+
+char *
+elfcore_write_aarch_hw_watch (bfd *abfd,
+                           char *buf,
+                           int *bufsiz,
+                           const void *aarch_hw_watch,
+                           int size)
+{
+  char *note_name = "LINUX";
+  return elfcore_write_note (abfd, buf, bufsiz,
+                            note_name, NT_ARM_HW_WATCH, aarch_hw_watch, size);
+}
+
 char *
 elfcore_write_register_note (bfd *abfd,
                             char *buf,
@@ -9272,6 +9557,12 @@ elfcore_write_register_note (bfd *abfd,
     return elfcore_write_s390_system_call (abfd, buf, bufsiz, data, size);
   if (strcmp (section, ".reg-arm-vfp") == 0)
     return elfcore_write_arm_vfp (abfd, buf, bufsiz, data, size);
+  if (strcmp (section, ".reg-aarch-tls") == 0)
+    return elfcore_write_aarch_tls (abfd, buf, bufsiz, data, size);
+  if (strcmp (section, ".reg-aarch-hw-break") == 0)
+    return elfcore_write_aarch_hw_break (abfd, buf, bufsiz, data, size);
+  if (strcmp (section, ".reg-aarch-hw-watch") == 0)
+    return elfcore_write_aarch_hw_watch (abfd, buf, bufsiz, data, size);
   return NULL;
 }
 
@@ -9452,7 +9743,7 @@ _bfd_elf_rela_local_sym (bfd *abfd,
                + sym->st_value);
   if ((sec->flags & SEC_MERGE)
       && ELF_ST_TYPE (sym->st_info) == STT_SECTION
-      && sec->sec_info_type == ELF_INFO_TYPE_MERGE)
+      && sec->sec_info_type == SEC_INFO_TYPE_MERGE)
     {
       rel->r_addend =
        _bfd_merged_section_offset (abfd, psec,
@@ -9483,7 +9774,7 @@ _bfd_elf_rel_local_sym (bfd *abfd,
 {
   asection *sec = *psec;
 
-  if (sec->sec_info_type != ELF_INFO_TYPE_MERGE)
+  if (sec->sec_info_type != SEC_INFO_TYPE_MERGE)
     return sym->st_value + addend;
 
   return _bfd_merged_section_offset (abfd, psec,
@@ -9499,10 +9790,10 @@ _bfd_elf_section_offset (bfd *abfd,
 {
   switch (sec->sec_info_type)
     {
-    case ELF_INFO_TYPE_STABS:
+    case SEC_INFO_TYPE_STABS:
       return _bfd_stab_section_offset (sec, elf_section_data (sec)->sec_info,
                                       offset);
-    case ELF_INFO_TYPE_EH_FRAME:
+    case SEC_INFO_TYPE_EH_FRAME:
       return _bfd_elf_eh_frame_section_offset (abfd, info, sec, offset);
     default:
       if ((sec->flags & SEC_ELF_REVERSE_COPY) != 0)
@@ -9533,7 +9824,7 @@ bfd_elf_bfd_from_remote_memory
   (bfd *templ,
    bfd_vma ehdr_vma,
    bfd_vma *loadbasep,
-   int (*target_read_memory) (bfd_vma, bfd_byte *, int))
+   int (*target_read_memory) (bfd_vma, bfd_byte *, bfd_size_type))
 {
   return (*get_elf_backend_data (templ)->elf_backend_bfd_from_remote_memory)
     (templ, ehdr_vma, loadbasep, target_read_memory);
@@ -9638,7 +9929,7 @@ _bfd_elf_get_synthetic_symtab (bfd *abfd,
       if (p->addend != 0)
        {
          char buf[30], *a;
-         
+
          memcpy (names, "+0x", sizeof ("+0x") - 1);
          names += sizeof ("+0x") - 1;
          bfd_sprintf_vma (abfd, buf, p->addend);
@@ -9691,21 +9982,26 @@ _bfd_elf_is_function_type (unsigned int type)
          || type == STT_GNU_IFUNC);
 }
 
-/* Return TRUE iff the ELF symbol SYM might be a function.  Set *CODE_SEC
-   and *CODE_OFF to the function's entry point.  */
+/* If the ELF symbol SYM might be a function in SEC, return the
+   function size and set *CODE_OFF to the function's entry point,
+   otherwise return zero.  */
 
-bfd_boolean
-_bfd_elf_maybe_function_sym (const elf_symbol_type *sym,
-                            asection **code_sec, bfd_vma *code_off)
+bfd_size_type
+_bfd_elf_maybe_function_sym (const asymbol *sym, asection *sec,
+                            bfd_vma *code_off)
 {
-  unsigned int type = ELF_ST_TYPE (sym->internal_elf_sym.st_info);
-  if (type == STT_NOTYPE
-      || type == STT_FUNC
-      || type == STT_GNU_IFUNC)
-    {
-      *code_sec = sym->symbol.section;
-      *code_off = sym->symbol.value;
-      return TRUE;
-    }
-  return FALSE;
+  bfd_size_type size;
+
+  if ((sym->flags & (BSF_SECTION_SYM | BSF_FILE | BSF_OBJECT
+                    | BSF_THREAD_LOCAL | BSF_RELC | BSF_SRELC)) != 0
+      || sym->section != sec)
+    return 0;
+
+  *code_off = sym->value;
+  size = 0;
+  if (!(sym->flags & BSF_SYNTHETIC))
+    size = ((elf_symbol_type *) sym)->internal_elf_sym.st_size;
+  if (size == 0)
+    size = 1;
+  return size;
 }
This page took 0.036966 seconds and 4 git commands to generate.