Support arbitrary length fill patterns.
[deliverable/binutils-gdb.git] / bfd / elf64-alpha.c
index 2836fd50b5852aacf3adb3f72873ef3fbef95119..6df126a4d13c9237744dc57654069fdb6b0b5ede 100644 (file)
@@ -1,5 +1,5 @@
 /* Alpha specific support for 64-bit ELF
-   Copyright 1996, 1997, 1998, 1999, 2000, 2001
+   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002
    Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@tamu.edu>.
 
@@ -136,7 +136,7 @@ static boolean elf64_alpha_merge_ind_symbols
 static Elf_Internal_Rela * elf64_alpha_find_reloc_at_ofs
   PARAMS ((Elf_Internal_Rela *, Elf_Internal_Rela *, bfd_vma, int));
 static enum elf_reloc_type_class elf64_alpha_reloc_type_class
-  PARAMS ((int));
+  PARAMS ((const Elf_Internal_Rela *));
 \f
 struct alpha_elf_link_hash_entry
 {
@@ -163,15 +163,16 @@ struct alpha_elf_link_hash_entry
     bfd *gotobj;
 
     /* the addend in effect for this entry.  */
-    bfd_signed_vma addend;
+    bfd_vma addend;
 
     /* the .got offset for this entry.  */
     int got_offset;
 
     int flags;
 
-    /* An additional flag.  */
+    /* Additional flags.  */
 #define ALPHA_ELF_GOT_ENTRY_RELOCS_DONE 0x10
+#define ALPHA_ELF_GOT_ENTRY_RELOCS_XLATED 0x20
 
     int use_count;
   } *got_entries;
@@ -321,9 +322,9 @@ elf64_alpha_bfd_link_hash_table_create (abfd)
      bfd *abfd;
 {
   struct alpha_elf_link_hash_table *ret;
+  bfd_size_type amt = sizeof (struct alpha_elf_link_hash_table);
 
-  ret = ((struct alpha_elf_link_hash_table *)
-        bfd_zalloc (abfd, sizeof (struct alpha_elf_link_hash_table)));
+  ret = (struct alpha_elf_link_hash_table *) bfd_zalloc (abfd, amt);
   if (ret == (struct alpha_elf_link_hash_table *) NULL)
     return NULL;
 
@@ -375,7 +376,8 @@ static boolean
 elf64_alpha_mkobject (abfd)
      bfd *abfd;
 {
-  abfd->tdata.any = bfd_zalloc (abfd, sizeof (struct alpha_elf_obj_tdata));
+  bfd_size_type amt = sizeof (struct alpha_elf_obj_tdata);
+  abfd->tdata.any = bfd_zalloc (abfd, amt);
   if (abfd->tdata.any == NULL)
     return false;
   return true;
@@ -387,7 +389,8 @@ elf64_alpha_object_p (abfd)
 {
   /* Allocate our special target data.  */
   struct alpha_elf_obj_tdata *new_tdata;
-  new_tdata = bfd_zalloc (abfd, sizeof (struct alpha_elf_obj_tdata));
+  bfd_size_type amt = sizeof (struct alpha_elf_obj_tdata);
+  new_tdata = bfd_zalloc (abfd, amt);
   if (new_tdata == NULL)
     return false;
   new_tdata->root = *abfd->tdata.elf_obj_data;
@@ -729,7 +732,22 @@ static reloc_howto_type elf64_alpha_howto_table[] =
         false,
         0,
         0,
-        true)
+        true),
+
+  /* A 21 bit branch that adjusts for gp loads.  */
+  HOWTO (R_ALPHA_BRSGP,                /* type */
+        2,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        21,                    /* bitsize */
+        true,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        0,                     /* special_function */
+        "BRSGP",               /* name */
+        false,                 /* partial_inplace */
+        0x1fffff,              /* src_mask */
+        0x1fffff,              /* dst_mask */
+        true),                 /* pcrel_offset */
 };
 
 /* A relocation function which doesn't do anything.  */
@@ -803,8 +821,8 @@ elf64_alpha_do_reloc_gpdisp (abfd, gpdisp, p_ldah, p_lda)
            | (((gpdisp >> 16) + ((gpdisp >> 15) & 1)) & 0xffff));
   i_lda = (i_lda & 0xffff0000) | (gpdisp & 0xffff);
 
-  bfd_put_32 (abfd, i_ldah, p_ldah);
-  bfd_put_32 (abfd, i_lda, p_lda);
+  bfd_put_32 (abfd, (bfd_vma) i_ldah, p_ldah);
+  bfd_put_32 (abfd, (bfd_vma) i_lda, p_lda);
 
   return ret;
 }
