This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

ia64 ltoff22x/ldxmov relaxation


Still misses reducing the size of the relocation sections.  Doesn't
affect correctness since we get R_IA64_NONE relocs here.  I'll need
to reorganize the code that lays out relocations to fix this.

Also misses properly choosing a new gp when jump buffers are added.
Technically this is a potential correctness issue.  Failures will
be caught by relocate_section in the form of GPREL22 overflows.
However this should should work well in practice because of the default
2**61 byte separation of the text and data segments in executables.
In order for this to be fixed, I need a callback from the main ld
relaxation loop at the start of a new round of relaxation.

Which brings me to my next point.  David, is there any *good* reason
to have this 2**61 byte separation?  If we did not have it, then the
4MB block spanned by the gp would cover at least part of the .rodata
section on many programs, which would allow us to optimize address
loads of string constants and the like.


r~


        * elfxx-ia64.c (struct elfNN_ia64_dyn_sym_info): Add want_gotx;
        (elfNN_ia64_check_relocs): Set it.
        (allocate_global_data_got): Check it.
        (allocate_local_got): Likewise.
        (allocate_dynrel_entries): Likewise.
        (elfNN_ia64_relax_ldxmov): New.
        (elfNN_ia64_relax_section): Handle LTOFF22X, LDXMOV.
        (elfNN_ia64_choose_gp): Split out from ...
        (elfNN_ia64_final_link): ... here.

Index: bfd/elfxx-ia64.c
===================================================================
RCS file: /cvs/src/src/bfd/elfxx-ia64.c,v
retrieving revision 1.68
diff -u -p -c -r1.68 elfxx-ia64.c
*** bfd/elfxx-ia64.c	17 Feb 2003 18:24:40 -0000	1.68
--- bfd/elfxx-ia64.c	28 Feb 2003 00:17:43 -0000
*************** struct elfNN_ia64_dyn_sym_info
*** 102,107 ****
--- 102,108 ----
  
    /* TRUE for the different kinds of linker data we want created.  */
    unsigned want_got : 1;
+   unsigned want_gotx : 1;
    unsigned want_fptr : 1;
    unsigned want_ltoff_fptr : 1;
    unsigned want_plt : 1;
*************** struct elfNN_ia64_link_hash_table
*** 154,159 ****
--- 155,166 ----
    struct elfNN_ia64_local_hash_table loc_hash_table;
  };
  
+ struct elfNN_ia64_allocate_data
+ {
+   struct bfd_link_info *info;
+   bfd_size_type ofs;
+ };
+ 
  #define elfNN_ia64_hash_table(p) \
    ((struct elfNN_ia64_link_hash_table *) ((p)->hash))
  
*************** static void elfNN_ia64_info_to_howto
*** 169,174 ****
--- 176,183 ----
  static bfd_boolean elfNN_ia64_relax_section
    PARAMS((bfd *abfd, asection *sec, struct bfd_link_info *link_info,
  	  bfd_boolean *again));
+ static void elfNN_ia64_relax_ldxmov
+   PARAMS((bfd *abfd, bfd_byte *contents, bfd_vma off));
  static bfd_boolean is_unwind_section_name
    PARAMS ((bfd *abfd, const char *));
  static bfd_boolean elfNN_ia64_section_from_shdr
*************** static bfd_vma elfNN_ia64_dtprel_base
*** 299,304 ****
--- 308,315 ----
    PARAMS ((struct bfd_link_info *info));
  static int elfNN_ia64_unwind_entry_compare
    PARAMS ((const PTR, const PTR));
+ static bfd_boolean elfNN_ia64_choose_gp
+   PARAMS ((bfd *abfd, struct bfd_link_info *info));
  static bfd_boolean elfNN_ia64_final_link
    PARAMS ((bfd *abfd, struct bfd_link_info *info));
  static bfd_boolean elfNN_ia64_relocate_section
*************** static const bfd_byte oor_ip[48] =
*** 671,681 ****
  };
  #endif
  
! /* These functions do relaxation for IA-64 ELF.
! 
!    This is primarily to support branches to targets out of range;
!    relaxation of R_IA64_LTOFF22X and R_IA64_LDXMOV is handled in
!    relocate_section directly.  */
  
  static bfd_boolean
  elfNN_ia64_relax_section (abfd, sec, link_info, again)
--- 682,688 ----
  };
  #endif
  
! /* These functions do relaxation for IA-64 ELF.  */
  
  static bfd_boolean
  elfNN_ia64_relax_section (abfd, sec, link_info, again)
