2004-06-07 Randolph Chung <tausq@debian.org>
[deliverable/binutils-gdb.git] / bfd / elf.c
index 00443c2cc830f3679f2a9f7dae7b1a035566e3e4..93a3d3ac9f837c6c0deacae5a53378efcdb65430 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -901,10 +901,31 @@ merge_sections_remove_hook (bfd *abfd ATTRIBUTE_UNUSED,
 bfd_boolean
 _bfd_elf_merge_sections (bfd *abfd, struct bfd_link_info *info)
 {
+  bfd *ibfd;
+  asection *sec;
+
   if (!is_elf_hash_table (info->hash))
     return FALSE;
-  if (elf_hash_table (info)->merge_info)
-    _bfd_merge_sections (abfd, elf_hash_table (info)->merge_info,
+
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+    if ((ibfd->flags & DYNAMIC) == 0)
+      for (sec = ibfd->sections; sec != NULL; sec = sec->next)
+       if ((sec->flags & SEC_MERGE) != 0
+           && !bfd_is_abs_section (sec->output_section))
+         {
+           struct bfd_elf_section_data *secdata;
+
+           secdata = elf_section_data (sec);
+           if (! _bfd_add_merge_section (abfd,
+                                         &elf_hash_table (info)->merge_info,
+                                         sec, &secdata->sec_info))
+             return FALSE;
+           else if (secdata->sec_info)
+             sec->sec_info_type = ELF_INFO_TYPE_MERGE;
+         }
+
+  if (elf_hash_table (info)->merge_info != NULL)
+    _bfd_merge_sections (abfd, info, elf_hash_table (info)->merge_info,
                         merge_sections_remove_hook);
   return TRUE;
 }
@@ -974,6 +995,7 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
            case PT_TLS: pt = "TLS"; break;
            case PT_GNU_EH_FRAME: pt = "EH_FRAME"; break;
            case PT_GNU_STACK: pt = "STACK"; break;
+           case PT_GNU_RELRO: pt = "RELRO"; break;
            default: sprintf (buf, "0x%lx", p->p_type); pt = buf; break;
            }
          fprintf (f, "%8s off    0x", pt);
@@ -2300,6 +2322,9 @@ bfd_section_from_phdr (bfd *abfd, Elf_Internal_Phdr *hdr, int index)
     case PT_GNU_STACK:
       return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "stack");
 
+    case PT_GNU_RELRO:
+      return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "relro");
+
     default:
       /* Check for any processor-specific program segment types.
          If no handler for them, default to making "segment" sections.  */
@@ -3547,6 +3572,21 @@ map_sections_to_segments (bfd *abfd)
       pm = &m->next;
     }
 
+  if (elf_tdata (abfd)->relro)
+    {
+      amt = sizeof (struct elf_segment_map);
+      m = bfd_zalloc (abfd, amt);
+      if (m == NULL)
+       goto error_return;
+      m->next = NULL;
+      m->p_type = PT_GNU_RELRO;
+      m->p_flags = PF_R;
+      m->p_flags_valid = 1;
+
+      *pm = m;
+      pm = &m->next;
+    }
+
   free (sections);
   sections = NULL;
 
@@ -4081,6 +4121,37 @@ Error: First section in segment (%s) starts at 0x%x whereas the segment starts a
              if (! m->p_paddr_valid)
                p->p_paddr = phdrs_paddr;
            }
+         else if (p->p_type == PT_GNU_RELRO)
+           {
+             Elf_Internal_Phdr *lp;
+
+             for (lp = phdrs; lp < phdrs + count; ++lp)
+               {
+                 if (lp->p_type == PT_LOAD
+                     && lp->p_vaddr <= link_info->relro_end
+                     && lp->p_vaddr >= link_info->relro_start
+                     && lp->p_vaddr + lp->p_filesz
+                        >= link_info->relro_end)
+                   break;
+               }
+
+             if (lp < phdrs + count
+                 && link_info->relro_end > lp->p_vaddr)
+               {
+                 p->p_vaddr = lp->p_vaddr;
+                 p->p_paddr = lp->p_paddr;
+                 p->p_offset = lp->p_offset;
+                 p->p_filesz = link_info->relro_end - lp->p_vaddr;
+                 p->p_memsz = p->p_filesz;
+                 p->p_align = 1;
+                 p->p_flags = (lp->p_flags & ~PF_W);
+               }
+             else
+               {
+                 memset (p, 0, sizeof *p);
+                 p->p_type = PT_NULL;
+               }
+           }
        }
     }
 