@@ -883,6 +901,7 @@ static const struct elf_reloc_map elf64_alpha_reloc_map[] =
   {BFD_RELOC_ALPHA_GPREL_HI16,         R_ALPHA_GPRELHIGH},
   {BFD_RELOC_ALPHA_GPREL_LO16,         R_ALPHA_GPRELLOW},
   {BFD_RELOC_GPREL16,                  R_ALPHA_GPREL16},
+  {BFD_RELOC_ALPHA_BRSGP,              R_ALPHA_BRSGP},
 };
 
 /* Given a BFD reloc type, return a HOWTO structure.  */
@@ -938,7 +957,7 @@ elf64_alpha_info_to_howto (abfd, cache_ptr, dst)
 #define OP_LDQ         0x29
 #define OP_BR          0x30
 #define OP_BSR         0x34
-#define INSN_UNOP      0x2fe00000
+#define INSN_UNOP      0x2ffe0000
 
 struct alpha_relax_info
 {
@@ -1008,8 +1027,8 @@ elf64_alpha_relax_with_lituse (info, symval, irel, irelend)
     {
       ((*_bfd_error_handler)
        ("%s: %s+0x%lx: warning: LITERAL relocation against unexpected insn",
-       bfd_get_filename (info->abfd), info->sec->name,
-       (unsigned long)irel->r_offset));
+       bfd_archive_filename (info->abfd), info->sec->name,
+       (unsigned long) irel->r_offset));
       return irel;
     }
 
@@ -1018,7 +1037,7 @@ elf64_alpha_relax_with_lituse (info, symval, irel, irelend)
     {
       if (ELF64_R_TYPE (urel->r_info) != R_ALPHA_LITUSE)
        break;
-      if (urel->r_addend >= 0 && urel->r_addend <= 3)
+      if (urel->r_addend <= 3)
        flags |= 1 << urel->r_addend;
     }
 
@@ -1065,7 +1084,8 @@ elf64_alpha_relax_with_lituse (info, symval, irel, irelend)
              urel->r_addend = irel->r_addend;
              info->changed_relocs = true;
 
-             bfd_put_32 (info->abfd, insn, info->contents + urel->r_offset);
+             bfd_put_32 (info->abfd, (bfd_vma) insn,
+                         info->contents + urel->r_offset);
              info->changed_contents = true;
            }
 
@@ -1077,7 +1097,7 @@ elf64_alpha_relax_with_lituse (info, symval, irel, irelend)
              irel->r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info),
                                           R_ALPHA_GPRELHIGH);
              lit_insn = (OP_LDAH << 26) | (lit_insn & 0x03ff0000);
-             bfd_put_32 (info->abfd, lit_insn,
+             bfd_put_32 (info->abfd, (bfd_vma) lit_insn,
                          info->contents + irel->r_offset);
              lit_reused = true;
              info->changed_contents = true;
@@ -1097,13 +1117,15 @@ elf64_alpha_relax_with_lituse (info, symval, irel, irelend)
          /* FIXME: sanity check the insn for byte op.  Check that the
             literal dest reg is indeed Rb in the byte insn.  */
 
-         insn = (insn & ~0x001ff000) | ((symval & 7) << 13) | 0x1000;
+         insn &= ~ (unsigned) 0x001ff000;
+         insn |= ((symval & 7) << 13) | 0x1000;
 
          urel->r_info = ELF64_R_INFO (0, R_ALPHA_NONE);
          urel->r_addend = 0;
          info->changed_relocs = true;
 
-         bfd_put_32 (info->abfd, insn, info->contents + urel->r_offset);
+         bfd_put_32 (info->abfd, (bfd_vma) insn,
+                     info->contents + urel->r_offset);
          info->changed_contents = true;
          break;
 
@@ -1136,7 +1158,8 @@ elf64_alpha_relax_with_lituse (info, symval, irel, irelend)
                else
                  all_optimized = false;
 
-               bfd_put_32 (info->abfd, insn, info->contents + urel->r_offset);
+               bfd_put_32 (info->abfd, (bfd_vma) insn,
+                           info->contents + urel->r_offset);
 
                /* Kill any HINT reloc that might exist for this insn.  */
                xrel = (elf64_alpha_find_reloc_at_ofs
@@ -1172,8 +1195,8 @@ elf64_alpha_relax_with_lituse (info, symval, irel, irelend)
                       In that case the insn would use $27 as the base.  */
                    if (ldah == 0x27ba0000 && lda == 0x23bd0000)
                      {
-                       bfd_put_32 (info->abfd, INSN_UNOP, p_ldah);
-                       bfd_put_32 (info->abfd, INSN_UNOP, p_lda);
+                       bfd_put_32 (info->abfd, (bfd_vma) INSN_UNOP, p_ldah);
+                       bfd_put_32 (info->abfd, (bfd_vma) INSN_UNOP, p_lda);
 
                        gpdisp->r_info = ELF64_R_INFO (0, R_ALPHA_NONE);
                        info->changed_contents = true;
@@ -1204,7 +1227,8 @@ elf64_alpha_relax_with_lituse (info, symval, irel, irelend)
          irel->r_info = ELF64_R_INFO (0, R_ALPHA_NONE);
          info->changed_relocs = true;
 
-         bfd_put_32 (info->abfd, INSN_UNOP, info->contents + irel->r_offset);
+         bfd_put_32 (info->abfd, (bfd_vma) INSN_UNOP,
+                     info->contents + irel->r_offset);
          info->changed_contents = true;
        }
     }
@@ -1300,7 +1324,7 @@ elf64_alpha_relax_without_lituse (info, symval, irel)
     {
       ((*_bfd_error_handler)
        ("%s: %s+0x%lx: warning: LITERAL relocation against unexpected insn",
-       bfd_get_filename (info->abfd), info->sec->name,
+       bfd_archive_filename (info->abfd), info->sec->name,
        (unsigned long) irel->r_offset));
       return true;
     }
@@ -1317,7 +1341,7 @@ elf64_alpha_relax_without_lituse (info, symval, irel)
      `ldq R,X(gp)' for `lda R,Y(gp)'.  */
 
   insn = (OP_LDA << 26) | (insn & 0x03ff0000);
-  bfd_put_32 (info->abfd, insn, info->contents + irel->r_offset);
+  bfd_put_32 (info->abfd, (bfd_vma) insn, info->contents + irel->r_offset);
   info->changed_contents = true;
 
   irel->r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info), R_ALPHA_GPREL16);
