Touches most files in bfd/, so likely will be blamed for everything..
[binutils-gdb.git] / bfd / elf64-s390.c
index d0a2a0eadeb87ee20e915afefd1250a7fdae7177..65041a6357a76d24eb720e0fb0b1f34d01ae86bd 100644 (file)
@@ -37,6 +37,12 @@ static struct bfd_link_hash_table *elf_s390_link_hash_table_create
 static boolean elf_s390_check_relocs
   PARAMS ((bfd *, struct bfd_link_info *, asection *,
           const Elf_Internal_Rela *));
+static asection *elf_s390_gc_mark_hook
+  PARAMS ((bfd *, struct bfd_link_info *, Elf_Internal_Rela *,
+          struct elf_link_hash_entry *, Elf_Internal_Sym *));
+static boolean elf_s390_gc_sweep_hook
+  PARAMS ((bfd *, struct bfd_link_info *, asection *,
+          const Elf_Internal_Rela *));
 static boolean elf_s390_adjust_dynamic_symbol
   PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
 static boolean elf_s390_size_dynamic_sections
@@ -49,6 +55,8 @@ static boolean elf_s390_finish_dynamic_symbol
           Elf_Internal_Sym *));
 static boolean elf_s390_finish_dynamic_sections
   PARAMS ((bfd *, struct bfd_link_info *));
+static boolean elf_s390_object_p PARAMS ((bfd *));
+static enum elf_reloc_type_class elf_s390_reloc_type_class PARAMS ((int));
 
 #define USE_RELA 1             /* We want RELA relocations, not REL.  */
 
@@ -107,7 +115,7 @@ static reloc_howto_type elf_howto_table[] =
 static reloc_howto_type elf64_s390_vtinherit_howto =
   HOWTO (R_390_GNU_VTINHERIT, 0,4,0,false,0,complain_overflow_dont, NULL, "R_390_GNU_VTINHERIT", false,0, 0, false);
 static reloc_howto_type elf64_s390_vtentry_howto =
-  HOWTO (R_390_GNU_VTENTRY, 0,4,0,false,0,complain_overflow_dont, _bfd_elf_rel_vtable_reloc_fn,"R_390_GNU_VTENTRY", false,0,0, false); 
+  HOWTO (R_390_GNU_VTENTRY, 0,4,0,false,0,complain_overflow_dont, _bfd_elf_rel_vtable_reloc_fn,"R_390_GNU_VTENTRY", false,0,0, false);
 
 static reloc_howto_type *
 elf_s390_reloc_type_lookup (abfd, code)
@@ -176,7 +184,7 @@ elf_s390_reloc_type_lookup (abfd, code)
   case BFD_RELOC_390_GOTENT:
     return &elf_howto_table[(int) R_390_GOTENT];
   default:
-    break;                                         
+    break;
   }
   return 0;
 }
@@ -203,7 +211,7 @@ elf_s390_info_to_howto (abfd, cache_ptr, dst)
     default:
       BFD_ASSERT (ELF64_R_TYPE(dst->r_info) < (unsigned int) R_390_max);
       cache_ptr->howto = &elf_howto_table[ELF64_R_TYPE(dst->r_info)];
-    }     
+    }
 }
 
 static boolean
@@ -232,7 +240,7 @@ elf_s390_is_local_label_name (abfd, name)
 /* The size in bytes of the first entry in the procedure linkage table.  */
 #define PLT_FIRST_ENTRY_SIZE 32
 /* The size in bytes of an entry in the procedure linkage table.  */
-#define PLT_ENTRY_SIZE 32 
+#define PLT_ENTRY_SIZE 32
 
 #define GOT_ENTRY_SIZE 8
 
@@ -246,7 +254,7 @@ elf_s390_is_local_label_name (abfd, name)
    are needed to load an address in a register and execute
    a branch( or just saving the address)
 
