Add support for parallel instructions.
[deliverable/binutils-gdb.git] / bfd / elf.c
index cdf1a31004a1f54f432ec6bbb38fd3f119b0727a..ab9d7575faac3cccd831bda364fb19d35a9c0d1e 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -305,6 +305,18 @@ bfd_elf_string_from_elf_section (abfd, shindex, strindex)
       && bfd_elf_get_str_section (abfd, shindex) == NULL)
     return NULL;
 
+  if (strindex >= hdr->sh_size)
+    {
+      (*_bfd_error_handler)
+       ("%s: invalid string offset %u >= %lu for section `%s'",
+        bfd_get_filename (abfd), strindex, (unsigned long) hdr->sh_size,
+        ((shindex == elf_elfheader(abfd)->e_shstrndx
+          && strindex == hdr->sh_name)
+         ? ".shstrtab"
+         : elf_string_from_elf_strtab (abfd, hdr->sh_name)));
+      return "";
+    }
+
   return ((char *) hdr->contents) + strindex;
 }
 
@@ -701,9 +713,10 @@ _bfd_elf_print_private_bfd_data (abfd, farg)
 }
 
 /* Display ELF-specific fields of a symbol.  */
+
 void
-bfd_elf_print_symbol (ignore_abfd, filep, symbol, how)
-     bfd *ignore_abfd;
+bfd_elf_print_symbol (abfd, filep, symbol, how)
+     bfd *abfd;
      PTR filep;
      asymbol *symbol;
      bfd_print_symbol_type how;
@@ -733,11 +746,64 @@ bfd_elf_print_symbol (ignore_abfd, filep, symbol, how)
                     (bfd_is_com_section (symbol->section)
                      ? ((elf_symbol_type *) symbol)->internal_elf_sym.st_value
                      : ((elf_symbol_type *) symbol)->internal_elf_sym.st_size));
+
+       /* If we have version information, print it.  */
+       if (elf_tdata (abfd)->dynversym_section != 0
+           && (elf_tdata (abfd)->dynverdef_section != 0
+               || elf_tdata (abfd)->dynverref_section != 0))
+         {
+           unsigned int vernum;
+           const char *version_string;
+
+           vernum = ((elf_symbol_type *) symbol)->version & VERSYM_VERSION;
+
+           if (vernum == 0)
+             version_string = "";
+           else if (vernum == 1)
+             version_string = "Base";
+           else if (vernum <= elf_tdata (abfd)->cverdefs)
+             version_string =
+               elf_tdata (abfd)->verdef[vernum - 1].vd_nodename;
+           else
+             {
+               Elf_Internal_Verneed *t;
+
+               version_string = "";
+               for (t = elf_tdata (abfd)->verref;
+                    t != NULL;
+                    t = t->vn_nextref)
+                 {
+                   Elf_Internal_Vernaux *a;
+
+                   for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
+                     {
+                       if (a->vna_other == vernum)
+                         {
+                           version_string = a->vna_nodename;
+                           break;
+                         }
+                     }
+                 }
+             }
+
+           if ((((elf_symbol_type *) symbol)->version & VERSYM_HIDDEN) == 0)
+             fprintf (file, "  %-11s", version_string);
+           else
+             {
+               int i;
+
+               fprintf (file, " (%s)", version_string);
+               for (i = 10 - strlen (version_string); i > 0; --i)
+                 putc (' ', file);
+             }
+         }
+
        /* If the st_other field is not zero, print it.  */
        if (((elf_symbol_type *) symbol)->internal_elf_sym.st_other != 0)
          fprintf (file, " 0x%02x",
                   ((unsigned int)
                    ((elf_symbol_type *) symbol)->internal_elf_sym.st_other));
+
        fprintf (file, " %s", symbol->name);
       }
       break;
@@ -1098,16 +1164,19 @@ bfd_section_from_shdr (abfd, shindex)
     case SHT_GNU_verdef:
       elf_dynverdef (abfd) = shindex;
       elf_tdata (abfd)->dynverdef_hdr = *hdr;
+      return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
       break;
 
     case SHT_GNU_versym:
       elf_dynversym (abfd) = shindex;
       elf_tdata (abfd)->dynversym_hdr = *hdr;
+      return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
       break;
 
     case SHT_GNU_verneed:
       elf_dynverref (abfd) = shindex;
       elf_tdata (abfd)->dynverref_hdr = *hdr;
+      return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
       break;
 
     case SHT_SHLIB:
