* archive.c (_bfd_write_archive_contents): Revert June 1 change.
[deliverable/binutils-gdb.git] / bfd / elf32-sparc.c
index bcce4baaeb88611468f33079abb192847fe39b4f..e44922cd25302223fd6ee0cbcfbbbc003de12b53 100644 (file)
@@ -1,5 +1,5 @@
 /* SPARC-specific support for 32-bit ELF
-   Copyright 1993 Free Software Foundation, Inc.
+   Copyright 1993, 1994, 1995 Free Software Foundation, Inc.
 
 This file is part of BFD, the Binary File Descriptor library.
 
@@ -23,7 +23,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "libbfd.h"
 #include "libelf.h"
 
-static CONST struct reloc_howto_struct *bfd_elf32_bfd_reloc_type_lookup
+static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
   PARAMS ((bfd *, bfd_reloc_code_real_type));
 static void elf_info_to_howto
   PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
@@ -36,6 +36,8 @@ static boolean elf32_sparc_check_relocs
           const Elf_Internal_Rela *));
 static boolean elf32_sparc_adjust_dynamic_symbol
   PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
+static boolean elf32_sparc_adjust_dynindx
+  PARAMS ((struct elf_link_hash_entry *, PTR));
 static boolean elf32_sparc_size_dynamic_sections
   PARAMS ((bfd *, struct bfd_link_info *));
 static boolean elf32_sparc_relocate_section
@@ -100,7 +102,7 @@ static reloc_howto_type elf_sparc_howto_table[] =
   HOWTO(R_SPARC_13,      0,2,13,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_13",      false,0,0x00001fff,true),
   HOWTO(R_SPARC_LO10,    0,2,10,false,0,complain_overflow_dont,    bfd_elf_generic_reloc,"R_SPARC_LO10",    false,0,0x000003ff,true),
   HOWTO(R_SPARC_GOT10,   0,2,10,false,0,complain_overflow_dont,    bfd_elf_generic_reloc,"R_SPARC_GOT10",   false,0,0x000003ff,true),
-  HOWTO(R_SPARC_GOT13,   0,2,13,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_GOT13",   false,0,0x00001fff,true),
+  HOWTO(R_SPARC_GOT13,   0,2,13,false,0,complain_overflow_signed,  bfd_elf_generic_reloc,"R_SPARC_GOT13",   false,0,0x00001fff,true),
   HOWTO(R_SPARC_GOT22,  10,2,22,false,0,complain_overflow_dont,    bfd_elf_generic_reloc,"R_SPARC_GOT22",   false,0,0x003fffff,true),
   HOWTO(R_SPARC_PC10,    0,2,10,true, 0,complain_overflow_dont,    bfd_elf_generic_reloc,"R_SPARC_PC10",    false,0,0x000003ff,true),
   HOWTO(R_SPARC_PC22,   10,2,22,true, 0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_PC22",    false,0,0x003fffff,true),
@@ -145,7 +147,7 @@ static CONST struct elf_reloc_map sparc_reloc_map[] =
 /*{ BFD_RELOC_SPARC_UA32, R_SPARC_UA32 }, not used?? */
 };
 
-static CONST struct reloc_howto_struct *
+static reloc_howto_type *
 bfd_elf32_bfd_reloc_type_lookup (abfd, code)
      bfd *abfd;
      bfd_reloc_code_real_type code;