*************** elfNN_ia64_relax_section (abfd, sec, lin
*** 701,706 ****
--- 708,715 ----
    struct one_fixup *fixups = NULL;
    bfd_boolean changed_contents = FALSE;
    bfd_boolean changed_relocs = FALSE;
+   bfd_boolean changed_got = FALSE;
+   bfd_vma gp = 0;
  
    /* Assume we're not going to change any sizes, and we'll only need
       one pass.  */
*************** elfNN_ia64_relax_section (abfd, sec, lin
*** 728,751 ****
    ia64_info = elfNN_ia64_hash_table (link_info);
    irelend = internal_relocs + sec->reloc_count;
  
-   for (irel = internal_relocs; irel < irelend; irel++)
-     {
-       unsigned long r_type = ELFNN_R_TYPE (irel->r_info);
-       if (r_type == R_IA64_PCREL21B
- 	  || r_type == R_IA64_PCREL21BI
- 	  || r_type == R_IA64_PCREL21M
- 	  || r_type == R_IA64_PCREL21F)
- 	break;
-     }
- 
-   /* No branch-type relocations.  */
-   if (irel == irelend)
-     {
-       if (elf_section_data (sec)->relocs != internal_relocs)
- 	free (internal_relocs);
-       return TRUE;
-     }
- 
    /* Get the section contents.  */
    if (elf_section_data (sec)->this_hdr.contents != NULL)
      contents = elf_section_data (sec)->this_hdr.contents;
--- 737,742 ----
*************** elfNN_ia64_relax_section (abfd, sec, lin
*** 760,778 ****
  	goto error_return;
      }
  
!   for (; irel < irelend; irel++)
      {
        unsigned long r_type = ELFNN_R_TYPE (irel->r_info);
        bfd_vma symaddr, reladdr, trampoff, toff, roff;
        asection *tsec;
        struct one_fixup *f;
        bfd_size_type amt;
  
!       if (r_type != R_IA64_PCREL21B
! 	  && r_type != R_IA64_PCREL21BI
! 	  && r_type != R_IA64_PCREL21M
! 	  && r_type != R_IA64_PCREL21F)
! 	continue;
  
        /* Get the value of the symbol referred to by the reloc.  */
        if (ELFNN_R_SYM (irel->r_info) < symtab_hdr->sh_info)
--- 751,783 ----
  	goto error_return;
      }
  
!   for (irel = internal_relocs; irel < irelend; irel++)
      {
        unsigned long r_type = ELFNN_R_TYPE (irel->r_info);
        bfd_vma symaddr, reladdr, trampoff, toff, roff;
        asection *tsec;
        struct one_fixup *f;
        bfd_size_type amt;
+       bfd_boolean is_branch;
+       struct elfNN_ia64_dyn_sym_info *dyn_i;
  
!       switch (r_type)
! 	{
! 	case R_IA64_PCREL21B:
! 	case R_IA64_PCREL21BI:
! 	case R_IA64_PCREL21M:
! 	case R_IA64_PCREL21F:
! 	  is_branch = TRUE;
! 	  break;
! 
! 	case R_IA64_LTOFF22X:
! 	case R_IA64_LDXMOV:
! 	  is_branch = FALSE;
! 	  break;
! 
! 	default:
! 	  continue;
! 	}
  
        /* Get the value of the symbol referred to by the reloc.  */
        if (ELFNN_R_SYM (irel->r_info) < symtab_hdr->sh_info)
*************** elfNN_ia64_relax_section (abfd, sec, lin
*** 805,816 ****
  	    tsec = bfd_section_from_elf_index (abfd, isym->st_shndx);
  
  	  toff = isym->st_value;
  	}
        else
  	{
  	  unsigned long indx;
  	  struct elf_link_hash_entry *h;
-           struct elfNN_ia64_dyn_sym_info *dyn_i;
  
  	  indx = ELFNN_R_SYM (irel->r_info) - symtab_hdr->sh_info;
  	  h = elf_sym_hashes (abfd)[indx];
--- 810,821 ----
  	    tsec = bfd_section_from_elf_index (abfd, isym->st_shndx);
  
  	  toff = isym->st_value;
+ 	  dyn_i = get_dyn_sym_info (ia64_info, NULL, abfd, irel, FALSE);
  	}
        else
  	{
  	  unsigned long indx;
  	  struct elf_link_hash_entry *h;
  
  	  indx = ELFNN_R_SYM (irel->r_info) - symtab_hdr->sh_info;
  	  h = elf_sym_hashes (abfd)[indx];
*************** elfNN_ia64_relax_section (abfd, sec, lin
*** 824,830 ****
  
  	  /* For branches to dynamic symbols, we're interested instead
  	     in a branch to the PLT entry.  */
! 	  if (dyn_i && dyn_i->want_plt2)
  	    {
  	      /* Internal branches shouldn't be sent to the PLT.
  		 Leave this for now and we'll give an error later.  */
--- 829,835 ----
  
  	  /* For branches to dynamic symbols, we're interested instead
  	     in a branch to the PLT entry.  */
! 	  if (is_branch && dyn_i && dyn_i->want_plt2)
  	    {
  	      /* Internal branches shouldn't be sent to the PLT.
  		 Leave this for now and we'll give an error later.  */
*************** elfNN_ia64_relax_section (abfd, sec, lin
*** 834,839 ****
--- 839,849 ----
  	      tsec = ia64_info->plt_sec;
  	      toff = dyn_i->plt2_offset;
  	    }
+ 
+ 	  /* Can't do anything else with dynamic symbols.  */
+ 	  else if (elfNN_ia64_dynamic_symbol_p (h, link_info))
+ 	    continue;
+ 
  	  else
  	    {
  	      /* We can't do anthing with undefined symbols.  */
*************** elfNN_ia64_relax_section (abfd, sec, lin
*** 852,954 ****
  		 + irel->r_addend);
  
        roff = irel->r_offset;
-       reladdr = (sec->output_section->vma
- 		 + sec->output_offset
- 		 + roff) & (bfd_vma) -4;
- 
-       /* If the branch is in range, no need to do anything.  */
-       if ((bfd_signed_vma) (symaddr - reladdr) >= -0x1000000
- 	  && (bfd_signed_vma) (symaddr - reladdr) <= 0x0FFFFF0)
- 	continue;
- 
-       /* If the branch and target are in the same section, you've
- 	 got one honking big section and we can't help you.  You'll
- 	 get an error message later.  */
-       if (tsec == sec)
- 	continue;
- 
-       /* Look for an existing fixup to this address.  */
-       for (f = fixups; f ; f = f->next)
- 	if (f->tsec == tsec && f->toff == toff)
- 	  break;
  
!       if (f == NULL)
  	{
! 	  /* Two alternatives: If it's a branch to a PLT entry, we can
! 	     make a copy of the FULL_PLT entry.  Otherwise, we'll have
! 	     to use a `brl' insn to get where we're going.  */
  
! 	  size_t size;
  
! 	  if (tsec == ia64_info->plt_sec)
! 	    size = sizeof (plt_full_entry);
! 	  else
  	    {
  #ifdef USE_BRL
! 	      size = sizeof (oor_brl);
  #else
! 	      size = sizeof (oor_ip);
  #endif
! 	    }
  
! 	  /* Resize the current section to make room for the new branch.  */
! 	  trampoff = (sec->_cooked_size + 15) & (bfd_vma) -16;
! 	  amt = trampoff + size;
! 	  contents = (bfd_byte *) bfd_realloc (contents, amt);
! 	  if (contents == NULL)
! 	    goto error_return;
! 	  sec->_cooked_size = amt;
  
! 	  if (tsec == ia64_info->plt_sec)
! 	    {
! 	      memcpy (contents + trampoff, plt_full_entry, size);
  
! 	      /* Hijack the old relocation for use as the PLTOFF reloc.  */
! 	      irel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info),
! 					   R_IA64_PLTOFF22);
! 	      irel->r_offset = trampoff;
! 	    }
! 	  else
! 	    {
  #ifdef USE_BRL
! 	      memcpy (contents + trampoff, oor_brl, size);
! 	      irel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info),
! 					   R_IA64_PCREL60B);
! 	      irel->r_offset = trampoff + 2;
  #else
! 	      memcpy (contents + trampoff, oor_ip, size);
! 	      irel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info),
! 					   R_IA64_PCREL64I);
! 	      irel->r_addend -= 16;
! 	      irel->r_offset = trampoff + 2;
  #endif
  	    }
  
! 	  /* Record the fixup so we don't do it again this section.  */
! 	  f = (struct one_fixup *) bfd_malloc ((bfd_size_type) sizeof (*f));
! 	  f->next = fixups;
! 	  f->tsec = tsec;
! 	  f->toff = toff;
! 	  f->trampoff = trampoff;
! 	  fixups = f;
  	}
        else
  	{
! 	  /* Nop out the reloc, since we're finalizing things here.  */
! 	  irel->r_info = ELFNN_R_INFO (0, R_IA64_NONE);
! 	}
  
!       /* Fix up the existing branch to hit the trampoline.  Hope like
! 	 hell this doesn't overflow too.  */
!       if (elfNN_ia64_install_value (abfd, contents + roff,
! 				    f->trampoff - (roff & (bfd_vma) -4),
! 				    r_type) != bfd_reloc_ok)
! 	goto error_return;
  
!       changed_contents = TRUE;
!       changed_relocs = TRUE;
      }
  
    /* Clean up and go home.  */
    while (fixups)
      {
--- 862,1013 ----
  		 + irel->r_addend);
  
        roff = irel->r_offset;
  
!       if (is_branch)
  	{
! 	  reladdr = (sec->output_section->vma
! 		     + sec->output_offset
! 		     + roff) & (bfd_vma) -4;
! 
! 	  /* If the branch is in range, no need to do anything.  */
! 	  if ((bfd_signed_vma) (symaddr - reladdr) >= -0x1000000
! 	      && (bfd_signed_vma) (symaddr - reladdr) <= 0x0FFFFF0)
! 	    continue;
  
! 	  /* If the branch and target are in the same section, you've
! 	     got one honking big section and we can't help you.  You'll
! 	     get an error message later.  */
! 	  if (tsec == sec)
! 	    continue;
  
! 	  /* Look for an existing fixup to this address.  */
! 	  for (f = fixups; f ; f = f->next)
! 	    if (f->tsec == tsec && f->toff == toff)
! 	      break;
! 
! 	  if (f == NULL)
  	    {
+ 	      /* Two alternatives: If it's a branch to a PLT entry, we can
+ 		 make a copy of the FULL_PLT entry.  Otherwise, we'll have
+ 		 to use a `brl' insn to get where we're going.  */
+ 
+ 	      size_t size;
+ 
+ 	      if (tsec == ia64_info->plt_sec)
+ 		size = sizeof (plt_full_entry);
+ 	      else
+ 		{
  #ifdef USE_BRL
! 		  size = sizeof (oor_brl);
  #else
! 		  size = sizeof (oor_ip);
  #endif
! 		}
  
! 	      /* Resize the current section to make room for the new branch. */
! 	      trampoff = (sec->_cooked_size + 15) & (bfd_vma) -16;
! 	      amt = trampoff + size;
! 	      contents = (bfd_byte *) bfd_realloc (contents, amt);
! 	      if (contents == NULL)
! 		goto error_return;
! 	      sec->_cooked_size = amt;
  
! 	      if (tsec == ia64_info->plt_sec)
! 		{
! 		  memcpy (contents + trampoff, plt_full_entry, size);
  
! 		  /* Hijack the old relocation for use as the PLTOFF reloc.  */
! 		  irel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info),
! 					       R_IA64_PLTOFF22);
! 		  irel->r_offset = trampoff;
! 		}
! 	      else
! 		{
  #ifdef USE_BRL
! 		  memcpy (contents + trampoff, oor_brl, size);
! 		  irel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info),
! 					       R_IA64_PCREL60B);
! 		  irel->r_offset = trampoff + 2;
  #else
