* elf-bfd.h (enum elf_link_info_type): New.
[deliverable/binutils-gdb.git] / bfd / elf.c
index feffd7c85982c0712dde2195e4d9eea7e9a9810b..98d3cd2d9b39869fb65850ad861d8739a1f95686 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -40,6 +40,7 @@ SECTION
 #include "libbfd.h"
 #define ARCH_SIZE 0
 #include "elf-bfd.h"
+#include "libiberty.h"
 
 static INLINE struct elf_segment_map *make_mapping
   PARAMS ((bfd *, asection **, unsigned int, unsigned int, boolean));
@@ -384,7 +385,7 @@ setup_group (abfd, hdr, newsect)
        }
 
       if (num_group == 0)
-       num_group = -1;
+       num_group = (unsigned) -1;
       elf_tdata (abfd)->num_group = num_group;
 
       if (num_group > 0)
@@ -402,7 +403,7 @@ setup_group (abfd, hdr, newsect)
              Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[i];
              if (shdr->sh_type == SHT_GROUP && shdr->sh_size >= 8)
                {
-                 char *src;
+                 unsigned char *src;
                  Elf_Internal_Group *dest;
 
                  /* Add to list of sections.  */
@@ -466,7 +467,7 @@ setup_group (abfd, hdr, newsect)
          while (--n_elt != 0)
            if ((++idx)->shdr == hdr)
              {
-               asection *s;
+               asection *s = NULL;
 
                /* We are a member of this group.  Go looking through
                   other members to see if any others are linked via
@@ -502,7 +503,7 @@ setup_group (abfd, hdr, newsect)
                    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, 4, abfd) != 4)
+                       || bfd_bread (ename, (bfd_size_type) 4, abfd) != 4)
                      return false;
                    iname = H_GET_32 (abfd, ename);
                    gname = elf_string_from_elf_strtab (abfd, iname);
@@ -599,7 +600,7 @@ _bfd_elf_make_section_from_shdr (abfd, hdr, name)
     };
     int i;
 
-    for (i = sizeof (debug_sec_names) / sizeof (debug_sec_names[0]); i--;)
+    for (i = ARRAY_SIZE (debug_sec_names); i--;)
       if (strncmp (name, debug_sec_names[i], strlen (debug_sec_names[i])) == 0)
        break;
 
@@ -643,17 +644,30 @@ _bfd_elf_make_section_from_shdr (abfd, hdr, name)
          phdr = elf_tdata (abfd)->phdr;
          for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++)
            {
+             /* This section is part of this segment if its file
+                offset plus size lies within the segment's memory
+                span and, if the section is loaded, the extent of the
+                loaded data lies within the extent of the segment.  
+                If the p_paddr field is not set, we don't alter the 
+                LMA.  */
              if (phdr->p_type == PT_LOAD
-                 && phdr->p_vaddr != phdr->p_paddr
-                 && phdr->p_vaddr <= hdr->sh_addr
-                 && (phdr->p_vaddr + phdr->p_memsz
-                     >= hdr->sh_addr + hdr->sh_size)
+                 && phdr->p_paddr
+                 && (bfd_vma) hdr->sh_offset >= phdr->p_offset
+                 && (hdr->sh_offset + hdr->sh_size
+                     <= phdr->p_offset + phdr->p_memsz)
                  && ((flags & SEC_LOAD) == 0
-                     || (phdr->p_offset <= (bfd_vma) hdr->sh_offset
-                         && (phdr->p_offset + phdr->p_filesz
-                             >= hdr->sh_offset + hdr->sh_size))))
+                     || (phdr->p_offset + phdr->p_filesz
+                         >= hdr->sh_offset + hdr->sh_size)))
                {
-                 newsect->lma += phdr->p_paddr - phdr->p_vaddr;
+                 /* 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;
                }
            }
@@ -798,6 +812,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_GNU_EH_FRAME: pt = "EH_FRAME"; break;
            default: sprintf (buf, "0x%lx", p->p_type); pt = buf; break;
            }
          fprintf (f, "%8s off    0x", pt);
@@ -1733,6 +1748,62 @@ bfd_section_from_shdr (abfd, shindex)
   return true;
 }
 
+/* Return the section for the local symbol specified by ABFD, R_SYMNDX.
+   Return SEC for sections that have no elf section, and NULL on error.  */
+
+asection *
+bfd_section_from_r_symndx (abfd, cache, sec, r_symndx)
+     bfd *abfd;
+     struct sym_sec_cache *cache;
+     asection *sec;
+     unsigned long r_symndx;
+{
+  unsigned char esym_shndx[2];
+  unsigned int isym_shndx;
+  Elf_Internal_Shdr *symtab_hdr;
+  file_ptr pos;
+  bfd_size_type amt;
+  unsigned int ent = r_symndx % LOCAL_SYM_CACHE_SIZE;
+
+  if (cache->abfd == abfd && cache->indx[ent] == r_symndx)
+    return cache->sec[ent];
+
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  pos = symtab_hdr->sh_offset;
+  if (get_elf_backend_data (abfd)->s->sizeof_sym
+      == sizeof (Elf64_External_Sym))
+    {
+      pos += r_symndx * sizeof (Elf64_External_Sym);
+      pos += offsetof (Elf64_External_Sym, st_shndx);
+    }
+  else
+    {
+      pos += r_symndx * sizeof (Elf32_External_Sym);
+      pos += offsetof (Elf32_External_Sym, st_shndx);
+    }
+  amt = sizeof (esym_shndx);
+  if (bfd_seek (abfd, pos, SEEK_SET) != 0
+      || bfd_bread ((PTR) esym_shndx, amt, abfd) != amt)
+    return NULL;
+  isym_shndx = H_GET_16 (abfd, esym_shndx);
+
+  if (cache->abfd != abfd)
+    {
+      memset (cache->indx, -1, sizeof (cache->indx));
+      cache->abfd = abfd;
+    }
+  cache->indx[ent] = r_symndx;
+  cache->sec[ent] = sec;
+  if (isym_shndx > 0 && isym_shndx < SHN_LORESERVE)
+    {
+      asection *s;
+      s = bfd_section_from_elf_index (abfd, isym_shndx);
+      if (s != NULL)
+       cache->sec[ent] = s;
+    }
+  return cache->sec[ent];
+}
+
 /* Given an ELF section number, retrieve the corresponding BFD
    section.  */
 
@@ -1925,8 +1996,8 @@ _bfd_elf_init_reloc_shdr (abfd, rel_hdr, asect, use_rela_p)
     return false;
   sprintf (name, "%s%s", use_rela_p ? ".rela" : ".rel", asect->name);
   rel_hdr->sh_name =
-    (unsigned int) _bfd_stringtab_add (elf_shstrtab (abfd), name,
-                                      true, false);
+    (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd), name,
+                                       false);
   if (rel_hdr->sh_name == (unsigned int) -1)
     return false;
   rel_hdr->sh_type = use_rela_p ? SHT_RELA : SHT_REL;
