*** empty log message ***
[deliverable/binutils-gdb.git] / bfd / elf.c
index 6589bc9ee007310c24b2db9b1eb0c7856d6ac032..7f63b34adcc3bc16c88fe979a92894c6122afc0e 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -1,26 +1,25 @@
 /* ELF executable support for BFD.
-   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
    Free Software Foundation, Inc.
 
-This file is part of BFD, the Binary File Descriptor library.
+   This file is part of BFD, the Binary File Descriptor library.
 
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
 
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
-/*
-
-SECTION
+/*  SECTION
+    
        ELF backends
 
        BFD support for ELF formats is being worked on.
@@ -29,8 +28,7 @@ SECTION
 
        Documentation of the internals of the support code still needs
        to be written.  The code is changing quickly enough that we
-       haven't bothered yet.
- */
+       haven't bothered yet.  */
 
 /* For sparc64-cross-sparc32.  */
 #define _SYSCALL32
@@ -53,6 +51,7 @@ 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 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 *));
@@ -653,10 +652,15 @@ _bfd_elf_make_section_from_shdr (abfd, hdr, name)
                 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.  */
+
+                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
+                have a p_paddr of zero.  Some architectures, eg ARM,
+                place special significance one the address 0 and
+                executables need to be able to have a segment which
+                covers this address.  */
              if (phdr->p_type == PT_LOAD
-                 && phdr->p_paddr
                  && (bfd_vma) hdr->sh_offset >= phdr->p_offset
                  && (hdr->sh_offset + hdr->sh_size
                      <= phdr->p_offset + phdr->p_memsz)
@@ -770,6 +774,20 @@ bfd_elf_generic_reloc (abfd,
   return bfd_reloc_continue;
 }
 \f
+/* Make sure sec_info_type is cleared if sec_info is cleared too.  */
+
+static void
+merge_sections_remove_hook (abfd, sec)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     asection *sec;
+{
+  struct bfd_elf_section_data *sec_data;
+    
+  sec_data = elf_section_data (sec);
+  BFD_ASSERT (sec_data->sec_info_type == ELF_INFO_TYPE_MERGE);
+  sec_data->sec_info_type = ELF_INFO_TYPE_NONE;
+}
+
 /* Finish SHF_MERGE section merging.  */
 
 boolean
@@ -780,11 +798,13 @@ _bfd_elf_merge_sections (abfd, info)
   if (!is_elf_hash_table (info))
     return false;
   if (elf_hash_table (info)->merge_info)
-    _bfd_merge_sections (abfd, elf_hash_table (info)->merge_info);
+    _bfd_merge_sections (abfd, elf_hash_table (info)->merge_info,
+                        merge_sections_remove_hook);
   return true;
 }
 \f
-/* Copy the program header from one object module to another */
+/* Copy the program header and other data from one object module to
+   another.  */
 
 boolean
 _bfd_elf_copy_private_bfd_data (ibfd, obfd)
@@ -799,6 +819,7 @@ _bfd_elf_copy_private_bfd_data (ibfd, obfd)
              || (elf_elfheader (obfd)->e_flags
                  == elf_elfheader (ibfd)->e_flags));
 
+  elf_gp (obfd) = elf_gp (ibfd);
   elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags;
   elf_flags_init (obfd) = true;
   return true;
@@ -1268,14 +1289,23 @@ _bfd_elf_link_hash_copy_indirect (dir, ind)
 }
 
 void
-_bfd_elf_link_hash_hide_symbol (info, h)
-     struct bfd_link_info *info ATTRIBUTE_UNUSED;
+_bfd_elf_link_hash_hide_symbol (info, h, force_local)
+     struct bfd_link_info *info;
      struct elf_link_hash_entry *h;
+     boolean force_local;
 {
-  h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
   h->plt.offset = (bfd_vma) -1;
-  if ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0)
-    h->dynindx = -1;
+  h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
+  if (force_local)
+    {
+      h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
+      if (h->dynindx != -1)
+       {
+         h->dynindx = -1;
+         _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
+                                 h->dynstr_index);
+       }
+    }
 }
 
 /* Initialize an ELF linker hash table.  */