@@ -1338,13 +1407,27 @@ elf_fake_sections (abfd, asect, failedptrarg)
     {
       this_hdr->sh_type = SHT_GNU_verdef;
       this_hdr->sh_entsize = 0;
-      this_hdr->sh_info = elf_tdata (abfd)->cverdefs;
+      /* objcopy or strip will copy over sh_info, but may not set
+         cverdefs.  The linker will set cverdefs, but sh_info will be
+         zero.  */
+      if (this_hdr->sh_info == 0)
+       this_hdr->sh_info = elf_tdata (abfd)->cverdefs;
+      else
+       BFD_ASSERT (elf_tdata (abfd)->cverdefs == 0
+                   || this_hdr->sh_info == elf_tdata (abfd)->cverdefs);
     }
   else if (strcmp (asect->name, ".gnu.version_r") == 0)
     {
       this_hdr->sh_type = SHT_GNU_verneed;
       this_hdr->sh_entsize = 0;
-      this_hdr->sh_info = elf_tdata (abfd)->cverrefs;
+      /* objcopy or strip will copy over sh_info, but may not set
+         cverrefs.  The linker will set cverrefs, but sh_info will be
+         zero.  */
+      if (this_hdr->sh_info == 0)
+       this_hdr->sh_info = elf_tdata (abfd)->cverrefs;
+      else
+       BFD_ASSERT (elf_tdata (abfd)->cverrefs == 0
+                   || this_hdr->sh_info == elf_tdata (abfd)->cverrefs);
     }
   else if ((asect->flags & SEC_ALLOC) != 0
           && (asect->flags & SEC_LOAD) != 0)
@@ -2035,19 +2118,12 @@ map_sections_to_segments (abfd)
          new_segment = true;
        }
       else if (BFD_ALIGN (last_hdr->lma + last_hdr->_raw_size, maxpagesize)
-              < hdr->lma)
+              < 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 ((abfd->flags & D_PAGED) == 0)
-       {
-         /* If the file is not demand paged, which means that we
-             don't require the sections to be correctly aligned in the
-             file, then there is no other reason for a new segment.  */
-         new_segment = false;
-       }
       else if ((last_hdr->flags & SEC_LOAD) == 0
               && (hdr->flags & SEC_LOAD) != 0)
        {
@@ -2055,6 +2131,13 @@ map_sections_to_segments (abfd)
              nonloadable section in the same segment.  */
          new_segment = true;
        }