! 		  memcpy (contents + trampoff, oor_ip, size);
! 		  irel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info),
! 					       R_IA64_PCREL64I);
! 		  irel->r_addend -= 16;
! 		  irel->r_offset = trampoff + 2;
  #endif
+ 		}
+ 
+ 	      /* Record the fixup so we don't do it again this section.  */
+ 	      f = (struct one_fixup *)
+ 		bfd_malloc ((bfd_size_type) sizeof (*f));
+ 	      f->next = fixups;
+ 	      f->tsec = tsec;
+ 	      f->toff = toff;
+ 	      f->trampoff = trampoff;
+ 	      fixups = f;
  	    }
+ 	  else
+ 	    {
+ 	      /* Nop out the reloc, since we're finalizing things here.  */
+ 	      irel->r_info = ELFNN_R_INFO (0, R_IA64_NONE);
+ 	    }
+ 
+ 	  /* Fix up the existing branch to hit the trampoline.  Hope like
+ 	     hell this doesn't overflow too.  */
+ 	  if (elfNN_ia64_install_value (abfd, contents + roff,
+ 					f->trampoff - (roff & (bfd_vma) -4),
+ 					r_type) != bfd_reloc_ok)
+ 	    goto error_return;
  
! 	  changed_contents = TRUE;
! 	  changed_relocs = TRUE;
  	}
        else
  	{
! 	  /* Fetch the gp.  */
! 	  if (gp == 0)
! 	    {
! 	      bfd *obfd = sec->output_section->owner;
! 	      gp = _bfd_get_gp_value (obfd);
! 	      if (gp == 0)
! 		{
! 		  if (!elfNN_ia64_choose_gp (obfd, link_info))
! 		    goto error_return;
! 		  gp = _bfd_get_gp_value (obfd);
! 		}
! 	    }
  
! 	  /* If the data is out of range, do nothing.  */
! 	  if ((bfd_signed_vma) (symaddr - gp) >= 0x400000
! 	      ||(bfd_signed_vma) (symaddr - gp) < -0x400000)
! 	    continue;
  
! 	  if (r_type == R_IA64_LTOFF22X)
! 	    {
! 	      irel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info),
! 					   R_IA64_GPREL22);
! 	      changed_relocs = TRUE;
! 	      if (dyn_i->want_gotx)
! 		{
! 		  dyn_i->want_gotx = 0;
! 		  changed_got |= !dyn_i->want_got;
! 		}
! 	    }
! 	  else
! 	    {
! 	      elfNN_ia64_relax_ldxmov (abfd, contents, roff);
! 	      irel->r_info = ELFNN_R_INFO (0, R_IA64_NONE);
! 	      changed_contents = TRUE;
! 	      changed_relocs = TRUE;
! 	    }
! 	}
      }
  
