* Makefile.am: Run "make dep-am".
[deliverable/binutils-gdb.git] / bfd / elf64-alpha.c
index 783f01030805b9d9dc304805258d2955c089e0b5..2c380d6a19b74dae16ec6bedc62ced180fe41c59 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>.
 
@@ -170,8 +170,9 @@ struct alpha_elf_link_hash_entry
 
     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;
@@ -731,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.  */
@@ -885,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.  */
@@ -940,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
 {
@@ -1361,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;
 
@@ -1447,17 +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_bread (extsyms, 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;
            }
        }
@@ -1466,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;
@@ -1565,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)
@@ -1585,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;
@@ -2389,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.  */
@@ -2476,7 +2518,8 @@ elf64_alpha_check_relocs (abfd, info, sec, relocs)
                  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;
@@ -2520,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
@@ -3400,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);
@@ -3498,11 +3572,68 @@ 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.  Note that
+              the source will always have an assigned gp, since we forced
+              one in check_relocs, but that the destination may not, as
+              it might not have had any relocations at all.  Also take 
+              care not to crash if H is an undefined symbol.  */
+           if (h != NULL && sec != NULL
+               && alpha_elf_tdata (sec->owner)->gotobj
+               && gotobj != alpha_elf_tdata (sec->owner)->gotobj)
+             {
+               (*_bfd_error_handler)
+                 (_("%s: change in gp: BRSGP %s"),
+                  bfd_archive_filename (input_bfd), h->root.root.root.string);
+               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.  */
@@ -3537,25 +3668,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 | 1) != (bfd_vma) -1)
              outrel.r_offset += (input_section->output_section->vma
                                  + input_section->output_offset);
            else
@@ -3587,6 +3703,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
@@ -3974,7 +4099,7 @@ elf64_alpha_final_link (abfd, info)
 
              if (p->type != bfd_indirect_link_order)
                {
-                 if (p->type == bfd_fill_link_order)
+                 if (p->type == bfd_data_link_order)
                    continue;
                  abort ();
                }
This page took 0.028396 seconds and 4 git commands to generate.