+      else if ((abfd->flags & D_PAGED) == 0)
+       {
+         /* If the file is not demand paged, which means that we
+             don't require the sections to be correctly aligned in the
+             file, then there is no other reason for a new segment.  */
+         new_segment = false;
+       }
       else if (! writable
               && (hdr->flags & SEC_READONLY) == 0
               && (BFD_ALIGN (last_hdr->lma + last_hdr->_raw_size, maxpagesize)
@@ -2348,6 +2431,15 @@ assign_file_positions_for_segments (abfd)
          if (m->count > 0)
            {
              BFD_ASSERT (p->p_type == PT_LOAD);
+
+             if (p->p_vaddr < off)
+               {
+                 _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;
+               }
+             
              p->p_vaddr -= off;
              if (! m->p_paddr_valid)
                p->p_paddr -= off;
@@ -2420,29 +2512,40 @@ assign_file_positions_for_segments (abfd)
            {
              bfd_vma adjust;
 
-             /* The section VMA must equal the file position modulo
-                 the page size.  */
-             if ((flags & SEC_ALLOC) != 0)
+             if ((flags & SEC_LOAD) != 0)
+               adjust = sec->lma - (p->p_paddr + p->p_memsz);
+             else if ((flags & SEC_ALLOC) != 0)
                {
+                 /* The section VMA must equal the file position
+                    modulo the page size.  FIXME: I'm not sure if
+                    this adjustment is really necessary.  We used to
+                    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;
                  else
                    adjust = (sec->vma - voff) % align;
-                 if (adjust != 0)
-                   {
-                     if (i == 0)
-                       abort ();
-                     p->p_memsz += adjust;
-                     off += adjust;
-                     voff += adjust;
-                     if ((flags & SEC_LOAD) != 0)
-                       p->p_filesz += adjust;
-                   }
+               }
+
+             if (adjust != 0)
+               {
+                 if (i == 0)
+                   abort ();
+                 p->p_memsz += adjust;
+                 off += adjust;
+                 voff += adjust;
+                 if ((flags & SEC_LOAD) != 0)
+                   p->p_filesz += adjust;
                }
 
              sec->filepos = off;
 
-             if ((flags & SEC_LOAD) != 0)
+             /* We check SEC_HAS_CONTENTS here because if NOLOAD is
+                 used in a linker script we may have a section with
+                 SEC_LOAD clear but which is supposed to have
+                 contents.  */
+             if ((flags & SEC_LOAD) != 0
+                 || (flags & SEC_HAS_CONTENTS) != 0)
                off += sec->_raw_size;
              if ((flags & SEC_ALLOC) != 0)
                voff += sec->_raw_size;
@@ -2787,27 +2890,30 @@ prep_headers (abfd)
       i_ehdrp->e_machine = EM_CYGNUS_D30V;
       break;
 /* end-sanitize-d30v */
-/* start-sanitize-v850 */
     case bfd_arch_v850:
-      i_ehdrp->e_machine = EM_CYGNUS_V850;
+      switch (bfd_get_mach (abfd))
+       {
+       default:
+       case 0:               i_ehdrp->e_machine = EM_CYGNUS_V850; break;
+       }
       break;
-/* end-sanitize-v850 */
-/* start-sanitize-arc */
-    case bfd_arch_arc:
+   case bfd_arch_arc:
       i_ehdrp->e_machine = EM_CYGNUS_ARC;
       break;
-/* end-sanitize-arc */
-/* start-sanitize-m32r */
     case bfd_arch_m32r:
       i_ehdrp->e_machine = EM_CYGNUS_M32R;
       break;
-/* end-sanitize-m32r */
     case bfd_arch_mn10200:
       i_ehdrp->e_machine = EM_CYGNUS_MN10200;
       break;
     case bfd_arch_mn10300:
       i_ehdrp->e_machine = EM_CYGNUS_MN10300;
       break;
+/* start-sanitize-sky */
+    case bfd_arch_txvu:
+      i_ehdrp->e_machine = EM_CYGNUS_TXVU;
+      break;
+/* end-sanitize-sky */
       /* also note that EM_M32, AT&T WE32100 is unknown to bfd */
     default:
       i_ehdrp->e_machine = EM_NONE;
@@ -3093,7 +3199,7 @@ copy_private_bfd_data (ibfd, obfd)
       m = ((struct elf_segment_map *)
           bfd_alloc (obfd,
                      (sizeof (struct elf_segment_map)
-                      + (csecs - 1) * sizeof (asection *))));
+                      + ((size_t) csecs - 1) * sizeof (asection *))));
       if (m == NULL)
        return false;
 
@@ -3187,7 +3293,9 @@ _bfd_elf_copy_private_section_data (ibfd, isec, obfd, osec)
   ohdr->sh_entsize = ihdr->sh_entsize;
 
   if (ihdr->sh_type == SHT_SYMTAB
-      || ihdr->sh_type == SHT_DYNSYM)
+      || ihdr->sh_type == SHT_DYNSYM
+      || ihdr->sh_type == SHT_GNU_verneed
+      || ihdr->sh_type == SHT_GNU_verdef)
     ohdr->sh_info = ihdr->sh_info;
 
   return true;
@@ -3831,17 +3939,34 @@ _bfd_elf_get_symbol_info (ignore_abfd, symbol, ret)
   bfd_symbol_info (symbol, ret);
 }
 
-/* Return whether a symbol name implies a local symbol.  In ELF, local
-   symbols generally start with ``.L''.  Most targets use this
-   function for the is_local_label_name entry point, but some override
-   it.  */
+/* Return whether a symbol name implies a local symbol.  Most targets
+   use this function for the is_local_label_name entry point, but some
+   override it.  */
 
 boolean
 _bfd_elf_is_local_label_name (abfd, name)
      bfd *abfd;
      const char *name;
 {
-  return name[0] == '.' && name[1] == 'L';
+  /* Normal local symbols start with ``.L''.  */
+  if (name[0] == '.' && name[1] == 'L')
+    return true;
+
+  /* At least some SVR4 compilers (e.g., UnixWare 2.1 cc) generate
+     DWARF debugging symbols starting with ``..''.  */
+  if (name[0] == '.' && name[1] == '.')
+    return true;
+
+  /* gcc will sometimes generate symbols beginning with ``_.L_'' when
+     emitting DWARF debugging output.  I suspect this is actually a
+     small bug in gcc (it calls ASM_OUTPUT_LABEL when it should call
+     ASM_GENERATE_INTERNAL_LABEL, and this causes the leading
+     underscore to be emitted on some ELF targets).  For ease of use,
+     we treat such symbols as local.  */
+  if (name[0] == '_' && name[1] == '.' && name[2] == 'L' && name[3] == '_')
+    return true;
+
+  return false;
 }
 
 alent *
@@ -3894,6 +4019,11 @@ _bfd_elf_find_nearest_line (abfd,
   bfd_vma low_func;
   asymbol **p;
 
+  if (_bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
+                                    filename_ptr, functionname_ptr, 
+                                    line_ptr))
+    return true;
+
   if (! _bfd_stab_section_find_nearest_line (abfd, symbols, section, offset,
                                             &found, filename_ptr,
                                             functionname_ptr, line_ptr,
This page took 0.027495 seconds and 4 git commands to generate.