@@ -4168,6 +4239,12 @@ get_program_header_size (bfd *abfd)
       ++segs;
     }
 
+  if (elf_tdata (abfd)->relro)
+    {
+      /* We need a PT_GNU_RELRO segment.  */
+      ++segs;
+    }
+
   for (s = abfd->sections; s != NULL; s = s->next)
     {
       if ((s->flags & SEC_LOAD) != 0
@@ -5234,24 +5311,6 @@ _bfd_elf_copy_private_section_data (bfd *ibfd,
       || obfd->xvec->flavour != bfd_target_elf_flavour)
     return TRUE;
 
-  if (elf_tdata (obfd)->segment_map == NULL && elf_tdata (ibfd)->phdr != NULL)
-    {
-       asection *s;
-
-       /* Only set up the segments if there are no more SEC_ALLOC
-          sections.  FIXME: This won't do the right thing if objcopy is
-          used to remove the last SEC_ALLOC section, since objcopy
-          won't call this routine in that case.  */
-       for (s = isec->next; s != NULL; s = s->next)
-         if ((s->flags & SEC_ALLOC) != 0)
-           break;
-       if (s == NULL)
-         {
-           if (! copy_private_bfd_data (ibfd, obfd))
-             return FALSE;
-         }
-    }
-
   ihdr = &elf_section_data (isec)->this_hdr;
   ohdr = &elf_section_data (osec)->this_hdr;
 
@@ -5274,6 +5333,29 @@ _bfd_elf_copy_private_section_data (bfd *ibfd,
   return TRUE;
 }
 
+/* Copy private header information.  */
+
+bfd_boolean
+_bfd_elf_copy_private_header_data (bfd *ibfd, bfd *obfd)
+{
+  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+    return TRUE;
+
+  /* Copy over private BFD data if it has not already been copied.
+     This must be done here, rather than in the copy_private_bfd_data
+     entry point, because the latter is called after the section
+     contents have been set, which means that the program headers have
+     already been worked out.  */
+  if (elf_tdata (obfd)->segment_map == NULL && elf_tdata (ibfd)->phdr != NULL)
+    {
+      if (! copy_private_bfd_data (ibfd, obfd))
+       return FALSE;
+    }
+
+  return TRUE;
+}
+
 /* Copy private symbol information.  If this symbol is in a section
    which we did not map into a BFD section, try to map the section
    index correctly.  We use special macro definitions for the mapped
@@ -7476,9 +7558,18 @@ _bfd_elf_rela_local_sym (bfd *abfd,
       rel->r_addend =
        _bfd_merged_section_offset (abfd, psec,
                                    elf_section_data (sec)->sec_info,
-                                   sym->st_value + rel->r_addend,
-                                   0);
-      sec = *psec;
+                                   sym->st_value + rel->r_addend);
+      if (sec != *psec)
+       {
+         /* If we have changed the section, and our original section is
+            marked with SEC_EXCLUDE, it means that the original
+            SEC_MERGE section has been completely subsumed in some
+            other SEC_MERGE section.  In this case, we need to leave
+            some info around for --emit-relocs.  */
+         if ((sec->flags & SEC_EXCLUDE) != 0)
+           sec->kept_section = *psec;
+         sec = *psec;
+       }
       rel->r_addend -= relocation;
       rel->r_addend += sec->output_section->vma + sec->output_offset;
     }
@@ -7498,7 +7589,7 @@ _bfd_elf_rel_local_sym (bfd *abfd,
 
   return _bfd_merged_section_offset (abfd, psec,
                                     elf_section_data (sec)->sec_info,
-                                    sym->st_value + addend, 0);
+                                    sym->st_value + addend);
 }
 
 bfd_vma
This page took 0.026724 seconds and 4 git commands to generate.