@@ -1354,12 +1378,14 @@ elf64_alpha_relax_section (abfd, sec, link_info, again)
      boolean *again;
 {
   Elf_Internal_Shdr *symtab_hdr;
+  Elf_Internal_Shdr *shndx_hdr;
   Elf_Internal_Rela *internal_relocs;
   Elf_Internal_Rela *free_relocs = NULL;
   Elf_Internal_Rela *irel, *irelend;
   bfd_byte *free_contents = NULL;
   Elf64_External_Sym *extsyms = NULL;
   Elf64_External_Sym *free_extsyms = NULL;
+  Elf_External_Sym_Shndx *shndx_buf = NULL;
   struct alpha_elf_got_entry **local_got_entries;
   struct alpha_relax_info info;
 
@@ -1440,18 +1466,33 @@ elf64_alpha_relax_section (abfd, sec, link_info, again)
       /* Read this BFD's symbols if we haven't done so already.  */
       if (extsyms == NULL)
        {
+         bfd_size_type amt;
+
          if (symtab_hdr->contents != NULL)
            extsyms = (Elf64_External_Sym *) symtab_hdr->contents;
          else
            {
-             extsyms = ((Elf64_External_Sym *)
-                        bfd_malloc (symtab_hdr->sh_size));
+             amt = symtab_hdr->sh_info;
+             amt *= sizeof (Elf64_External_Sym);
+             extsyms = (Elf64_External_Sym *) bfd_malloc (amt);
              if (extsyms == NULL)
                goto error_return;
              free_extsyms = extsyms;
              if (bfd_seek (abfd, symtab_hdr->sh_offset, SEEK_SET) != 0
-                 || (bfd_read (extsyms, 1, symtab_hdr->sh_size, abfd)
-                     != symtab_hdr->sh_size))
+                 || bfd_bread ((PTR) extsyms, amt, abfd) != amt)
+               goto error_return;
+           }
+
+         shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
+         if (shndx_hdr->sh_size != 0)
+           {
+             amt = symtab_hdr->sh_info;
+             amt *= sizeof (Elf_External_Sym_Shndx);
+             shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
+             if (shndx_buf == NULL)
+               goto error_return;
+             if (bfd_seek (abfd, shndx_hdr->sh_offset, SEEK_SET) != 0
+                 || bfd_bread ((PTR) shndx_buf, amt, abfd) != amt)
                goto error_return;
            }
        }