@@ -1963,9 +2034,8 @@ elf_fake_sections (abfd, asect, failedptrarg)
 
   this_hdr = &elf_section_data (asect)->this_hdr;
 
-  this_hdr->sh_name = (unsigned long) _bfd_stringtab_add (elf_shstrtab (abfd),
-                                                         asect->name,
-                                                         true, false);
+  this_hdr->sh_name = (unsigned long) _bfd_elf_strtab_add (elf_shstrtab (abfd),
+                                                          asect->name, false);
   if (this_hdr->sh_name == (unsigned long) -1)
     {
       *failedptr = true;
@@ -2186,38 +2256,51 @@ assign_section_numbers (abfd)
 {
   struct elf_obj_tdata *t = elf_tdata (abfd);
   asection *sec;
-  unsigned int section_number;
+  unsigned int section_number, secn;
   Elf_Internal_Shdr **i_shdrp;
   bfd_size_type amt;
 
   section_number = 1;
 
+  _bfd_elf_strtab_clear_all_refs (elf_shstrtab (abfd));
+
   for (sec = abfd->sections; sec; sec = sec->next)
     {
       struct bfd_elf_section_data *d = elf_section_data (sec);
 
       d->this_idx = section_number++;
+      _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->this_hdr.sh_name);
       if ((sec->flags & SEC_RELOC) == 0)
        d->rel_idx = 0;
       else
-       d->rel_idx = section_number++;
+       {
+         d->rel_idx = section_number++;
+         _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->rel_hdr.sh_name);
+       }
 
       if (d->rel_hdr2)
-       d->rel_idx2 = section_number++;
+       {
+         d->rel_idx2 = section_number++;
+         _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->rel_hdr2->sh_name);
+       }
       else
        d->rel_idx2 = 0;
     }
 
   t->shstrtab_section = section_number++;