@@ -572,19 +574,13 @@ elf32_sparc_adjust_dynamic_symbol (info, h)
 
   /* Make sure we know what is going on here.  */
   BFD_ASSERT (dynobj != NULL
-             && h->root.type == bfd_link_hash_defined
-             && (bfd_get_flavour (h->root.u.def.section->owner)
-                 == bfd_target_elf_flavour)
              && ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT)
                  || ((h->elf_link_hash_flags
                       & ELF_LINK_HASH_DEF_DYNAMIC) != 0
                      && (h->elf_link_hash_flags
                          & ELF_LINK_HASH_REF_REGULAR) != 0
                      && (h->elf_link_hash_flags
-                         & ELF_LINK_HASH_DEF_REGULAR) == 0
-                     && (elf_elfheader (h->root.u.def.section->owner)->e_type
-                         == ET_DYN)
-                     && h->root.u.def.section->output_section == NULL)));
+                         & ELF_LINK_HASH_DEF_REGULAR) == 0)));
 
   /* If this is a function, put it in the procedure linkage table.  We
      will fill in the contents of the procedure linkage table later
@@ -617,9 +613,17 @@ elf32_sparc_adjust_dynamic_symbol (info, h)
          return false;
        }
 
-      /* Set the symbol to this location in the .plt.  */
-      h->root.u.def.section = s;
-      h->root.u.def.value = s->_raw_size;
+      /* If this symbol is not defined in a regular file, and we are
+        not generating a shared library, then set the symbol to this
+        location in the .plt.  This is required to make function
+        pointers compare as equal between the normal executable and
+        the shared library.  */
+      if (! info->shared
+         && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+       {
+         h->root.u.def.section = s;
+         h->root.u.def.value = s->_raw_size;
+       }
 
       h->plt_offset = s->_raw_size;
 
@@ -640,7 +644,8 @@ elf32_sparc_adjust_dynamic_symbol (info, h)
      real definition first, and we can just use the same value.  */
   if (h->weakdef != NULL)
     {
-      BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined);
+      BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined
+                 || h->weakdef->root.type == bfd_link_hash_defweak);
       h->root.u.def.section = h->weakdef->root.u.def.section;
       h->root.u.def.value = h->weakdef->root.u.def.value;
       return true;
@@ -721,6 +726,7 @@ elf32_sparc_size_dynamic_sections (output_bfd, info)
   bfd *dynobj;
   asection *s;
   boolean reltext;
+  boolean relplt;
 
   dynobj = elf_hash_table (info)->dynobj;
   BFD_ASSERT (dynobj != NULL);
@@ -758,6 +764,7 @@ elf32_sparc_size_dynamic_sections (output_bfd, info)
      determined the sizes of the various dynamic sections.  Allocate
      memory for them.  */
   reltext = false;
+  relplt = false;
   for (s = dynobj->sections; s != NULL; s = s->next)
     {
       const char *name;
@@ -798,6 +805,9 @@ elf32_sparc_size_dynamic_sections (output_bfd, info)
                  && (target->flags & SEC_READONLY) != 0)
                reltext = true;
 
+             if (strcmp (name, ".rela.plt") == 0)
+               relplt = true;
+
              /* We use the reloc_count field as a counter if we need
                 to copy relocs into the output file.  */
              s->reloc_count = 0;
@@ -846,11 +856,18 @@ elf32_sparc_size_dynamic_sections (output_bfd, info)
            return false;
        }
 
-      if (! bfd_elf32_add_dynamic_entry (info, DT_PLTGOT, 0)
-         || ! bfd_elf32_add_dynamic_entry (info, DT_PLTRELSZ, 0)
-         || ! bfd_elf32_add_dynamic_entry (info, DT_PLTREL, DT_RELA)
-         || ! bfd_elf32_add_dynamic_entry (info, DT_JMPREL, 0)
-         || ! bfd_elf32_add_dynamic_entry (info, DT_RELA, 0)
+      if (! bfd_elf32_add_dynamic_entry (info, DT_PLTGOT, 0))
+       return false;
+
+      if (relplt)
+       {
+         if (! bfd_elf32_add_dynamic_entry (info, DT_PLTRELSZ, 0)
+             || ! bfd_elf32_add_dynamic_entry (info, DT_PLTREL, DT_RELA)
+             || ! bfd_elf32_add_dynamic_entry (info, DT_JMPREL, 0))
+           return false;
+       }
+
+      if (! bfd_elf32_add_dynamic_entry (info, DT_RELA, 0)
          || ! bfd_elf32_add_dynamic_entry (info, DT_RELASZ, 0)
          || ! bfd_elf32_add_dynamic_entry (info, DT_RELAENT,
                                            sizeof (Elf32_External_Rela)))
@@ -863,6 +880,44 @@ elf32_sparc_size_dynamic_sections (output_bfd, info)
        }
     }
 