@@ -1460,19 +1501,20 @@ elf64_alpha_relax_section (abfd, sec, link_info, again)
       if (ELF64_R_SYM (irel->r_info) < symtab_hdr->sh_info)
        {
          /* A local symbol.  */
-         bfd_elf64_swap_symbol_in (abfd,
-                                   extsyms + ELF64_R_SYM (irel->r_info),
-                                   &isym);
+         Elf64_External_Sym *esym;
+         Elf_External_Sym_Shndx *shndx;
+
+         esym = extsyms + ELF64_R_SYM (irel->r_info);
+         shndx = shndx_buf + (shndx_buf ? ELF64_R_SYM (irel->r_info) : 0);
+         bfd_elf64_swap_symbol_in (abfd, esym, shndx, &isym);
          if (isym.st_shndx == SHN_UNDEF)
            info.tsec = bfd_und_section_ptr;
-         else if (isym.st_shndx > 0 && isym.st_shndx < SHN_LORESERVE)
-           info.tsec = bfd_section_from_elf_index (abfd, isym.st_shndx);
          else if (isym.st_shndx == SHN_ABS)
            info.tsec = bfd_abs_section_ptr;
          else if (isym.st_shndx == SHN_COMMON)
            info.tsec = bfd_com_section_ptr;
          else
-           continue;   /* who knows.  */
+           info.tsec = bfd_section_from_elf_index (abfd, isym.st_shndx);
 
          info.h = NULL;
          info.other = isym.st_other;
@@ -1559,6 +1601,9 @@ elf64_alpha_relax_section (abfd, sec, link_info, again)
        }
     }
 
+  if (shndx_buf != NULL)
+    free (shndx_buf);
+
   if (free_extsyms != NULL)
     {
       if (! link_info->keep_memory)
@@ -1566,7 +1611,7 @@ elf64_alpha_relax_section (abfd, sec, link_info, again)
       else
        {
          /* Cache the symbols for elf_link_input_bfd.  */
-         symtab_hdr->contents = extsyms;
+         symtab_hdr->contents = (unsigned char *) extsyms;
        }
     }
 
@@ -1579,6 +1624,8 @@ elf64_alpha_relax_section (abfd, sec, link_info, again)
     free (free_relocs);
   if (free_contents != NULL)
     free (free_contents);
+  if (shndx_buf != NULL)
+    free (shndx_buf);
   if (free_extsyms != NULL)
     free (free_extsyms);
   return false;
@@ -1586,10 +1633,10 @@ elf64_alpha_relax_section (abfd, sec, link_info, again)
 \f
 /* PLT/GOT Stuff */
 #define PLT_HEADER_SIZE 32
-#define PLT_HEADER_WORD1       0xc3600000      /* br   $27,.+4     */
-#define PLT_HEADER_WORD2       0xa77b000c      /* ldq  $27,12($27) */
-#define PLT_HEADER_WORD3       0x47ff041f      /* nop              */
-#define PLT_HEADER_WORD4       0x6b7b0000      /* jmp  $27,($27)   */
+#define PLT_HEADER_WORD1       (bfd_vma) 0xc3600000    /* br   $27,.+4     */
+#define PLT_HEADER_WORD2       (bfd_vma) 0xa77b000c    /* ldq  $27,12($27) */
+#define PLT_HEADER_WORD3       (bfd_vma) 0x47ff041f    /* nop              */
+#define PLT_HEADER_WORD4       (bfd_vma) 0x6b7b0000    /* jmp  $27,($27)   */
 
 #define PLT_ENTRY_SIZE 12
 #define PLT_ENTRY_WORD1                0xc3800000      /* br   $28, plt0   */
@@ -1857,7 +1904,7 @@ elf64_alpha_read_ecoff_info (abfd, section, debug)
   swap = get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap;
   memset (debug, 0, sizeof (*debug));
 
-  ext_hdr = (char *) bfd_malloc ((size_t) swap->external_hdr_size);
+  ext_hdr = (char *) bfd_malloc (swap->external_hdr_size);
   if (ext_hdr == NULL && swap->external_hdr_size != 0)
     goto error_return;
 
@@ -1876,12 +1923,12 @@ elf64_alpha_read_ecoff_info (abfd, section, debug)
     debug->ptr = NULL;                                                 \
   else                                                                 \
     {                                                                  \
-      debug->ptr = (type) bfd_malloc ((size_t) (size * symhdr->count));        \
+      bfd_size_type amt = (bfd_size_type) size * symhdr->count;                \
+      debug->ptr = (type) bfd_malloc (amt);                            \
       if (debug->ptr == NULL)                                          \
        goto error_return;                                              \
       if (bfd_seek (abfd, (file_ptr) symhdr->offset, SEEK_SET) != 0    \
-         || (bfd_read (debug->ptr, size, symhdr->count,                \
-                       abfd) != size * symhdr->count))                 \
+         || bfd_bread (debug->ptr, amt, abfd) != amt)                  \
        goto error_return;                                              \
     }
 