+  _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->shstrtab_hdr.sh_name);
   elf_elfheader (abfd)->e_shstrndx = t->shstrtab_section;
-  t->shstrtab_hdr.sh_size = _bfd_stringtab_size (elf_shstrtab (abfd));
 
   if (bfd_get_symcount (abfd) > 0)
     {
       t->symtab_section = section_number++;
+      _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->symtab_hdr.sh_name);
       t->strtab_section = section_number++;
+      _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->strtab_hdr.sh_name);
     }
 
+  _bfd_elf_strtab_finalize (elf_shstrtab (abfd));
+  t->shstrtab_hdr.sh_size = _bfd_elf_strtab_size (elf_shstrtab (abfd));
   elf_elfheader (abfd)->e_shnum = section_number;
 
   /* Set up the list of section header pointers, in agreement with the
@@ -2354,6 +2437,10 @@ assign_section_numbers (abfd)
        }
     }
 
+  for (secn = 1; secn < section_number; ++secn)
+    i_shdrp[secn]->sh_name = _bfd_elf_strtab_offset (elf_shstrtab (abfd),
+                                                    i_shdrp[secn]->sh_name);
+
   return true;
 }
 
@@ -2615,7 +2702,7 @@ _bfd_elf_compute_section_file_positions (abfd, link_info)
   shstrtab_hdr->sh_type = SHT_STRTAB;
   shstrtab_hdr->sh_flags = 0;
   shstrtab_hdr->sh_addr = 0;
-  shstrtab_hdr->sh_size = _bfd_stringtab_size (elf_shstrtab (abfd));
+  shstrtab_hdr->sh_size = _bfd_elf_strtab_size (elf_shstrtab (abfd));
   shstrtab_hdr->sh_entsize = 0;
   shstrtab_hdr->sh_link = 0;
   shstrtab_hdr->sh_info = 0;
@@ -2708,7 +2795,7 @@ map_sections_to_segments (abfd)
   asection **hdrpp;
   boolean phdr_in_segment = true;
   boolean writable;
-  asection *dynsec;
+  asection *dynsec, *eh_frame_hdr;
   bfd_size_type amt;
 
   if (elf_tdata (abfd)->segment_map != NULL)
@@ -2948,6 +3035,24 @@ map_sections_to_segments (abfd)
        }
     }
 
+  /* If there is a .eh_frame_hdr section, throw in a PT_GNU_EH_FRAME
+     segment.  */
+  eh_frame_hdr = bfd_get_section_by_name (abfd, ".eh_frame_hdr");
+  if (eh_frame_hdr != NULL && (eh_frame_hdr->flags & SEC_LOAD))
+    {
+      amt = sizeof (struct elf_segment_map);
+      m = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
+      if (m == NULL)
+       goto error_return;
+      m->next = NULL;
+      m->p_type = PT_GNU_EH_FRAME;
+      m->count = 1;
+      m->sections[0] = eh_frame_hdr;
+
+      *pm = m;
+      pm = &m->next;
+    }
+
   free (sections);
   sections = NULL;
 
