* elf-bfd.h (enum elf_link_info_type): New.
[deliverable/binutils-gdb.git] / bfd / elfxx-ia64.c
index d467a980952e5bc0b3274b7c86f878c1af689701..6abd6909dd7cb60fd87f12b6ceab7cd6defdc4ad 100644 (file)
@@ -111,6 +111,10 @@ struct elfNN_ia64_local_hash_entry
 {
   struct bfd_hash_entry root;
   struct elfNN_ia64_dyn_sym_info *info;
+
+  /* True if this hash entry's addends was translated for
+     SHF_MERGE optimization.  */
+  unsigned sec_merge_done : 1;
 };
 
 struct elfNN_ia64_local_hash_table
@@ -216,6 +220,9 @@ static void elfNN_ia64_dyn_sym_traverse
           PTR info));
 static boolean elfNN_ia64_create_dynamic_sections
   PARAMS ((bfd *abfd, struct bfd_link_info *info));
+static struct elfNN_ia64_local_hash_entry * get_local_sym_hash
+  PARAMS ((struct elfNN_ia64_link_hash_table *ia64_info,
+          bfd *abfd, const Elf_Internal_Rela *rel, boolean create));
 static struct elfNN_ia64_dyn_sym_info * get_dyn_sym_info
   PARAMS ((struct elfNN_ia64_link_hash_table *ia64_info,
           struct elf_link_hash_entry *h,
@@ -922,7 +929,7 @@ elfNN_ia64_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;
        }
     }
 
@@ -1512,8 +1519,8 @@ elfNN_ia64_hash_copy_indirect (xdir, xind)
 {
   struct elfNN_ia64_link_hash_entry *dir, *ind;
 
-  dir = (struct elfNN_ia64_link_hash_entry *)xdir;
-  ind = (struct elfNN_ia64_link_hash_entry *)xind;
+  dir = (struct elfNN_ia64_link_hash_entry *) xdir;
+  ind = (struct elfNN_ia64_link_hash_entry *) xind;
 
   /* Copy down any references that we may have already seen to the
      symbol which just became indirect.  */
@@ -1524,7 +1531,7 @@ elfNN_ia64_hash_copy_indirect (xdir, xind)
         | ELF_LINK_HASH_REF_REGULAR
         | ELF_LINK_HASH_REF_REGULAR_NONWEAK));
 
-  if (dir == ind->weakdef)
+  if (ind->root.root.type != bfd_link_hash_indirect)
     return;
 
   /* Copy over the got and plt data.  This would have been done
@@ -1719,6 +1726,32 @@ elfNN_ia64_create_dynamic_sections (abfd, info)
   return true;
 }
 
+/* Find and/or create a hash entry for local symbol.  */
+static struct elfNN_ia64_local_hash_entry *
+get_local_sym_hash (ia64_info, abfd, rel, create)
+     struct elfNN_ia64_link_hash_table *ia64_info;
+     bfd *abfd;
+     const Elf_Internal_Rela *rel;
+     boolean create;
+{
+  char *addr_name;
+  size_t len;
+
+  /* Construct a string for use in the elfNN_ia64_local_hash_table.
+     name describes what was once anonymous memory.  */
+
+  len = sizeof (void*)*2 + 1 + sizeof (bfd_vma)*4 + 1 + 1;
+  len += 10;   /* %p slop */
+
+  addr_name = alloca (len);
+  sprintf (addr_name, "%p:%lx",
+          (void *) abfd, (unsigned long) ELFNN_R_SYM (rel->r_info));
+
+  /* Collect the canonical entry data for this address.  */
+  return elfNN_ia64_local_hash_lookup (&ia64_info->loc_hash_table,
+                                      addr_name, create, create);
+}
+
 /* Find and/or create a descriptor for dynamic symbol info.  This will
    vary based on global or local symbol, and the addend to the reloc.  */
 
