2009-11-17 H.J. Lu <hongjiu.lu@intel.com>
authorH.J. Lu <hjl.tools@gmail.com>
Tue, 17 Nov 2009 19:21:53 +0000 (19:21 +0000)
committerH.J. Lu <hjl.tools@gmail.com>
Tue, 17 Nov 2009 19:21:53 +0000 (19:21 +0000)
PR ld/10955
* elfxx-ia64.c (elfNN_ia64_link_hash_table): Add max_short_sec,
max_short_offset, min_short_sec and min_short_offset.
(elfNN_ia64_update_short_info): New.
(elfNN_ia64_relax_section): Update max_short_sec,
max_short_offset, min_short_sec and min_short_offset.
(elfNN_ia64_choose_gp): Use min_short_sec/max_short_sec if
they are set.

bfd/ChangeLog
bfd/elfxx-ia64.c

index 6166526e9a975c1f4b73fd600aaa68e705cdebf2..113ddf8e41ad8f3d695bfc57d277061fa475e616 100644 (file)
@@ -1,5 +1,16 @@
+2009-11-17  H.J. Lu  <hongjiu.lu@intel.com>
+
+       PR ld/10955
+       * elfxx-ia64.c (elfNN_ia64_link_hash_table): Add max_short_sec,
+       max_short_offset, min_short_sec and min_short_offset.
+       (elfNN_ia64_update_short_info): New.
+       (elfNN_ia64_relax_section): Update max_short_sec,
+       max_short_offset, min_short_sec and min_short_offset.
+       (elfNN_ia64_choose_gp): Use min_short_sec/max_short_sec if
+       they are set.
+
 2009-11-17  Paul Brook  <paul@codesourcery.com>
-       Daniel Jacobowitz  <dan@codesourcery.com>
+           Daniel Jacobowitz  <dan@codesourcery.com>
 
        * elf32-arm.c (using_thumb_only, arch_has_arm_nop,
        arch_has_thumb2_nop): Handle TAG_CPU_ARCH_V7E_M.
index 932886b38af7e7b3004f68e93222b4905dd710d8..5bf4d9e444b7d0c63e28178954c2c249ddfcea34 100644 (file)
@@ -172,6 +172,14 @@ struct elfNN_ia64_link_hash_table
   unsigned reltext : 1;                /* are there relocs against readonly sections? */
   unsigned self_dtpmod_done : 1;/* has self DTPMOD entry been finished? */
   bfd_vma self_dtpmod_offset;  /* .got offset to self DTPMOD entry */
+  /* There are maybe R_IA64_GPREL22 relocations, including those
+     optimized from R_IA64_LTOFF22X, against non-SHF_IA_64_SHORT
+     sections.  We need to record those sections so that we can choose
+     a proper GP to cover all R_IA64_GPREL22 relocations.  */
+  asection *max_short_sec;     /* maximum short section */
+  bfd_vma max_short_offset;    /* maximum short offset */
+  asection *min_short_sec;     /* minimum short section */
+  bfd_vma min_short_offset;    /* minimum short offset */
 
   htab_t loc_hash_table;
   void *loc_hash_memory;
@@ -752,6 +760,41 @@ elfNN_ia64_relax_brl (bfd_byte *contents, bfd_vma off)
 \f
 /* These functions do relaxation for IA-64 ELF.  */
 