+   /* ??? If we created fixups, this may push the code segment large
+      enough that the data segment moves, which will change the GP.
+      Reset the GP so that we re-calculate next round.  We need to
+      do this at the _beginning_ of the next round; now will not do.  */
+       
    /* Clean up and go home.  */
    while (fixups)
      {
*************** elfNN_ia64_relax_section (abfd, sec, lin
*** 989,994 ****
--- 1048,1068 ----
  	elf_section_data (sec)->relocs = internal_relocs;
      }
  
+   if (changed_got)
+     {
+       struct elfNN_ia64_allocate_data data;
+       data.info = link_info;
+       data.ofs = 0;
+ 
+       elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_global_data_got, &data);
+       elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_global_fptr_got, &data);
+       elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_local_got, &data);
+       ia64_info->got_sec->_raw_size = data.ofs;
+       ia64_info->got_sec->_cooked_size = data.ofs;
+ 
+       /* ??? Resize .rela.got too.  */
+     }
+ 
    *again = changed_contents || changed_relocs;
    return TRUE;
  
*************** elfNN_ia64_relax_section (abfd, sec, lin
*** 1003,1008 ****
--- 1077,1115 ----
      free (internal_relocs);
    return FALSE;
  }
+ 
+ static void
+ elfNN_ia64_relax_ldxmov (abfd, contents, off)
+      bfd *abfd;
+      bfd_byte *contents;
+      bfd_vma off;
+ {
+   int shift, r1, r3;
+   bfd_vma dword, insn;
+ 
+   switch ((int)off & 0x3)
+     {
+     case 0: shift =  5; break;
+     case 1: shift = 14; off += 3; break;
+     case 2: shift = 23; off += 6; break;
+     case 3:
+       abort ();
+     }
+ 
+   dword = bfd_get_64 (abfd, contents + off);
+   insn = (dword >> shift) & 0x1ffffffffffLL;
+ 
+   r1 = (insn >> 6) & 127;
+   r3 = (insn >> 20) & 127;
+   if (r1 == r3)
+     insn = 0x8000000;				   /* nop */
+   else
+     insn = (insn & 0x7f01fff) | 0x10800000000LL;   /* (qp) mov r1 = r3 */
+ 
+   dword &= ~(0x1ffffffffffLL << shift);
+   dword |= (insn << shift);
+   bfd_put_64 (abfd, dword, contents + off);
+ }
  
  /* Return TRUE if NAME is an unwind table section name.  */
  