@@ -3248,10 +3353,10 @@ assign_file_positions_for_segments (abfd)
 
          /* The section may have artificial alignment forced by a
             link script.  Notice this case by the gap between the
-            cumulative phdr vma and the section's vma.  */
-         if (p->p_vaddr + p->p_memsz < sec->vma)
+            cumulative phdr lma and the section's lma.  */
+         if (p->p_paddr + p->p_memsz < sec->lma)
            {
-             bfd_vma adjust = sec->vma - (p->p_vaddr + p->p_memsz);
+             bfd_vma adjust = sec->lma - (p->p_paddr + p->p_memsz);
 
              p->p_memsz += adjust;
              off += adjust;
@@ -3289,13 +3394,11 @@ assign_file_positions_for_segments (abfd)
                {
                  if (i == 0)
                    {
-                     (* _bfd_error_handler)
-                       (_("Error: First section in segment (%s) starts at 0x%x"),
-                        bfd_section_name (abfd, sec), sec->lma);
-                     (* _bfd_error_handler)
-                       (_("       whereas segment starts at 0x%x"),
-                        p->p_paddr);
-
+                     (* _bfd_error_handler) (_("\
+Error: First section in segment (%s) starts at 0x%x whereas the segment starts at 0x%x"),
+                                             bfd_section_name (abfd, sec),
+                                             sec->lma,
+                                             p->p_paddr);
                      return false;
                    }
                  p->p_memsz += adjust;
@@ -3464,6 +3567,13 @@ get_program_header_size (abfd)
       ++segs;
     }
 
+  if (elf_tdata (abfd)->eh_frame_hdr
+      && bfd_get_section_by_name (abfd, ".eh_frame_hdr") != NULL)
+    {
+      /* We need a PT_GNU_EH_FRAME segment.  */
+      ++segs;
+    }
+
   for (s = abfd->sections; s != NULL; s = s->next)
     {
       if ((s->flags & SEC_LOAD) != 0
@@ -3606,13 +3716,13 @@ prep_headers (abfd)
   Elf_Internal_Phdr *i_phdrp = 0; /* Program header table, internal form */
   Elf_Internal_Shdr **i_shdrp; /* Section header table, internal form */
   int count;
-  struct bfd_strtab_hash *shstrtab;
+  struct elf_strtab_hash *shstrtab;
   struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
   i_ehdrp = elf_elfheader (abfd);
   i_shdrp = elf_elfsections (abfd);
 
-  shstrtab = _bfd_elf_stringtab_init ();
+  shstrtab = _bfd_elf_strtab_init ();
   if (shstrtab == NULL)
     return false;
 
@@ -3698,11 +3808,11 @@ prep_headers (abfd)
     }
 
   elf_tdata (abfd)->symtab_hdr.sh_name =
-    (unsigned int) _bfd_stringtab_add (shstrtab, ".symtab", true, false);
+    (unsigned int) _bfd_elf_strtab_add (shstrtab, ".symtab", false);
   elf_tdata (abfd)->strtab_hdr.sh_name =
-    (unsigned int) _bfd_stringtab_add (shstrtab, ".strtab", true, false);
+    (unsigned int) _bfd_elf_strtab_add (shstrtab, ".strtab", false);
   elf_tdata (abfd)->shstrtab_hdr.sh_name =
-    (unsigned int) _bfd_stringtab_add (shstrtab, ".shstrtab", true, false);
+    (unsigned int) _bfd_elf_strtab_add (shstrtab, ".shstrtab", false);
   if (elf_tdata (abfd)->symtab_hdr.sh_name == (unsigned int) -1
       || elf_tdata (abfd)->symtab_hdr.sh_name == (unsigned int) -1
       || elf_tdata (abfd)->shstrtab_hdr.sh_name == (unsigned int) -1)
@@ -3781,7 +3891,7 @@ _bfd_elf_write_object_contents (abfd)
 
   /* Write out the section header names.  */
   if (bfd_seek (abfd, elf_tdata (abfd)->shstrtab_hdr.sh_offset, SEEK_SET) != 0
-      || ! _bfd_stringtab_emit (abfd, elf_shstrtab (abfd)))
+      || ! _bfd_elf_strtab_emit (abfd, elf_shstrtab (abfd)))
     return false;
 
   if (bed->elf_backend_final_write_processing)
@@ -3980,16 +4090,19 @@ copy_private_bfd_data (ibfd, obfd)
 
   /* Decide if the given section should be included in the given segment.
      A section will be included if:
-       1. It is within the address space of the segment,
+       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 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)   \
-  ((((IS_CONTAINED_BY_VMA (section, segment)           \
-      || IS_SOLARIS_PT_INTERP (segment, section))      \
-     && (section->flags & SEC_ALLOC) != 0)             \
-    || IS_COREFILE_NOTE (segment, section))            \
-   && section->output_section != NULL                  \
+#define INCLUDE_SECTION_IN_SEGMENT(section, segment)                   \
+  (((((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))                            \
+   && section->output_section != NULL                                  \
    && section->segment_mark == false)
 
   /* Returns true iff seg1 starts after the end of seg2.  */
@@ -5532,7 +5645,7 @@ _bfd_elf_close_and_cleanup (abfd)
   if (bfd_get_format (abfd) == bfd_object)
     {
       if (elf_shstrtab (abfd) != NULL)
-       _bfd_stringtab_free (elf_shstrtab (abfd));
+       _bfd_elf_strtab_free (elf_shstrtab (abfd));
     }
 
   return _bfd_generic_close_and_cleanup (abfd);
@@ -5664,7 +5777,10 @@ elfcore_grok_prstatus (abfd, note)
       offset   = offsetof (prstatus_t, pr_reg);
       memcpy (&prstat, note->descdata, sizeof (prstat));
 
-      elf_tdata (abfd)->core_signal = prstat.pr_cursig;
+      /* Do not overwrite the core signal if it
+        has already been set by another thread.  */
+      if (elf_tdata (abfd)->core_signal == 0)
+       elf_tdata (abfd)->core_signal = prstat.pr_cursig;
       elf_tdata (abfd)->core_pid = prstat.pr_pid;
 
       /* pr_who exists on:
@@ -5687,7 +5803,10 @@ elfcore_grok_prstatus (abfd, note)
       offset   = offsetof (prstatus32_t, pr_reg);
       memcpy (&prstat, note->descdata, sizeof (prstat));
 
-      elf_tdata (abfd)->core_signal = prstat.pr_cursig;
+      /* Do not overwrite the core signal if it
+        has already been set by another thread.  */
+      if (elf_tdata (abfd)->core_signal == 0)
+       elf_tdata (abfd)->core_signal = prstat.pr_cursig;
       elf_tdata (abfd)->core_pid = prstat.pr_pid;
 
       /* pr_who exists on:
@@ -6281,3 +6400,76 @@ _bfd_elf_reloc_type_class (rela)
 {
   return reloc_class_normal;
 }
+
+/* For RELA architectures, return what the relocation value for
+   relocation against a local symbol.  */
+
+bfd_vma
+_bfd_elf_rela_local_sym (abfd, sym, sec, rel)
+     bfd *abfd;
+     Elf_Internal_Sym *sym;
+     asection *sec;
+     Elf_Internal_Rela *rel;
+{
+  bfd_vma relocation;
+
+  relocation = (sec->output_section->vma
+               + sec->output_offset
+               + sym->st_value);
+  if ((sec->flags & SEC_MERGE)
+      && ELF_ST_TYPE (sym->st_info) == STT_SECTION
+      && elf_section_data (sec)->sec_info_type == ELF_INFO_TYPE_MERGE)
+    {
+      asection *msec;
+
+      msec = sec;
+      rel->r_addend =
+       _bfd_merged_section_offset (abfd, &msec,
+                                   elf_section_data (sec)->sec_info,
+                                   sym->st_value + rel->r_addend,
+                                   (bfd_vma) 0)
+       - relocation;
+      rel->r_addend += msec->output_section->vma + msec->output_offset;
+    }
+  return relocation;
+}
+
+bfd_vma
+_bfd_elf_rel_local_sym (abfd, sym, psec, addend)
+     bfd *abfd;
+     Elf_Internal_Sym *sym;
+     asection **psec;
+     bfd_vma addend;
+{     
+  asection *sec = *psec;
+
+  if (elf_section_data (sec)->sec_info_type != ELF_INFO_TYPE_MERGE)
+    return sym->st_value + addend;
+
+  return _bfd_merged_section_offset (abfd, psec,
+                                    elf_section_data (sec)->sec_info,
+                                    sym->st_value + addend, (bfd_vma) 0);
+}
+
+bfd_vma
+_bfd_elf_section_offset (abfd, info, sec, offset)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     asection *sec;
+     bfd_vma offset;
+{
+  struct bfd_elf_section_data *sec_data;
+
+  sec_data = elf_section_data (sec);
+  switch (sec_data->sec_info_type)
+    {
+    case ELF_INFO_TYPE_STABS:
+      return _bfd_stab_section_offset
+       (abfd, &elf_hash_table (info)->merge_info, sec, &sec_data->sec_info,
+        offset);
+    case ELF_INFO_TYPE_EH_FRAME:
+      return _bfd_elf_eh_frame_section_offset (abfd, sec, offset);
+    default:
+      return offset;
+    }
+}
This page took 0.030449 seconds and 4 git commands to generate.