@@ -1994,9 +2041,9 @@ elf64_alpha_find_nearest_line (abfd, section, symbols, offset, filename_ptr,
          char *fraw_src;
          char *fraw_end;
          struct fdr *fdr_ptr;
+         bfd_size_type amt = sizeof (struct mips_elf_find_line);
 
-         fi = ((struct mips_elf_find_line *)
-               bfd_zalloc (abfd, sizeof (struct mips_elf_find_line)));
+         fi = (struct mips_elf_find_line *) bfd_zalloc (abfd, amt);
          if (fi == NULL)
            {
              msec->flags = origflags;
@@ -2010,10 +2057,8 @@ elf64_alpha_find_nearest_line (abfd, section, symbols, offset, filename_ptr,
            }
 
          /* Swap in the FDR information.  */
-         fi->d.fdr = ((struct fdr *)
-                      bfd_alloc (abfd,
-                                 (fi->d.symbolic_header.ifdMax *
-                                  sizeof (struct fdr))));
+         amt = fi->d.symbolic_header.ifdMax * sizeof (struct fdr);
+         fi->d.fdr = (struct fdr *) bfd_alloc (abfd, amt);
          if (fi->d.fdr == NULL)
            {
              msec->flags = origflags;
@@ -2225,6 +2270,7 @@ elf64_alpha_check_relocs (abfd, info, sec, relocs)
   struct alpha_elf_got_entry **local_got_entries;
   const Elf_Internal_Rela *rel, *relend;
   int got_created;
+  bfd_size_type amt;
 
   if (info->relocateable)
     return true;
@@ -2278,9 +2324,9 @@ elf64_alpha_check_relocs (abfd, info, sec, relocs)
 
                if (!gotent)
                  {
+                   amt = sizeof (struct alpha_elf_got_entry);
                    gotent = ((struct alpha_elf_got_entry *)
-                             bfd_alloc (abfd,
-                                        sizeof (struct alpha_elf_got_entry)));
+                             bfd_alloc (abfd, amt));
                    if (!gotent)
                      return false;
 
@@ -2303,16 +2349,16 @@ elf64_alpha_check_relocs (abfd, info, sec, relocs)
                /* This is a local .got entry -- record for merge.  */
                if (!local_got_entries)
                  {
-                   size_t size;
-                   size = (symtab_hdr->sh_info
-                           * sizeof (struct alpha_elf_got_entry *));
+                   bfd_size_type size;
+                   size = symtab_hdr->sh_info;
+                   size *= sizeof (struct alpha_elf_got_entry *);
 
                    local_got_entries = ((struct alpha_elf_got_entry **)
                                         bfd_alloc (abfd, size));
                    if (!local_got_entries)
                      return false;
 
-                   memset (local_got_entries, 0, size);
+                   memset (local_got_entries, 0, (size_t) size);
                    alpha_elf_tdata (abfd)->local_got_entries =
                      local_got_entries;
                  }
@@ -2323,9 +2369,9 @@ elf64_alpha_check_relocs (abfd, info, sec, relocs)
                  continue;
                if (!gotent)
                  {
+                   amt = sizeof (struct alpha_elf_got_entry);
                    gotent = ((struct alpha_elf_got_entry *)
-                             bfd_alloc (abfd,
-                                        sizeof (struct alpha_elf_got_entry)));
+                             bfd_alloc (abfd, amt));
                    if (!gotent)
                      return false;
 
@@ -2384,6 +2430,7 @@ elf64_alpha_check_relocs (abfd, info, sec, relocs)
        case R_ALPHA_GPREL32:
        case R_ALPHA_GPRELHIGH:
        case R_ALPHA_GPRELLOW:
+       case R_ALPHA_BRSGP:
          /* We don't actually use the .got here, but the sections must
             be created before the linker maps input sections to output
             sections.  */
@@ -2433,17 +2480,15 @@ elf64_alpha_check_relocs (abfd, info, sec, relocs)
              sreloc = bfd_get_section_by_name (dynobj, rel_sec_name);
              if (sreloc == NULL)
                {
+                 flagword flags;
+
                  sreloc = bfd_make_section (dynobj, rel_sec_name);
+                 flags = (SEC_HAS_CONTENTS | SEC_IN_MEMORY
+                          | SEC_LINKER_CREATED | SEC_READONLY);
+                 if (sec->flags & SEC_ALLOC)
+                   flags |= SEC_ALLOC | SEC_LOAD;
                  if (sreloc == NULL
-                     || !bfd_set_section_flags (dynobj, sreloc,
-                                                (((sec->flags
-                                                   & SEC_ALLOC)
-                                                  ? (SEC_ALLOC
-                                                     | SEC_LOAD) : 0)
-                                                 | SEC_HAS_CONTENTS
-                                                 | SEC_IN_MEMORY
-                                                 | SEC_LINKER_CREATED
-                                                 | SEC_READONLY))
+                     || !bfd_set_section_flags (dynobj, sreloc, flags)
                      || !bfd_set_section_alignment (dynobj, sreloc, 3))
                    return false;
                }
@@ -2465,16 +2510,16 @@ elf64_alpha_check_relocs (abfd, info, sec, relocs)
 
              if (!rent)
                {
-                 rent = ((struct alpha_elf_reloc_entry *)
-                         bfd_alloc (abfd,
-                                    sizeof (struct alpha_elf_reloc_entry)));
+                 amt = sizeof (struct alpha_elf_reloc_entry);
+                 rent = (struct alpha_elf_reloc_entry *) bfd_alloc (abfd, amt);
                  if (!rent)
                    return false;
 
                  rent->srel = sreloc;
                  rent->rtype = r_type;
                  rent->count = 1;
-                 rent->reltext = (sec->flags & SEC_READONLY) != 0;
+                 rent->reltext = ((sec->flags & (SEC_READONLY | SEC_ALLOC))
+                                  == (SEC_READONLY | SEC_ALLOC));
 
                  rent->next = h->reloc_entries;
                  h->reloc_entries = rent;
@@ -2518,8 +2563,7 @@ elf64_alpha_adjust_dynamic_symbol (info, h)
   /* Now that we've seen all of the input symbols, finalize our decision
      about whether this symbol should get a .plt entry.  */
 
-  if (h->root.type != bfd_link_hash_undefweak
-      && alpha_elf_dynamic_symbol_p (h, info)
+  if (alpha_elf_dynamic_symbol_p (h, info)
       && ((h->type == STT_FUNC
           && !(ah->flags & ALPHA_ELF_LINK_HASH_LU_ADDR))
          || (h->type == STT_NOTYPE
@@ -2905,7 +2949,7 @@ elf64_alpha_size_got_sections (output_bfd, info)
              /* Yikes! A single object file has too many entries.  */
              (*_bfd_error_handler)
                (_("%s: .got subsegment exceeds 64K (size %d)"),
-                bfd_get_filename (i),
+                bfd_archive_filename (i),
                 alpha_elf_tdata (this_got)->total_got_entries * 8);
              return false;
            }
@@ -3162,7 +3206,7 @@ elf64_alpha_size_dynamic_sections (output_bfd, info)
       else
        {
          /* Allocate memory for the section contents.  */
-         s->contents = (bfd_byte *) bfd_zalloc(dynobj, s->_raw_size);
+         s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->_raw_size);
          if (s->contents == NULL && s->_raw_size != 0)
            return false;
        }
@@ -3175,35 +3219,38 @@ elf64_alpha_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 (! bfd_elf64_add_dynamic_entry (info, DT_PLTGOT, 0))
+      if (!add_dynamic_entry (DT_PLTGOT, 0))
        return false;
 
       if (relplt)
        {
-         if (! 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_PLTRELSZ, 0)
+             || !add_dynamic_entry (DT_PLTREL, DT_RELA)
+             || !add_dynamic_entry (DT_JMPREL, 0))
            return false;
        }
 
-      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 (info->flags & DF_TEXTREL)
        {
-         if (! bfd_elf64_add_dynamic_entry (info, DT_TEXTREL, 0))
+         if (!add_dynamic_entry (DT_TEXTREL, 0))
            return false;
        }
     }
+#undef add_dynamic_entry
 
   return true;
 }
@@ -3265,7 +3312,7 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
       struct alpha_elf_link_hash_entry *h;
       Elf_Internal_Sym *sym;
       bfd_vma relocation;
-      bfd_signed_vma addend;
+      bfd_vma addend;
       bfd_reloc_status_type r;
 
       r_type = ELF64_R_TYPE(rel->r_info);
@@ -3313,9 +3360,7 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
        {
          sym = local_syms + r_symndx;
          sec = local_sections[r_symndx];
-         relocation = (sec->output_section->vma
-                       + sec->output_offset
-                       + sym->st_value);
+         relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel);
        }
       else
        {
@@ -3341,7 +3386,8 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
            }
          else if (h->root.root.type == bfd_link_hash_undefweak)
            relocation = 0;
-         else if (info->shared && !info->symbolic
+         else if (info->shared
+                  && (!info->symbolic || info->allow_shlib_undefined)
                   && !info->no_undefined
                   && ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT)
            relocation = 0;
@@ -3396,6 +3442,38 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
                gotent = (alpha_elf_tdata(input_bfd)->
                          local_got_entries[r_symndx]);
                dynamic_symbol = false;
+
+               /* Need to adjust local GOT entries' addends for SEC_MERGE
+                  unless it has been done already.  */
+               if ((sec->flags & SEC_MERGE)
+                   && ELF_ST_TYPE (sym->st_info) == STT_SECTION
+                   && (elf_section_data (sec)->sec_info_type
+                       == ELF_INFO_TYPE_MERGE)
+                   && (gotent->flags & ALPHA_ELF_GOT_ENTRY_RELOCS_XLATED) == 0)
+                 {
+                   struct alpha_elf_got_entry *ent;
+                   asection *msec;
+
+                   for (ent = gotent; ent; ent = ent->next)
+                     {
+                       ent->flags |= ALPHA_ELF_GOT_ENTRY_RELOCS_XLATED;
+                       if (ent->use_count == 0)
+                         continue;
+                       msec = sec;
+                       ent->addend =
+                         _bfd_merged_section_offset (output_bfd, &msec,
+                                                     elf_section_data (sec)->
+                                                     sec_info,
+                                                     sym->st_value
+                                                     + ent->addend,
+                                                     (bfd_vma) 0);
+                       ent->addend -= sym->st_value;
+                       ent->addend += msec->output_section->vma
+                                      + msec->output_offset
+                                      - sec->output_section->vma
+                                      - sec->output_offset;
+                     }
+                 }
              }
 
            BFD_ASSERT(gotent != NULL);
@@ -3408,7 +3486,7 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
            /* Initialize the .got entry's value.  */
            if (!(gotent->flags & ALPHA_ELF_GOT_ENTRY_RELOCS_DONE))
              {
-               bfd_put_64 (output_bfd, relocation+addend,
+               bfd_put_64 (output_bfd, relocation + addend,
                            sgot->contents + gotent->got_offset);
 
                /* If the symbol has been forced local, output a
@@ -3424,7 +3502,7 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
                                       + sgot->output_offset
                                       + gotent->got_offset);
                    outrel.r_info = ELF64_R_INFO(0, R_ALPHA_RELATIVE);
-                   outrel.r_addend = relocation+addend;
+                   outrel.r_addend = relocation + addend;
 
                    bfd_elf64_swap_reloca_out (output_bfd, &outrel,
                                               ((Elf64_External_Rela *)
@@ -3455,7 +3533,7 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
             {
               (*_bfd_error_handler)
                 (_("%s: gp-relative relocation against dynamic symbol %s"),
-                 bfd_get_filename (input_bfd), h->root.root.root.string);
+                 bfd_archive_filename (input_bfd), h->root.root.root.string);
               ret_val = false;
             }
          BFD_ASSERT(gp != 0);
@@ -3467,7 +3545,7 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
             {
               (*_bfd_error_handler)
                 (_("%s: gp-relative relocation against dynamic symbol %s"),
-                 bfd_get_filename (input_bfd), h->root.root.root.string);
+                 bfd_archive_filename (input_bfd), h->root.root.root.string);
               ret_val = false;
             }
          BFD_ASSERT(gp != 0);
@@ -3494,11 +3572,74 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
          addend -= 4;
          goto default_reloc;
 
+       case R_ALPHA_BRSGP:
+         {
+           int other;
+           const char *name;
+
+           /* The regular PC-relative stuff measures from the start of
+              the instruction rather than the end.  */
+           addend -= 4;
+
+           /* The source and destination gp must be the same.  */
+           if (h != NULL
+               && gotobj != alpha_elf_tdata (sec->owner)->gotobj)
+             {
+               if (h != NULL)
+                 name = h->root.root.root.string;
+               else
+                 {
+                   name = (bfd_elf_string_from_elf_section
+                           (input_bfd, symtab_hdr->sh_link, sym->st_name));
+                   if (name == NULL)
+                     name = _("<unknown>");
+                   else if (name[0] == 0)
+                     name = bfd_section_name (input_bfd, sec);
+                 }
+               (*_bfd_error_handler)
+                 (_("%s: change in gp: BRSGP %s"),
+                  bfd_archive_filename (input_bfd), name);
+               ret_val = false;
+             }
+
+           /* The symbol should be marked either NOPV or STD_GPLOAD.  */
+           if (h != NULL)
+             other = h->root.other;
+           else
+             other = sym->st_other;
+           switch (other & STO_ALPHA_STD_GPLOAD)
+             {
+             case STO_ALPHA_NOPV:
+               break;
+             case STO_ALPHA_STD_GPLOAD:
+               addend += 8;
+               break;
+             default:
+               if (h != NULL)
+                 name = h->root.root.root.string;
+               else
+                 {
+                   name = (bfd_elf_string_from_elf_section
+                           (input_bfd, symtab_hdr->sh_link, sym->st_name));
+                   if (name == NULL)
+                     name = _("<unknown>");
+                   else if (name[0] == 0)
+                     name = bfd_section_name (input_bfd, sec);
+                 }
+               (*_bfd_error_handler)
+                 (_("%s: !samegp reloc against symbol without .prologue: %s"),
+                  bfd_archive_filename (input_bfd), name);
+               ret_val = false;
+               break;
+             }
+
+           goto default_reloc;
+         }
+
        case R_ALPHA_REFLONG:
        case R_ALPHA_REFQUAD:
          {
            Elf_Internal_Rela outrel;
-           boolean skip;
 
            /* Careful here to remember RELATIVE relocations for global
               variables for symbolic shared objects.  */
@@ -3510,7 +3651,9 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
                outrel.r_addend = addend;
                addend = 0, relocation = 0;
              }
-           else if (info->shared && (input_section->flags & SEC_ALLOC))
+           else if (info->shared
+                    && r_symndx != 0
+                    && (input_section->flags & SEC_ALLOC))
              {
                outrel.r_info = ELF64_R_INFO(0, R_ALPHA_RELATIVE);
                outrel.r_addend = relocation + addend;
@@ -3531,25 +3674,10 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
                BFD_ASSERT(srel != NULL);
              }
 
-           skip = false;
-
-           if (elf_section_data (input_section)->stab_info == NULL)
-             outrel.r_offset = rel->r_offset;
-           else
-             {
-               bfd_vma off;
-
-               off = (_bfd_stab_section_offset
-                      (output_bfd, &elf_hash_table (info)->stab_info,
-                       input_section,
-                       &elf_section_data (input_section)->stab_info,
-                       rel->r_offset));
-               if (off == (bfd_vma) -1)
-                 skip = true;
-               outrel.r_offset = off;
-             }
-
-           if (! skip)
+           outrel.r_offset =
+             _bfd_elf_section_offset (output_bfd, info, input_section,
+                                      rel->r_offset);
+           if (outrel.r_offset != (bfd_vma) -1)
              outrel.r_offset += (input_section->output_section->vma
                                  + input_section->output_offset);
            else
@@ -3581,6 +3709,15 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
          {
            const char *name;
 
+           /* Don't warn if the overflow is due to pc relative reloc
+              against discarded section.  Section optimization code should
+              handle it.  */
+
+           if (r_symndx < symtab_hdr->sh_info
+               && sec != NULL && howto->pc_relative
+               && elf_discarded_section (sec))
+             break;
+
            if (h != NULL)
              name = h->root.root.root.string;
            else
@@ -3654,7 +3791,7 @@ elf64_alpha_finish_dynamic_symbol (output_bfd, info, h, sym)
 
       /* Fill in the entry in the procedure linkage table.  */
       {
-       unsigned insn1, insn2, insn3;
+       bfd_vma insn1, insn2, insn3;
 
        insn1 = PLT_ENTRY_WORD1 | ((-(h->plt.offset + 4) >> 2) & 0x1fffff);
        insn2 = PLT_ENTRY_WORD2;
@@ -3840,8 +3977,8 @@ elf64_alpha_finish_dynamic_sections (output_bfd, info)
          bfd_put_32 (output_bfd, PLT_HEADER_WORD4, splt->contents + 12);
 
          /* The next two words will be filled in by ld.so */
-         bfd_put_64 (output_bfd, 0, splt->contents + 16);
-         bfd_put_64 (output_bfd, 0, splt->contents + 24);
+         bfd_put_64 (output_bfd, (bfd_vma) 0, splt->contents + 16);
+         bfd_put_64 (output_bfd, (bfd_vma) 0, splt->contents + 24);
 
          elf_section_data (splt->output_section)->this_hdr.sh_entsize =
            PLT_HEADER_SIZE;
@@ -4103,7 +4240,8 @@ elf64_alpha_final_link (abfd, info)
 
        sgot = alpha_elf_tdata(i)->got;
        if (! bfd_set_section_contents (abfd, sgot->output_section,
-                                       sgot->contents, sgot->output_offset,
+                                       sgot->contents,
+                                       (file_ptr) sgot->output_offset,
                                        sgot->_raw_size))
          return false;
       }
@@ -4124,10 +4262,10 @@ elf64_alpha_final_link (abfd, info)
 }
 
 static enum elf_reloc_type_class
-elf64_alpha_reloc_type_class (type)
-     int type;
+elf64_alpha_reloc_type_class (rela)
+     const Elf_Internal_Rela *rela;
 {
-  switch (type)
+  switch ((int) ELF64_R_TYPE (rela->r_info))
     {
     case R_ALPHA_RELATIVE:
       return reloc_class_relative;
This page took 0.035896 seconds and 4 git commands to generate.