+static void
+elfNN_ia64_update_short_info (asection *sec, bfd_vma offset,
+                             struct elfNN_ia64_link_hash_table *ia64_info)
+{
+  /* Skip SHF_IA_64_SHORT sections.  */
+  if (sec->flags & SEC_SMALL_DATA)
+    return;
+
+  if (!ia64_info->min_short_sec)
+    {
+      ia64_info->max_short_sec = sec;
+      ia64_info->max_short_offset = offset;
+      ia64_info->min_short_sec = sec;
+      ia64_info->min_short_offset = offset;
+    }
+  else if (sec == ia64_info->max_short_sec
+          && offset > ia64_info->max_short_offset)
+    ia64_info->max_short_offset = offset;
+  else if (sec == ia64_info->min_short_sec
+          && offset < ia64_info->min_short_offset)
+    ia64_info->min_short_offset = offset;
+  else if (sec->output_section->vma
+          > ia64_info->max_short_sec->output_section->vma)
+    {
+      ia64_info->max_short_sec = sec;
+      ia64_info->max_short_offset = offset;
+    }
+  else if (sec->output_section->vma
+          < ia64_info->min_short_sec->output_section->vma)
+    {
+      ia64_info->min_short_sec = sec;
+      ia64_info->min_short_offset = offset;
+    }
+}
+
 static bfd_boolean
 elfNN_ia64_relax_section (bfd *abfd, asection *sec,
                          struct bfd_link_info *link_info,
@@ -855,6 +898,9 @@ elfNN_ia64_relax_section (bfd *abfd, asection *sec,
          is_branch = TRUE;
          break;
 
+       case R_IA64_GPREL22:
+         /* Update max_short_sec/min_short_sec.  */
+
        case R_IA64_LTOFF22X:
        case R_IA64_LDXMOV:
          /* We can't relax ldx/mov in pass 0 since br relaxations will
@@ -1171,7 +1217,11 @@ elfNN_ia64_relax_section (bfd *abfd, asection *sec,
              ||(bfd_signed_vma) (symaddr - gp) < -0x200000)
            continue;
 
-         if (r_type == R_IA64_LTOFF22X)
+         if (r_type == R_IA64_GPREL22)
+           elfNN_ia64_update_short_info (tsec,
+                                         tsec->output_offset + toff,
+                                         ia64_info);
+         else if (r_type == R_IA64_LTOFF22X)
            {
              irel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info),
                                           R_IA64_GPREL22);
@@ -1181,6 +1231,10 @@ elfNN_ia64_relax_section (bfd *abfd, asection *sec,
                  dyn_i->want_gotx = 0;
                  changed_got |= !dyn_i->want_got;
                }
+
+             elfNN_ia64_update_short_info (tsec,
+                                           tsec->output_offset + toff,
+                                           ia64_info);
            }
          else
            {
@@ -4256,6 +4310,20 @@ elfNN_ia64_choose_gp (bfd *abfd, struct bfd_link_info *info)
        }
     }
 
+  if (ia64_info->min_short_sec)
+    {
+      if (min_short_vma 
+         > (ia64_info->min_short_sec->output_section->vma
+            + ia64_info->min_short_offset))
+       min_short_vma = (ia64_info->min_short_sec->output_section->vma
+                        + ia64_info->min_short_offset);
+      if (max_short_vma
+         < (ia64_info->max_short_sec->output_section->vma
+            + ia64_info->max_short_offset))
+       max_short_vma = (ia64_info->max_short_sec->output_section->vma
+                        + ia64_info->max_short_offset);
+    }
+
   /* See if the user wants to force a value.  */
   gp = elf_link_hash_lookup (elf_hash_table (info), "__gp", FALSE,
                             FALSE, FALSE);
@@ -4273,17 +4341,30 @@ elfNN_ia64_choose_gp (bfd *abfd, struct bfd_link_info *info)
     {
       /* Pick a sensible value.  */
 
-      asection *got_sec = ia64_info->root.sgot;
+      if (ia64_info->min_short_sec)
+       {
+         bfd_vma short_range = max_short_vma - min_short_vma;
 
-      /* Start with just the address of the .got.  */
-      if (got_sec)
-       gp_val = got_sec->output_section->vma;
-      else if (max_short_vma != 0)
-       gp_val = min_short_vma;
-      else if (max_vma - min_vma < 0x200000)
-       gp_val = min_vma;
+         /* If min_short_sec is set, pick one in the middle bewteen
+            min_short_vma and max_short_vma.  */
+         if (short_range >= 0x400000)
+           goto overflow;
+         gp_val = min_short_vma + short_range / 2;
+       }
       else
-       gp_val = max_vma - 0x200000 + 8;
+       {
+         asection *got_sec = ia64_info->root.sgot;
+
+         /* Start with just the address of the .got.  */
+         if (got_sec)
+           gp_val = got_sec->output_section->vma;
+         else if (max_short_vma != 0)
+           gp_val = min_short_vma;
+         else if (max_vma - min_vma < 0x200000)
+           gp_val = min_vma;
+         else
+           gp_val = max_vma - 0x200000 + 8;
+       }
 
       /* If it is possible to address the entire image, but we
         don't with the choice above, adjust.  */
@@ -4310,6 +4391,7 @@ elfNN_ia64_choose_gp (bfd *abfd, struct bfd_link_info *info)
     {
       if (max_short_vma - min_short_vma >= 0x400000)
        {
+overflow:
          (*_bfd_error_handler)
            (_("%s: short data segment overflowed (0x%lx >= 0x400000)"),
             bfd_get_filename (abfd),