-   Furthermore, only r 0 and 1 are free to use!!!  */ 
+   Furthermore, only r 0 and 1 are free to use!!!  */
 
 /* The first 3 words in the GOT are then reserved.
    Word 0 is the address of the dynamic table.
@@ -258,7 +266,7 @@ elf_s390_is_local_label_name (abfd, name)
    The GOT holds the address in the PLT to be executed.
    The loader then gets:
    24(15) =  Pointer to the structure describing the object.
-   28(15) =  Offset in symbol table                                             
+   28(15) =  Offset in symbol table
    The loader  must  then find the module where the function is
    and insert the address in the GOT.
 
@@ -281,14 +289,14 @@ elf_s390_is_local_label_name (abfd, name)
    the program that manages to have a symbol table of more than 2 GB with a
    total size of at max 4 GB.  */
 
-#define PLT_ENTRY_WORD0     0xc0100000
-#define PLT_ENTRY_WORD1     0x0000e310
-#define PLT_ENTRY_WORD2     0x10000004
-#define PLT_ENTRY_WORD3     0x07f10d10
-#define PLT_ENTRY_WORD4     0xe310100c
-#define PLT_ENTRY_WORD5     0x0014c0f4
-#define PLT_ENTRY_WORD6     0x00000000
-#define PLT_ENTRY_WORD7     0x00000000
+#define PLT_ENTRY_WORD0     (bfd_vma) 0xc0100000
+#define PLT_ENTRY_WORD1     (bfd_vma) 0x0000e310
+#define PLT_ENTRY_WORD2     (bfd_vma) 0x10000004
+#define PLT_ENTRY_WORD3     (bfd_vma) 0x07f10d10
+#define PLT_ENTRY_WORD4     (bfd_vma) 0xe310100c
+#define PLT_ENTRY_WORD5     (bfd_vma) 0x0014c0f4
+#define PLT_ENTRY_WORD6     (bfd_vma) 0x00000000
+#define PLT_ENTRY_WORD7     (bfd_vma) 0x00000000
 
 /* The first PLT entry pushes the offset into the symbol table
    from R1 onto the stack at 8(15) and the loader object info
@@ -305,14 +313,14 @@ elf_s390_is_local_label_name (abfd, name)
 
      Fixup at offset 8: relative address to start of GOT.  */
 
-#define PLT_FIRST_ENTRY_WORD0     0xe310f038
-#define PLT_FIRST_ENTRY_WORD1     0x0024c010
-#define PLT_FIRST_ENTRY_WORD2     0x00000000
-#define PLT_FIRST_ENTRY_WORD3     0xd207f030
-#define PLT_FIRST_ENTRY_WORD4     0x1008e310
-#define PLT_FIRST_ENTRY_WORD5     0x10100004
-#define PLT_FIRST_ENTRY_WORD6     0x07f10700
-#define PLT_FIRST_ENTRY_WORD7     0x07000700
+#define PLT_FIRST_ENTRY_WORD0     (bfd_vma) 0xe310f038
+#define PLT_FIRST_ENTRY_WORD1     (bfd_vma) 0x0024c010
+#define PLT_FIRST_ENTRY_WORD2     (bfd_vma) 0x00000000
+#define PLT_FIRST_ENTRY_WORD3     (bfd_vma) 0xd207f030
+#define PLT_FIRST_ENTRY_WORD4     (bfd_vma) 0x1008e310
+#define PLT_FIRST_ENTRY_WORD5     (bfd_vma) 0x10100004
+#define PLT_FIRST_ENTRY_WORD6     (bfd_vma) 0x07f10700
+#define PLT_FIRST_ENTRY_WORD7     (bfd_vma) 0x07000700
 
 /* The s390 linker needs to keep track of the number of relocs that it
    decides to copy in check_relocs for each symbol.  This is so that
@@ -407,9 +415,9 @@ elf_s390_link_hash_table_create (abfd)
      bfd *abfd;
 {
   struct elf_s390_link_hash_table *ret;
+  bfd_size_type amt = sizeof (struct elf_s390_link_hash_table);
 
-  ret = ((struct elf_s390_link_hash_table *)
-        bfd_alloc (abfd, sizeof (struct elf_s390_link_hash_table)));
+  ret = ((struct elf_s390_link_hash_table *) bfd_alloc (abfd, amt));
   if (ret == (struct elf_s390_link_hash_table *) NULL)
     return NULL;
 
@@ -468,7 +476,7 @@ elf_s390_check_relocs (abfd, info, sec, relocs)
       if (r_symndx < symtab_hdr->sh_info)
        h = NULL;
       else
-       h = sym_hashes[r_symndx - symtab_hdr->sh_info];      
+       h = sym_hashes[r_symndx - symtab_hdr->sh_info];
 
       /* Some relocs require a global offset table.  */
       if (dynobj == NULL)