@@ -2189,7 +2219,8 @@ elf_fake_sections (abfd, asect, failedptrarg)
       this_hdr->sh_entsize = 4;
     }
   else if ((asect->flags & SEC_ALLOC) != 0
-          && ((asect->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0))
+          && (((asect->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0)
+              || (asect->flags & SEC_NEVER_LOAD) != 0))
     this_hdr->sh_type = SHT_NOBITS;
   else
     this_hdr->sh_type = SHT_PROGBITS;
@@ -2211,8 +2242,9 @@ elf_fake_sections (abfd, asect, failedptrarg)
     this_hdr->sh_flags |= SHF_GROUP;
 
   /* Check for processor-specific section types.  */
-  if (bed->elf_backend_fake_sections)
-    (*bed->elf_backend_fake_sections) (abfd, this_hdr, asect);
+  if (bed->elf_backend_fake_sections
+      && !(*bed->elf_backend_fake_sections) (abfd, this_hdr, asect))
+    *failedptr = true;
 
   /* If the section has relocs, set up a section header for the
      SHT_REL[A] section.  If two relocation sections are required for
@@ -3297,8 +3329,13 @@ assign_file_positions_for_segments (abfd)
       asection **secpp;
 
       /* If elf_segment_map is not from map_sections_to_segments, the
-         sections may not be correctly ordered.  */
-      if (m->count > 0)
+         sections may not be correctly ordered.  NOTE: sorting should 
+        not be done to the PT_NOTE section of a corefile, which may
+        contain several pseudo-sections artificially created by bfd.
+        Sorting these pseudo-sections breaks things badly.  */
+      if (m->count > 1 
+         && !(elf_elfheader (abfd)->e_type == ET_CORE 
+              && m->p_type == PT_NOTE))
        qsort (m->sections, (size_t) m->count, sizeof (asection *),
               elf_sort_sections);
 
@@ -4026,50 +4063,47 @@ _bfd_elf_section_from_bfd_section (abfd, asect)
      bfd *abfd;
      struct sec *asect;
 {
-  struct elf_backend_data *bed = get_elf_backend_data (abfd);
-  Elf_Internal_Shdr **i_shdrp = elf_elfsections (abfd);
+  struct elf_backend_data *bed;
   int index;
-  Elf_Internal_Shdr *hdr;
-  int maxindex = elf_numsections (abfd);
 
   if (elf_section_data (asect) != NULL
       && elf_section_data (asect)->this_idx != 0)
     return elf_section_data (asect)->this_idx;
 
   if (bfd_is_abs_section (asect))
-    return SHN_ABS;
-  if (bfd_is_com_section (asect))
-    return SHN_COMMON;
-  if (bfd_is_und_section (asect))
-    return SHN_UNDEF;
-
-  for (index = 1; index < maxindex; index++)
+    index = SHN_ABS;
+  else if (bfd_is_com_section (asect))
+    index = SHN_COMMON;
+  else if (bfd_is_und_section (asect))
+    index = SHN_UNDEF;
+  else
     {
-      hdr = i_shdrp[index];
-      if (hdr != NULL && hdr->bfd_section == asect)
-       return index;
+      Elf_Internal_Shdr **i_shdrp = elf_elfsections (abfd);
+      int maxindex = elf_numsections (abfd);
+
+      for (index = 1; index < maxindex; index++)
+       {
+         Elf_Internal_Shdr *hdr = i_shdrp[index];
+
+         if (hdr != NULL && hdr->bfd_section == asect)
+           return index;
+       }
+      index = -1;
     }
 
+  bed = get_elf_backend_data (abfd);
   if (bed->elf_backend_section_from_bfd_section)
     {
-      for (index = 0; index < maxindex; index++)
-       {
-         int retval;
-
-         hdr = i_shdrp[index];
-         if (hdr == NULL)
-           continue;
+      int retval = index;
 
-         retval = index;
-         if ((*bed->elf_backend_section_from_bfd_section)
-             (abfd, hdr, asect, &retval))
-           return retval;
-       }
+      if ((*bed->elf_backend_section_from_bfd_section) (abfd, asect, &retval))
+       return retval;
     }
 
-  bfd_set_error (bfd_error_nonrepresentable_section);
+  if (index == -1)
+    bfd_set_error (bfd_error_nonrepresentable_section);
 
-  return SHN_BAD;
+  return index;
 }
 
 /* Given a BFD symbol, return the index in the ELF symbol table, or -1
@@ -4120,7 +4154,7 @@ _bfd_elf_symbol_from_bfd_symbol (abfd, asym_ptr_ptr)
 #if DEBUG & 4
   {
     fprintf (stderr,
-            _("elf_symbol_from_bfd_symbol 0x%.8lx, name = %s, sym num = %d, flags = 0x%.8lx%s\n"),
+            "elf_symbol_from_bfd_symbol 0x%.8lx, name = %s, sym num = %d, flags = 0x%.8lx%s\n",
             (long) asym_ptr, asym_ptr->name, idx, flags,
             elf_symbol_flags (flags));
     fflush (stderr);
@@ -6120,6 +6154,8 @@ elfcore_grok_psinfo (abfd, note)
 #endif /* defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T) */
 
 #if defined (HAVE_PSTATUS_T)
+static boolean elfcore_grok_pstatus PARAMS ((bfd *, Elf_Internal_Note *));
+
 static boolean
 elfcore_grok_pstatus (abfd, note)
      bfd *abfd;
@@ -6157,6 +6193,8 @@ elfcore_grok_pstatus (abfd, note)
 #endif /* defined (HAVE_PSTATUS_T) */
 
 #if defined (HAVE_LWPSTATUS_T)
+static boolean elfcore_grok_lwpstatus PARAMS ((bfd *, Elf_Internal_Note *));
+
 static boolean
 elfcore_grok_lwpstatus (abfd, note)
      bfd *abfd;
@@ -6252,7 +6290,7 @@ elfcore_grok_win32pstatus (abfd, note)
   if (note->descsz < sizeof (pstatus))
     return true;
 
-  memcpy (&pstatus, note->descdata, note->descsz);
+  memcpy (&pstatus, note->descdata, sizeof (pstatus));
 
   switch (pstatus.data_type)
     {
@@ -6424,7 +6462,7 @@ elfcore_grok_netbsd_note (abfd, note)
   if (elfcore_netbsd_get_lwpid (note, &lwp))
     elf_tdata (abfd)->core_lwpid = lwp;
 
-  if (note->type == 1)
+  if (note->type == NT_NETBSDCORE_PROCINFO)
     {
       /* NetBSD-specific core "procinfo".  Note that we expect to
          find this note before any of the others, which is fine,
@@ -6434,11 +6472,12 @@ elfcore_grok_netbsd_note (abfd, note)
       return elfcore_grok_netbsd_procinfo (abfd, note);
     }
 
-  /* There are not currently any other machine-independent notes defined
-     for NetBSD ELF core files.  If the note type is less than the start
-     of the machine-dependent note types, we don't understand it.  */
+  /* As of Jan 2002 there are no other machine-independent notes
+     defined for NetBSD core files.  If the note type is less
+     than the start of the machine-dependent note types, we don't
+     understand it.  */
   
-  if (note->type < 32)
+  if (note->type < NT_NETBSDCORE_FIRSTMACH)
     return true;
 
 
@@ -6451,10 +6490,10 @@ elfcore_grok_netbsd_note (abfd, note)
     case bfd_arch_sparc:
       switch (note->type)
         {
-        case 32+0:
+        case NT_NETBSDCORE_FIRSTMACH+0:
           return elfcore_make_note_pseudosection (abfd, ".reg", note);
 
-        case 32+2:
+        case NT_NETBSDCORE_FIRSTMACH+2:
           return elfcore_make_note_pseudosection (abfd, ".reg2", note);
 
         default:
@@ -6467,10 +6506,10 @@ elfcore_grok_netbsd_note (abfd, note)
     default:
       switch (note->type)
         {
-        case 32+1:
+        case NT_NETBSDCORE_FIRSTMACH+1:
           return elfcore_make_note_pseudosection (abfd, ".reg", note);
 
-        case 32+3:
+        case NT_NETBSDCORE_FIRSTMACH+3:
           return elfcore_make_note_pseudosection (abfd, ".reg2", note);
 
         default:
@@ -6480,6 +6519,174 @@ elfcore_grok_netbsd_note (abfd, note)
     /* NOTREACHED */
 }
 
+/* Function: elfcore_write_note
+
+   Inputs: 
+     buffer to hold note
+     name of note
+     type of note
+     data for note
+     size of data for note
+
+   Return:
+   End of buffer containing note.  */
+
+char *
+elfcore_write_note (abfd, buf, bufsiz, name, type, input, size)
+     bfd  *abfd;
+     char *buf;
+     int  *bufsiz;
+     char *name;
+     int  type;
+     void *input;
+     int  size;
+{
+  Elf_External_Note *xnp;
+  int namesz = strlen (name);
+  int newspace = BFD_ALIGN (sizeof (Elf_External_Note) + size + namesz - 1, 4);
+  char *p, *dest;
+
+  p = realloc (buf, *bufsiz + newspace);
+  dest = p + *bufsiz;
+  *bufsiz += newspace;
+  xnp = (Elf_External_Note *) dest;
+  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);
+  return p;
+}
+
+#if defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T)
+char *
+elfcore_write_prpsinfo (abfd, buf, bufsiz, fname, psargs)
+     bfd  *abfd;
+     char *buf;
+     int  *bufsiz;
+     char *fname; 
+     char *psargs;
+{
+  int note_type;
+  char *note_name = "CORE";
+
+#if defined (HAVE_PSINFO_T)
+  psinfo_t  data;
+  note_type = NT_PSINFO;
+#else
+  prpsinfo_t data;
+  note_type = NT_PRPSINFO;
+#endif
+
+  memset (&data, 0, sizeof (data));
+  strncpy (data.pr_fname, fname, sizeof (data.pr_fname));
+  strncpy (data.pr_psargs, psargs, sizeof (data.pr_psargs));
+  return elfcore_write_note (abfd, buf, bufsiz, 
+                            note_name, note_type, &data, sizeof (data));
+}
+#endif /* PSINFO_T or PRPSINFO_T */
+
+#if defined (HAVE_PRSTATUS_T)
+char *
+elfcore_write_prstatus (abfd, buf, bufsiz, pid, cursig, gregs)
+     bfd *abfd;
+     char *buf;
+     int *bufsiz;
+     long pid;
+     int cursig;
+     void *gregs;
+{
+  prstatus_t prstat;
+  char *note_name = "CORE";
+
+  memset (&prstat, 0, sizeof (prstat));
+  prstat.pr_pid = pid;
+  prstat.pr_cursig = cursig;
+  memcpy (&prstat.pr_reg, gregs, sizeof (prstat.pr_reg));
+  return elfcore_write_note (abfd, buf, bufsiz, 
+                            note_name, NT_PRSTATUS, &prstat, sizeof (prstat));
+}
+#endif /* HAVE_PRSTATUS_T */
+
+#if defined (HAVE_LWPSTATUS_T)
+char *
+elfcore_write_lwpstatus (abfd, buf, bufsiz, pid, cursig, gregs)
+     bfd *abfd;
+     char *buf;
+     int *bufsiz;
+     long pid;
+     int cursig;
+     void *gregs;
+{
+  lwpstatus_t lwpstat;
+  char *note_name = "CORE";
+
+  memset (&lwpstat, 0, sizeof (lwpstat));
+  lwpstat.pr_lwpid  = pid >> 16;
+  lwpstat.pr_cursig = cursig;
+#if defined (HAVE_LWPSTATUS_T_PR_REG)
+  memcpy (lwpstat.pr_reg, gregs, sizeof (lwpstat.pr_reg));
+#elif defined (HAVE_LWPSTATUS_T_PR_CONTEXT)
+#if !defined(gregs)
+  memcpy (lwpstat.pr_context.uc_mcontext.gregs,
+         gregs, sizeof (lwpstat.pr_context.uc_mcontext.gregs));
+#else
+  memcpy (lwpstat.pr_context.uc_mcontext.__gregs,
+         gregs, sizeof (lwpstat.pr_context.uc_mcontext.__gregs));
+#endif
+#endif
+  return elfcore_write_note (abfd, buf, bufsiz, note_name, 
+                            NT_LWPSTATUS, &lwpstat, sizeof (lwpstat));
+}
+#endif /* HAVE_LWPSTATUS_T */
+
+#if defined (HAVE_PSTATUS_T)
+char *
+elfcore_write_pstatus (abfd, buf, bufsiz, pid, cursig, gregs)
+     bfd *abfd;
+     char *buf;
+     int *bufsiz;
+     long pid;
+     int cursig;
+     void *gregs;
+{
+  pstatus_t pstat;
+  char *note_name = "CORE";
+
+  memset (&pstat, 0, sizeof (pstat));
+  pstat.pr_pid = pid & 0xffff;
+  buf = elfcore_write_note (abfd, buf, bufsiz, note_name, 
+                           NT_PSTATUS, &pstat, sizeof (pstat));
+  return buf;
+}
+#endif /* HAVE_PSTATUS_T */
+
+char *
+elfcore_write_prfpreg (abfd, buf, bufsiz, fpregs, size)
+     bfd  *abfd;
+     char *buf;
+     int  *bufsiz;
+     void *fpregs;
+     int size;
+{
+  char *note_name = "CORE";
+  return elfcore_write_note (abfd, buf, bufsiz, 
+                            note_name, NT_FPREGSET, fpregs, size);
+}
+
+char *
+elfcore_write_prxfpreg (abfd, buf, bufsiz, xfpregs, size)
+     bfd  *abfd;
+     char *buf;
+     int  *bufsiz;
+     void *xfpregs;
+     int size;
+{
+  char *note_name = "LINUX";
+  return elfcore_write_note (abfd, buf, bufsiz, 
+                            note_name, NT_PRXFPREG, xfpregs, size);
+}
+
 static boolean
 elfcore_read_notes (abfd, offset, size)
      bfd *abfd;
This page took 0.031165 seconds and 4 git commands to generate.