*************** elfNN_ia64_check_relocs (abfd, info, sec
*** 2125,2139 ****
      {
        enum {
  	NEED_GOT = 1,
! 	NEED_FPTR = 2,
! 	NEED_PLTOFF = 4,
! 	NEED_MIN_PLT = 8,
! 	NEED_FULL_PLT = 16,
! 	NEED_DYNREL = 32,
! 	NEED_LTOFF_FPTR = 64,
! 	NEED_TPREL = 128,
! 	NEED_DTPMOD = 256,
! 	NEED_DTPREL = 512
        };
  
        struct elf_link_hash_entry *h = NULL;
--- 2232,2247 ----
      {
        enum {
  	NEED_GOT = 1,
! 	NEED_GOTX = 2,
! 	NEED_FPTR = 4,
! 	NEED_PLTOFF = 8,
! 	NEED_MIN_PLT = 16,
! 	NEED_FULL_PLT = 32,
! 	NEED_DYNREL = 64,
! 	NEED_LTOFF_FPTR = 128,
! 	NEED_TPREL = 256,
! 	NEED_DTPMOD = 512,
! 	NEED_DTPREL = 1024
        };
  
        struct elf_link_hash_entry *h = NULL;
*************** elfNN_ia64_check_relocs (abfd, info, sec
*** 2230,2240 ****
  	  break;
  
  	case R_IA64_LTOFF22:
- 	case R_IA64_LTOFF22X:
  	case R_IA64_LTOFF64I:
  	  need_entry = NEED_GOT;
  	  break;
  
  	case R_IA64_PLTOFF22:
  	case R_IA64_PLTOFF64I:
  	case R_IA64_PLTOFF64MSB:
--- 2338,2351 ----
  	  break;
  
  	case R_IA64_LTOFF22:
  	case R_IA64_LTOFF64I:
  	  need_entry = NEED_GOT;
  	  break;
  
+ 	case R_IA64_LTOFF22X:
+ 	  need_entry = NEED_GOTX;
+ 	  break;
+ 
  	case R_IA64_PLTOFF22:
  	case R_IA64_PLTOFF64I:
  	case R_IA64_PLTOFF64MSB:
*************** elfNN_ia64_check_relocs (abfd, info, sec
*** 2316,2322 ****
        dyn_i->h = h;
  
        /* Create what's needed.  */
!       if (need_entry & (NEED_GOT | NEED_TPREL | NEED_DTPMOD | NEED_DTPREL))
  	{
  	  if (!got)
  	    {
--- 2427,2434 ----
        dyn_i->h = h;
  
        /* Create what's needed.  */
!       if (need_entry & (NEED_GOT | NEED_GOTX | NEED_TPREL
! 			| NEED_DTPMOD | NEED_DTPREL))
  	{
  	  if (!got)
  	    {
*************** elfNN_ia64_check_relocs (abfd, info, sec
*** 2326,2331 ****
--- 2438,2445 ----
  	    }
  	  if (need_entry & NEED_GOT)
  	    dyn_i->want_got = 1;
+ 	  if (need_entry & NEED_GOTX)
+ 	    dyn_i->want_gotx = 1;
  	  if (need_entry & NEED_TPREL)
  	    dyn_i->want_tprel = 1;
  	  if (need_entry & NEED_DTPMOD)
*************** elfNN_ia64_check_relocs (abfd, info, sec
*** 2385,2396 ****
    return TRUE;
  }
  
- struct elfNN_ia64_allocate_data
- {
-   struct bfd_link_info *info;
-   bfd_size_type ofs;
- };
- 
  /* For cleanliness, and potentially faster dynamic loading, allocate
     external GOT entries first.  */
  
--- 2499,2504 ----
*************** allocate_global_data_got (dyn_i, data)
*** 2401,2407 ****
  {
    struct elfNN_ia64_allocate_data *x = (struct elfNN_ia64_allocate_data *)data;
  
!   if (dyn_i->want_got
        && ! dyn_i->want_fptr
        && (elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info)
  	  || (elfNN_ia64_aix_vec (x->info->hash->creator)
--- 2509,2515 ----
  {
    struct elfNN_ia64_allocate_data *x = (struct elfNN_ia64_allocate_data *)data;
  
!   if ((dyn_i->want_got || dyn_i->want_gotx)
        && ! dyn_i->want_fptr
        && (elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info)
  	  || (elfNN_ia64_aix_vec (x->info->hash->creator)
*************** allocate_local_got (dyn_i, data)
*** 2473,2479 ****
  {
    struct elfNN_ia64_allocate_data *x = (struct elfNN_ia64_allocate_data *)data;
  
!   if (dyn_i->want_got
        && ! (elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info)
  	    || elfNN_ia64_aix_vec (x->info->hash->creator)))
      {
--- 2581,2587 ----
  {
    struct elfNN_ia64_allocate_data *x = (struct elfNN_ia64_allocate_data *)data;
  
!   if ((dyn_i->want_got || dyn_i->want_gotx)
        && ! (elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info)
  	    || elfNN_ia64_aix_vec (x->info->hash->creator)))
      {
*************** allocate_dynrel_entries (dyn_i, data)
*** 2699,2705 ****
  
    /* Take care of the GOT and PLT relocations.  */
  
!   if (((dynamic_symbol || shared) && dyn_i->want_got)
        || (dyn_i->want_ltoff_fptr && dyn_i->h && dyn_i->h->dynindx != -1))
      ia64_info->rel_got_sec->_raw_size += sizeof (ElfNN_External_Rela);
    if ((dynamic_symbol || shared) && dyn_i->want_tprel)
--- 2807,2813 ----
  
    /* Take care of the GOT and PLT relocations.  */
  
!   if (((dynamic_symbol || shared) && (dyn_i->want_got || dyn_i->want_gotx))
        || (dyn_i->want_ltoff_fptr && dyn_i->h && dyn_i->h->dynindx != -1))
      ia64_info->rel_got_sec->_raw_size += sizeof (ElfNN_External_Rela);
    if ((dynamic_symbol || shared) && dyn_i->want_tprel)
*************** elfNN_ia64_unwind_entry_compare (a, b)
*** 3516,3640 ****
    return (av < bv ? -1 : av > bv ? 1 : 0);
  }
  
  static bfd_boolean
! elfNN_ia64_final_link (abfd, info)
       bfd *abfd;
       struct bfd_link_info *info;
  {
    struct elfNN_ia64_link_hash_table *ia64_info;
-   asection *unwind_output_sec;
  
    ia64_info = elfNN_ia64_hash_table (info);
  
!   /* Make sure we've got ourselves a nice fat __gp value.  */
!   if (!info->relocateable)
      {
!       bfd_vma min_vma = (bfd_vma) -1, max_vma = 0;
!       bfd_vma min_short_vma = min_vma, max_short_vma = 0;
!       struct elf_link_hash_entry *gp;
!       bfd_vma gp_val;
!       asection *os;
  
!       /* Find the min and max vma of all sections marked short.  Also
! 	 collect min and max vma of any type, for use in selecting a
! 	 nice gp.  */
!       for (os = abfd->sections; os ; os = os->next)
! 	{
! 	  bfd_vma lo, hi;
  
! 	  if ((os->flags & SEC_ALLOC) == 0)
! 	    continue;
  
! 	  lo = os->vma;
! 	  hi = os->vma + os->_raw_size;
! 	  if (hi < lo)
! 	    hi = (bfd_vma) -1;
  
! 	  if (min_vma > lo)
! 	    min_vma = lo;
! 	  if (max_vma < hi)
! 	    max_vma = hi;
! 	  if (os->flags & SEC_SMALL_DATA)
! 	    {
! 	      if (min_short_vma > lo)
! 		min_short_vma = lo;
! 	      if (max_short_vma < hi)
! 		max_short_vma = hi;
! 	    }
  	}
  
!       /* See if the user wants to force a value.  */
!       gp = elf_link_hash_lookup (elf_hash_table (info), "__gp", FALSE,
! 				 FALSE, FALSE);
  
!       if (gp
! 	  && (gp->root.type == bfd_link_hash_defined
! 	      || gp->root.type == bfd_link_hash_defweak))
! 	{
! 	  asection *gp_sec = gp->root.u.def.section;
! 	  gp_val = (gp->root.u.def.value
! 		    + gp_sec->output_section->vma
! 		    + gp_sec->output_offset);
  	}
!       else
  	{
! 	  /* Pick a sensible value.  */
  
! 	  asection *got_sec = ia64_info->got_sec;
  
! 	  /* 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
! 	    gp_val = min_vma;
  
! 	  /* If it is possible to address the entire image, but we
! 	     don't with the choice above, adjust.  */
! 	  if (max_vma - min_vma < 0x400000
! 	      && max_vma - gp_val <= 0x200000
! 	      && gp_val - min_vma > 0x200000)
! 	    gp_val = min_vma + 0x200000;
! 	  else if (max_short_vma != 0)
! 	    {
! 	      /* If we don't cover all the short data, adjust.  */
! 	      if (max_short_vma - gp_val >= 0x200000)
! 		gp_val = min_short_vma + 0x200000;
  
! 	      /* If we're addressing stuff past the end, adjust back.  */
! 	      if (gp_val > max_vma)
! 		gp_val = max_vma - 0x200000 + 8;
! 	    }
! 	}
  
!       /* Validate whether all SHF_IA_64_SHORT sections are within
! 	 range of the chosen GP.  */
  
!       if (max_short_vma != 0)
  	{
! 	  if (max_short_vma - min_short_vma >= 0x400000)
! 	    {
! 	      (*_bfd_error_handler)
! 		(_("%s: short data segment overflowed (0x%lx >= 0x400000)"),
! 		 bfd_get_filename (abfd),
! 		 (unsigned long) (max_short_vma - min_short_vma));
! 	      return FALSE;
! 	    }
! 	  else if ((gp_val > min_short_vma
! 		    && gp_val - min_short_vma > 0x200000)
! 		   || (gp_val < max_short_vma
! 		       && max_short_vma - gp_val >= 0x200000))
! 	    {
! 	      (*_bfd_error_handler)
! 		(_("%s: __gp does not cover short data segment"),
! 		 bfd_get_filename (abfd));
! 	      return FALSE;
! 	    }
  	}
  
!       _bfd_set_gp_value (abfd, gp_val);
! 
        if (gp)
  	{
  	  gp->root.type = bfd_link_hash_defined;
--- 3624,3771 ----
    return (av < bv ? -1 : av > bv ? 1 : 0);
  }
  
+ /* Make sure we've got ourselves a nice fat __gp value.  */
  static bfd_boolean
! elfNN_ia64_choose_gp (abfd, info)
       bfd *abfd;
       struct bfd_link_info *info;
  {
+   bfd_vma min_vma = (bfd_vma) -1, max_vma = 0;
+   bfd_vma min_short_vma = min_vma, max_short_vma = 0;
+   struct elf_link_hash_entry *gp;
+   bfd_vma gp_val;
+   asection *os;
    struct elfNN_ia64_link_hash_table *ia64_info;
  
    ia64_info = elfNN_ia64_hash_table (info);
  
!   /* Find the min and max vma of all sections marked short.  Also collect
!      min and max vma of any type, for use in selecting a nice gp.  */
!   for (os = abfd->sections; os ; os = os->next)
      {
!       bfd_vma lo, hi;
  
!       if ((os->flags & SEC_ALLOC) == 0)
! 	continue;
  
!       lo = os->vma;
!       hi = os->vma + os->_raw_size;
!       if (hi < lo)
! 	hi = (bfd_vma) -1;
! 
!       if (min_vma > lo)
! 	min_vma = lo;
!       if (max_vma < hi)
! 	max_vma = hi;
!       if (os->flags & SEC_SMALL_DATA)
! 	{
! 	  if (min_short_vma > lo)
! 	    min_short_vma = lo;
! 	  if (max_short_vma < hi)
! 	    max_short_vma = hi;
! 	}
!     }
  
!   /* See if the user wants to force a value.  */
!   gp = elf_link_hash_lookup (elf_hash_table (info), "__gp", FALSE,
! 			     FALSE, FALSE);
! 
!   if (gp
!       && (gp->root.type == bfd_link_hash_defined
! 	  || gp->root.type == bfd_link_hash_defweak))
!     {
!       asection *gp_sec = gp->root.u.def.section;
!       gp_val = (gp->root.u.def.value
! 		+ gp_sec->output_section->vma
! 		+ gp_sec->output_offset);
!     }
!   else
!     {
!       /* Pick a sensible value.  */
  
!       asection *got_sec = ia64_info->got_sec;
! 
!       /* 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
! 	gp_val = min_vma;
! 
!       /* If it is possible to address the entire image, but we
! 	 don't with the choice above, adjust.  */
!       if (max_vma - min_vma < 0x400000
! 	  && max_vma - gp_val <= 0x200000
! 	  && gp_val - min_vma > 0x200000)
! 	gp_val = min_vma + 0x200000;
!       else if (max_short_vma != 0)
! 	{
! 	  /* If we don't cover all the short data, adjust.  */
! 	  if (max_short_vma - gp_val >= 0x200000)
! 	    gp_val = min_short_vma + 0x200000;
! 
! 	  /* If we're addressing stuff past the end, adjust back.  */
! 	  if (gp_val > max_vma)
! 	    gp_val = max_vma - 0x200000 + 8;
  	}
+     }
  
!   /* Validate whether all SHF_IA_64_SHORT sections are within
!      range of the chosen GP.  */
  
!   if (max_short_vma != 0)
!     {
!       if (max_short_vma - min_short_vma >= 0x400000)
! 	{
! 	  (*_bfd_error_handler)
! 	    (_("%s: short data segment overflowed (0x%lx >= 0x400000)"),
! 	     bfd_get_filename (abfd),
! 	     (unsigned long) (max_short_vma - min_short_vma));
! 	  return FALSE;
  	}
!       else if ((gp_val > min_short_vma
! 		&& gp_val - min_short_vma > 0x200000)
! 	       || (gp_val < max_short_vma
! 		   && max_short_vma - gp_val >= 0x200000))
  	{
! 	  (*_bfd_error_handler)
! 	    (_("%s: __gp does not cover short data segment"),
! 	     bfd_get_filename (abfd));
! 	  return FALSE;
! 	}
!     }
  
!   _bfd_set_gp_value (abfd, gp_val);
  
!   return TRUE;
! }
  
! static bfd_boolean
! elfNN_ia64_final_link (abfd, info)
!      bfd *abfd;
!      struct bfd_link_info *info;
! {
!   struct elfNN_ia64_link_hash_table *ia64_info;
!   asection *unwind_output_sec;
  
!   ia64_info = elfNN_ia64_hash_table (info);
  
!   /* Make sure we've got ourselves a nice fat __gp value.  */
!   if (!info->relocateable)
!     {
!       bfd_vma gp_val = _bfd_get_gp_value (abfd);
!       struct elf_link_hash_entry *gp;
  
!       if (gp_val == 0)
  	{
! 	  if (! elfNN_ia64_choose_gp (abfd, info))
! 	    return FALSE;
! 	  gp_val = _bfd_get_gp_value (abfd);
  	}
  
!       gp = elf_link_hash_lookup (elf_hash_table (info), "__gp", FALSE,
! 			         FALSE, FALSE);
        if (gp)
  	{
  	  gp->root.type = bfd_link_hash_defined;


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]