@@ -542,7 +550,7 @@ elf_s390_check_relocs (abfd, info, sec, relocs)
                      if (! bfd_elf64_link_record_dynamic_symbol (info, h))
                        return false;
                    }
-                 
+
                  sgot->_raw_size += 8;
                  srelgot->_raw_size += sizeof (Elf64_External_Rela);
                }
@@ -551,18 +559,18 @@ elf_s390_check_relocs (abfd, info, sec, relocs)
            }
          else
            {
-             /* This is a global offset table entry for a local symbol.  */
+             /* This is a global offset table entry for a local symbol.  */
              if (local_got_refcounts == NULL)
                {
-                 size_t size;
+                 bfd_size_type size;
 
                  size = symtab_hdr->sh_info * sizeof (bfd_vma);
-                 local_got_refcounts = (bfd_signed_vma *)
-                                        bfd_alloc (abfd, size);
+                 local_got_refcounts = ((bfd_signed_vma *)
+                                        bfd_alloc (abfd, size));
                  if (local_got_refcounts == NULL)
                    return false;
                  elf_local_got_refcounts (abfd) = local_got_refcounts;
-                 memset (local_got_refcounts, -1, size);
+                 memset (local_got_refcounts, -1, (size_t) size);
                }
              if (local_got_refcounts[r_symndx] == -1)
                {
@@ -635,7 +643,7 @@ elf_s390_check_relocs (abfd, info, sec, relocs)
          if (info->shared
               && (sec->flags & SEC_ALLOC) != 0
              && (ELF64_R_TYPE (rel->r_info) == R_390_8
-                 || ELF64_R_TYPE (rel->r_info) == R_390_16 
+                 || ELF64_R_TYPE (rel->r_info) == R_390_16
                  || ELF64_R_TYPE (rel->r_info) == R_390_32
                  || ELF64_R_TYPE (rel->r_info) == R_390_64
                  || (h != NULL
@@ -677,6 +685,8 @@ elf_s390_check_relocs (abfd, info, sec, relocs)
                          || ! bfd_set_section_alignment (dynobj, sreloc, 2))
                        return false;
                    }
+                 if (sec->flags & SEC_READONLY)
+                   info->flags |= DF_TEXTREL;
                }
 
              sreloc->_raw_size += sizeof (Elf64_External_Rela);
@@ -708,7 +718,7 @@ elf_s390_check_relocs (abfd, info, sec, relocs)
                  if (p == NULL)
                    {
                      p = ((struct elf_s390_pcrel_relocs_copied *)
-                          bfd_alloc (dynobj, sizeof *p));
+                          bfd_alloc (dynobj, (bfd_size_type) sizeof *p));
                      if (p == NULL)
                        return false;
                      p->next = eh->pcrel_relocs_copied;
@@ -736,7 +746,7 @@ elf_s390_check_relocs (abfd, info, sec, relocs)
           if (!_bfd_elf64_gc_record_vtentry (abfd, sec, h, rel->r_addend))
             return false;
           break;
-                   
+
        default:
          break;
        }
@@ -1062,12 +1072,11 @@ elf_s390_adjust_dynamic_symbol (info, h)
 
 static boolean
 elf_s390_size_dynamic_sections (output_bfd, info)
-     bfd *output_bfd;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
      struct bfd_link_info *info;
 {
   bfd *dynobj;
   asection *s;
-  boolean reltext;
   boolean relocs;
   boolean plt;
 
@@ -1110,7 +1119,6 @@ elf_s390_size_dynamic_sections (output_bfd, info)
      determined the sizes of the various dynamic sections.  Allocate
      memory for them.  */
   plt = false;
-  reltext = false;
   relocs = false;
   for (s = dynobj->sections; s != NULL; s = s->next)
     {
@@ -1157,29 +1165,10 @@ elf_s390_size_dynamic_sections (output_bfd, info)
            }
          else
            {
-             asection *target;
-
              /* Remember whether there are any reloc sections other
                  than .rela.plt.  */
              if (strcmp (name, ".rela.plt") != 0)
-               {
-                 const char *outname;
-
-                 relocs = true;
-
-                 /* If this relocation section applies to a read only
-                    section, then we probably need a DT_TEXTREL
-                    entry.  The entries in the .rela.plt section
-                    really apply to the .got section, which we
-                    created ourselves and so know is not readonly.  */
-                 outname = bfd_get_section_name (output_bfd,
-                                                 s->output_section);
-                 target = bfd_get_section_by_name (output_bfd, outname + 5);
-                 if (target != NULL
-                     && (target->flags & SEC_READONLY) != 0
-                     && (target->flags & SEC_ALLOC) != 0)
-                   reltext = true;
-               }
+               relocs = true;
 
              /* We use the reloc_count field as a counter if we need
                 to copy relocs into the output file.  */
@@ -1211,37 +1200,40 @@ elf_s390_size_dynamic_sections (output_bfd, info)
         must add the entries now so that we get the correct size for
         the .dynamic section.  The DT_DEBUG entry is filled in by the
         dynamic linker and used by the debugger.  */
+#define add_dynamic_entry(TAG, VAL) \
+  bfd_elf64_add_dynamic_entry (info, (bfd_vma) (TAG), (bfd_vma) (VAL))
+
       if (! info->shared)
        {
-         if (! bfd_elf64_add_dynamic_entry (info, DT_DEBUG, 0))
+         if (!add_dynamic_entry (DT_DEBUG, 0))
            return false;
        }
 
       if (plt)
        {
-         if (! bfd_elf64_add_dynamic_entry (info, DT_PLTGOT, 0)
-             || ! bfd_elf64_add_dynamic_entry (info, DT_PLTRELSZ, 0)
-             || ! bfd_elf64_add_dynamic_entry (info, DT_PLTREL, DT_RELA)
-             || ! bfd_elf64_add_dynamic_entry (info, DT_JMPREL, 0))
+         if (!add_dynamic_entry (DT_PLTGOT, 0)
+             || !add_dynamic_entry (DT_PLTRELSZ, 0)
+             || !add_dynamic_entry (DT_PLTREL, DT_RELA)
+             || !add_dynamic_entry (DT_JMPREL, 0))
            return false;
        }
 
       if (relocs)
         {
-          if (! bfd_elf64_add_dynamic_entry (info, DT_RELA, 0)
-              || ! bfd_elf64_add_dynamic_entry (info, DT_RELASZ, 0)
-              || ! bfd_elf64_add_dynamic_entry (info, DT_RELAENT,
-                                           sizeof (Elf64_External_Rela)))
+          if (!add_dynamic_entry (DT_RELA, 0)
+              || !add_dynamic_entry (DT_RELASZ, 0)
+              || !add_dynamic_entry (DT_RELAENT, sizeof (Elf64_External_Rela)))
            return false;
          }
 
-      if (reltext)
+      if ((info->flags & DF_TEXTREL) != 0)
        {
-         if (! bfd_elf64_add_dynamic_entry (info, DT_TEXTREL, 0))
+         if (!add_dynamic_entry (DT_TEXTREL, 0))
            return false;
          info->flags |= DF_TEXTREL;
        }
     }
+#undef add_dynamic_entry
 
   return true;
 }
@@ -1448,8 +1440,8 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
            {
              if (! ((*info->callbacks->undefined_symbol)
                     (info, h->root.root.string, input_bfd,
-                     input_section, rel->r_offset,
-                    (!info->shared || info->no_undefined
+             input_section, rel->r_offset,
+                    (!info->shared || info->no_undefined
                      || ELF_ST_VISIBILITY (h->other)))))
                return false;
              relocation = 0;
@@ -1556,7 +1548,7 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
            relocation += sgot->output_section->vma;
 
           break;
+
         case R_390_GOTOFF:
           /* Relocation is relative to the start of the global offset
              table.  */
@@ -1692,7 +1684,7 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
                 }
               else if (r_type == R_390_PC16 ||
                        r_type == R_390_PC16DBL ||
-                      r_type == R_390_PC32 || 
+                      r_type == R_390_PC32 ||
                       r_type == R_390_PC32DBL ||
                       r_type == R_390_PC64)
                 {
@@ -1816,7 +1808,7 @@ elf_s390_finish_dynamic_symbol (output_bfd, info, h, sym)
       srela = bfd_get_section_by_name (dynobj, ".rela.plt");
       BFD_ASSERT (splt != NULL && sgot != NULL && srela != NULL);
 
-      /* Calc. index no. 
+      /* Calc. index no.
          Current offset - size first entry / entry size.  */
       plt_index = (h->plt.offset - PLT_FIRST_ENTRY_SIZE) / PLT_ENTRY_SIZE;
 
@@ -1897,7 +1889,7 @@ elf_s390_finish_dynamic_symbol (output_bfd, info, h, sym)
 
       rela.r_offset = (sgot->output_section->vma
                       + sgot->output_offset
-                      + (h->got.offset &~ 1));
+                      + (h->got.offset &~ (bfd_vma) 1));
 
       /* If this is a static link, or it is a -Bsymbolic link and the
         symbol is defined locally or was forced to be local because
@@ -2072,7 +2064,7 @@ elf_s390_finish_dynamic_sections (output_bfd, info)
                      splt->contents + 8);
        }
 
-      elf_section_data (splt->output_section)->this_hdr.sh_entsize = 
+      elf_section_data (splt->output_section)->this_hdr.sh_entsize =
        PLT_ENTRY_SIZE;
     }
 
@@ -2105,6 +2097,24 @@ elf_s390_object_p (abfd)
   return bfd_default_set_arch_mach (abfd, bfd_arch_s390, bfd_mach_s390_esame);
 }
 
+
+static enum elf_reloc_type_class
+elf_s390_reloc_type_class (type)
+     int type;
+{
+  switch (type)
+    {
+    case R_390_RELATIVE:
+      return reloc_class_relative;
+    case R_390_JMP_SLOT:
+      return reloc_class_plt;
+    case R_390_COPY:
+      return reloc_class_copy;
+    default:
+      return reloc_class_normal;
+    }
+}
+
 /*
  * Why was the hash table entry size definition changed from
  * ARCH_SIZE/8 to 4? This breaks the 64 bit dynamic linker and
@@ -2172,6 +2182,7 @@ const struct elf_size_info s390_elf64_size_info =
 #define elf_backend_gc_sweep_hook            elf_s390_gc_sweep_hook
 #define elf_backend_relocate_section         elf_s390_relocate_section
 #define elf_backend_size_dynamic_sections     elf_s390_size_dynamic_sections
+#define elf_backend_reloc_type_class         elf_s390_reloc_type_class
 
 #define elf_backend_object_p                  elf_s390_object_p