@@ -1739,22 +1772,8 @@ get_dyn_sym_info (ia64_info, h, abfd, rel, create)
   else
     {
       struct elfNN_ia64_local_hash_entry *loc_h;
-      char *addr_name;
-      size_t len;
 
-      /* Construct a string for use in the elfNN_ia64_local_hash_table.
-         The name describes what was once anonymous memory.  */
-
-      len = sizeof (void*)*2 + 1 + sizeof (bfd_vma)*4 + 1 + 1;
-      len += 10;       /* %p slop */
-
-      addr_name = alloca (len);
-      sprintf (addr_name, "%p:%lx",
-              (void *) abfd, (unsigned long) ELFNN_R_SYM (rel->r_info));
-
-      /* Collect the canonical entry data for this address.  */
-      loc_h = elfNN_ia64_local_hash_lookup (&ia64_info->loc_hash_table,
-                                           addr_name, create, create);
+      loc_h = get_local_sym_hash (ia64_info, abfd, rel, create);
       BFD_ASSERT (loc_h);
 
       pp = &loc_h->info;
@@ -2995,33 +3014,19 @@ elfNN_ia64_install_dyn_reloc (abfd, info, sec, srel, offset, type,
 {
   Elf_Internal_Rela outrel;
 
-  outrel.r_offset = (sec->output_section->vma
-                    + sec->output_offset
-                    + offset);
+  offset += sec->output_section->vma + sec->output_offset;
 
   BFD_ASSERT (dynindx != -1);
   outrel.r_info = ELFNN_R_INFO (dynindx, type);
   outrel.r_addend = addend;
-
-  if (elf_section_data (sec)->stab_info != NULL)
+  outrel.r_offset = _bfd_elf_section_offset (abfd, info, sec, offset);
+  if (outrel.r_offset == (bfd_vma) -1)
     {
-      /* This may be NULL for linker-generated relocations, as it is
-        inconvenient to pass all the bits around.  And this shouldn't
-        happen.  */
-      BFD_ASSERT (info != NULL);
-
-      offset = (_bfd_stab_section_offset
-               (abfd, &elf_hash_table (info)->stab_info, sec,
-                &elf_section_data (sec)->stab_info, offset));
-      if (offset == (bfd_vma) -1)
-       {
-         /* Run for the hills.  We shouldn't be outputting a relocation
-            for this.  So do what everyone else does and output a no-op.  */
-         outrel.r_info = ELFNN_R_INFO (0, R_IA64_NONE);
-         outrel.r_addend = 0;
-         offset = 0;
-       }
-      outrel.r_offset = offset;
+      /* Run for the hills.  We shouldn't be outputting a relocation
+        for this.  So do what everyone else does and output a no-op.  */
+      outrel.r_info = ELFNN_R_INFO (0, R_IA64_NONE);
+      outrel.r_addend = 0;
+      outrel.r_offset = 0;
     }
 
   bfd_elfNN_swap_reloca_out (abfd, &outrel,
@@ -3481,9 +3486,39 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
          /* Reloc against local symbol.  */
          sym = local_syms + r_symndx;
          sym_sec = local_sections[r_symndx];
-         value  = (sym_sec->output_section->vma
-                   + sym_sec->output_offset
-                   + sym->st_value);
+         value = _bfd_elf_rela_local_sym (output_bfd, sym, sym_sec, rel);
+         if ((sym_sec->flags & SEC_MERGE)
+             && ELF_ST_TYPE (sym->st_info) == STT_SECTION
+             && (elf_section_data (sym_sec)->sec_info_type
+                 == ELF_INFO_TYPE_MERGE))
+           {
+             struct elfNN_ia64_local_hash_entry *loc_h;
+      
+             loc_h = get_local_sym_hash (ia64_info, input_bfd, rel, false);
+             if (loc_h && ! loc_h->sec_merge_done)
+               {
+                 struct elfNN_ia64_dyn_sym_info *dynent;
+                 asection *msec;
+
+                 for (dynent = loc_h->info; dynent; dynent = dynent->next)
+                   {
+                     msec = sym_sec;
+                     dynent->addend =
+                       _bfd_merged_section_offset (output_bfd, &msec,
+                                                   elf_section_data (msec)->
+                                                   sec_info,
+                                                   sym->st_value
+                                                   + dynent->addend,
+                                                   (bfd_vma) 0);
+                     dynent->addend -= sym->st_value;
+                     dynent->addend += msec->output_section->vma
+                                       + msec->output_offset
+                                       - sym_sec->output_section->vma
+                                       - sym_sec->output_offset;
+                   }
+                 loc_h->sec_merge_done = 1;
+               }
+           }
        }
       else
        {
@@ -3560,6 +3595,7 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
                   /* Don't emit relocs for __GLOB_DATA_PTR on AIX. */
                   && (!h || strcmp (h->root.root.string,
                                     "__GLOB_DATA_PTR") != 0)))
+             && r_symndx != 0
              && (input_section->flags & SEC_ALLOC) != 0)
            {
              unsigned int dyn_r_type;
@@ -3754,8 +3790,9 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
        case R_IA64_PCREL64MSB:
        case R_IA64_PCREL64LSB:
          /* Install a dynamic relocation for this reloc.  */
-         if (dynamic_symbol_p
-             || elfNN_ia64_aix_vec (info->hash->creator))
+         if ((dynamic_symbol_p
+              || elfNN_ia64_aix_vec (info->hash->creator))
+             && r_symndx != 0)
            {
              BFD_ASSERT (srel != NULL);
 
@@ -3833,47 +3870,48 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
        case R_IA64_SEGREL32LSB:
        case R_IA64_SEGREL64MSB:
        case R_IA64_SEGREL64LSB:
-         {
-           struct elf_segment_map *m;
-           Elf_Internal_Phdr *p;
-
-           /* Find the segment that contains the output_section.  */
-           for (m = elf_tdata (output_bfd)->segment_map,
-                  p = elf_tdata (output_bfd)->phdr;
-                m != NULL;
-                m = m->next, p++)
-             {
-               int i;
-               for (i = m->count - 1; i >= 0; i--)
-                 if (m->sections[i] == sym_sec->output_section)
+         if (r_symndx == 0)
+           {
+             /* If the input section was discarded from the output, then
+                do nothing.  */
+             r = bfd_reloc_ok;
+           }
+         else
+           {
+             struct elf_segment_map *m;
+             Elf_Internal_Phdr *p;
+
+             /* Find the segment that contains the output_section.  */
+             for (m = elf_tdata (output_bfd)->segment_map,
+                    p = elf_tdata (output_bfd)->phdr;
+                  m != NULL;
+                  m = m->next, p++)
+               {
+                 int i;
+                 for (i = m->count - 1; i >= 0; i--)
+                   if (m->sections[i] == sym_sec->output_section)
+                     break;
+                 if (i >= 0)
                    break;
-               if (i >= 0)
-                 break;
-             }
-
-           if (m == NULL)
-             {
-               /* If the input section was discarded from the output, then
-                  do nothing.  */
+               }
 
-               if (bfd_is_abs_section (sym_sec->output_section))
-                 r = bfd_reloc_ok;
-               else
+             if (m == NULL)
+               {
                  r = bfd_reloc_notsupported;
-             }
-           else
-             {
-               /* The VMA of the segment is the vaddr of the associated
-                  program header.  */
-               if (value > p->p_vaddr)
-                 value -= p->p_vaddr;
-               else
-                 value = 0;
-               r = elfNN_ia64_install_value (output_bfd, hit_addr, value,
-                                             r_type);
-             }
-           break;
-         }
+               }
+             else
+               {
+                 /* The VMA of the segment is the vaddr of the associated
+                    program header.  */
+                 if (value > p->p_vaddr)
+                   value -= p->p_vaddr;
+                 else
+                   value = 0;
+                 r = elfNN_ia64_install_value (output_bfd, hit_addr, value,
+                                               r_type);
+               }
+             break;
+           }
 
        case R_IA64_SECREL32MSB:
        case R_IA64_SECREL32LSB:
This page took 0.040705 seconds and 4 git commands to generate.