+  /* If we are generating a shared library, we generate a section
+     symbol for each output section.  These are local symbols, which
+     means that they must come first in the dynamic symbol table.
+     That means we must increment the dynamic symbol index of every
+     other dynamic symbol.  */
+  if (info->shared)
+    {
+      int c, i;
+
+      c = bfd_count_sections (output_bfd);
+      elf_link_hash_traverse (elf_hash_table (info),
+                             elf32_sparc_adjust_dynindx,
+                             (PTR) &c);
+      elf_hash_table (info)->dynsymcount += c;
+
+      for (i = 1, s = output_bfd->sections; s != NULL; s = s->next, i++)
+       {
+         elf_section_data (s)->dynindx = i;
+         /* These symbols will have no names, so we don't need to
+             fiddle with dynstr_index.  */
+       }
+    }
+
+  return true;
+}
+
+/* Increment the index of a dynamic symbol by a given amount.  Called
+   via elf_link_hash_traverse.  */
+
+static boolean
+elf32_sparc_adjust_dynindx (h, cparg)
+     struct elf_link_hash_entry *h;
+     PTR cparg;
+{
+  int *cp = (int *) cparg;
+
+  if (h->dynindx != -1)
+    h->dynindx += *cp;
   return true;
 }
 
@@ -904,7 +959,7 @@ elf32_sparc_relocate_section (output_bfd, info, input_bfd, input_section,
   for (; rel < relend; rel++)
     {
       int r_type;
-      const reloc_howto_type *howto;
+      reloc_howto_type *howto;
       long r_symndx;
       struct elf_link_hash_entry *h;
       Elf_Internal_Sym *sym;
@@ -956,14 +1011,47 @@ elf32_sparc_relocate_section (output_bfd, info, input_bfd, input_section,
       else
        {
          h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-         if (h->root.type == bfd_link_hash_defined)
+         if (h->root.type == bfd_link_hash_defined
+             || h->root.type == bfd_link_hash_defweak)
            {
              sec = h->root.u.def.section;
-             relocation = (h->root.u.def.value
-                           + sec->output_section->vma
-                           + sec->output_offset);
+             if ((r_type == R_SPARC_WPLT30
+                  && h->plt_offset != (bfd_vma) -1)
+                 || ((r_type == R_SPARC_GOT10
+                      || r_type == R_SPARC_GOT13
+                      || r_type == R_SPARC_GOT22)
+                     && elf_hash_table (info)->dynamic_sections_created)
+                 || (info->shared
+                     && (input_section->flags & SEC_ALLOC) != 0
+                     && (r_type == R_SPARC_8
+                         || r_type == R_SPARC_16
+                         || r_type == R_SPARC_32
+                         || r_type == R_SPARC_DISP8
+                         || r_type == R_SPARC_DISP16
+                         || r_type == R_SPARC_DISP32
+                         || r_type == R_SPARC_WDISP30
+                         || r_type == R_SPARC_WDISP22
+                         || r_type == R_SPARC_HI22
+                         || r_type == R_SPARC_22
+                         || r_type == R_SPARC_13
+                         || r_type == R_SPARC_LO10
+                         || r_type == R_SPARC_UA32
+                         || ((r_type == R_SPARC_PC10
+                              || r_type == R_SPARC_PC22)
+                             && strcmp (h->root.root.string,
+                                        "_GLOBAL_OFFSET_TABLE_") != 0))))
+               {
+                 /* In these cases, we don't need the relocation
+                     value.  We check specially because in some
+                     obscure cases sec->output_section will be NULL.  */
+                 relocation = 0;
+               }
+             else
+               relocation = (h->root.u.def.value
+                             + sec->output_section->vma
+                             + sec->output_offset);
            }
-         else if (h->root.type == bfd_link_hash_weak)
+         else if (h->root.type == bfd_link_hash_undefweak)
            relocation = 0;
          else if (info->shared)
            relocation = 0;
@@ -1146,37 +1234,44 @@ elf32_sparc_relocate_section (output_bfd, info, input_bfd, input_section,
                {
                  BFD_ASSERT (h->dynindx != -1);
                  outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
-                 outrel.r_addend = 0;
+                 outrel.r_addend = rel->r_addend;
                }
              else
                {
-                 long indx;
-
-                 sym = local_syms + r_symndx;
-
-                 /* If this isn't a section symbol, we need to map it
-                     to something that is going to be put into the
-                     dynamic symbols.  The case will probably never
-                     arise.  */
-                 BFD_ASSERT (ELF_ST_TYPE (sym->st_info) == STT_SECTION);
-
-                 sec = local_sections[r_symndx];
-                 if (sec != NULL && bfd_is_abs_section (sec))
-                   indx = 0;
-                 else if (sec == NULL || sec->owner == NULL)
+                 if (r_type == R_SPARC_32)
                    {
-                     bfd_set_error (bfd_error_bad_value);
-                     return false;
+                     outrel.r_info = ELF32_R_INFO (0, R_SPARC_RELATIVE);
+                     outrel.r_addend = relocation + rel->r_addend;
                    }
                  else
                    {
-                     indx = sec->output_section->target_index;
-                     if (indx == 0)
-                       abort ();
+                     long indx;
+
+                     sym = local_syms + r_symndx;
+
+                     BFD_ASSERT (ELF_ST_TYPE (sym->st_info) == STT_SECTION);
+
+                     sec = local_sections[r_symndx];
+                     if (sec != NULL && bfd_is_abs_section (sec))
+                       indx = 0;
+                     else if (sec == NULL || sec->owner == NULL)
+                       {
+                         bfd_set_error (bfd_error_bad_value);
+                         return false;
+                       }
+                     else
+                       {
+                         asection *osec;
+
+                         osec = sec->output_section;
+                         indx = elf_section_data (osec)->dynindx;
+                         if (indx == 0)
+                           abort ();
+                       }
+
+                     outrel.r_info = ELF32_R_INFO (indx, r_type);
+                     outrel.r_addend = relocation + rel->r_addend;
                    }
-
-                 outrel.r_info = ELF32_R_INFO (indx, r_type);
-                 outrel.r_addend = sec->output_offset + sym->st_value;
                }
 
              bfd_elf32_swap_reloca_out (output_bfd, &outrel,
@@ -1399,15 +1494,19 @@ elf32_sparc_finish_dynamic_sections (output_bfd, info)
              asection *s;
 
              s = bfd_get_section_by_name (output_bfd, name);
-             BFD_ASSERT (s != NULL);
-             if (! size)
-               dyn.d_un.d_ptr = s->vma;
+             if (s == NULL)
+               dyn.d_un.d_val = 0;
              else
                {
-                 if (s->_cooked_size != 0)
-                   dyn.d_un.d_val = s->_cooked_size;
+                 if (! size)
+                   dyn.d_un.d_ptr = s->vma;
                  else
-                   dyn.d_un.d_val = s->_raw_size;
+                   {
+                     if (s->_cooked_size != 0)
+                       dyn.d_un.d_val = s->_cooked_size;
+                     else
+                       dyn.d_un.d_val = s->_raw_size;
+                   }
                }
              bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
            }
@@ -1442,6 +1541,43 @@ elf32_sparc_finish_dynamic_sections (output_bfd, info)
 
   elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4;
 
+  if (info->shared)
+    {
+      asection *sdynsym;
+      asection *s;
+      Elf_Internal_Sym sym;
+
+      /* Set up the section symbols for the output sections.  */
+
+      sdynsym = bfd_get_section_by_name (dynobj, ".dynsym");
+      BFD_ASSERT (sdynsym != NULL);
+
+      sym.st_size = 0;
+      sym.st_name = 0;
+      sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
+      sym.st_other = 0;
+
+      for (s = output_bfd->sections; s != NULL; s = s->next)
+       {
+         int indx;
+
+         sym.st_value = s->vma;
+
+         indx = elf_section_data (s)->this_idx;
+         BFD_ASSERT (indx > 0);
+         sym.st_shndx = indx;
+
+         bfd_elf32_swap_symbol_out (output_bfd, &sym,
+                                    ((Elf32_External_Sym *) sdynsym->contents
+                                     + elf_section_data (s)->dynindx));
+       }
+
+      /* Set the sh_info field of the output .dynsym section to the
+         index of the first global symbol.  */
+      elf_section_data (sdynsym->output_section)->this_hdr.sh_info =
+       bfd_count_sections (output_bfd) + 1;
+    }
+
   return true;
 }
 
This page took 0.027866 seconds and 4 git commands to generate.