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]

ld on irix revisited


I think I've finally got ld working on irix6 with shared libraries.
Patches attached below.

First, here's a summary of the differences I found between glibc and
irix rld.  I'm sure most of this stuff isn't new, but I need to say
it anyway in order to justify the patches.

glibc 2.2.5's behaviour was:

    If the symbol index < DT_MIPS_GOTSYM, add the final symbol value.
    Otherwise add the symbol's final GOT entry.

glibc 2.3.2's behaviour is:

    If the symbol index < DT_MIPS_GOTSYM, add the base address.
    Otherwise add the symbol's final GOT entry.

The irix rld hehaviour seems to be:

    If the symbol index < DT_MIPS_GOT_SYM, subtract the symbol's
    st_value and add its final value.  Otherwise subract the symbol's
    initial GOT entry and add its final GOT entry.

See last weekend's postings for a verbose justification of the irix
behaviour.  But that's all by-the-bye.  Comparing 2.3.2 with rld,
there are three incompatible cases:

A. Relocs against symbol STN_UNDEF
----------------------------------

    - glibc adds the base address
    - irix rld does nothing (st_value = 0, final symbol value = 0)

    (FWIW, glibc seems to be wrong here since the r_info description
    in the gABI says:

	If the index is STN_UNDEF, the undefined symbol index,
	the relocation uses 0 as the "symbol value".

    The 64-bit ABI has similar wording.)

B. Relocs against defined external symbols
------------------------------------------

    - glibc adds the final symbol value
    - irix rld subtracts the initial contents of the GOT (the original
      st_value) and adds the final symbol value

    This one's the killer.  The addend must include the symbol
    value when using irix rld but it must not when using glibc.

C. Relocs against undefined external symbols
--------------------------------------------

    - glibc adds the final symbol value
    - irix rld subtracts the initial contents of the GOT and adds
      the final symbol value

    At the moment, ld initialises the GOT with the value it found in the
    external DSO, so these behaviours aren't compatible.  I think we're
    supposed to initialise the GOT to zero in this case, see:

        http://sources.redhat.com/ml/binutils/2003-06/msg00525.html

    for justification.


The attached patches are intended to fix the irix problems while
keeping compatibility with glibc.  Where the two loaders need
different behaviour (cases (A) and (B) above), I've used SGI_COMPAT
to select between them.

All the patches are needed in order to get correct irix behaviour:
it doesn't really make sense to apply some and not others.  I've split
them up anyway in the hope that they'll be easier to review that way.

Note: the patches are against 2.14.

Patch 1
-------

	* elfxx-mips.c (_bfd_mips_elf_finish_dynamic_symbol): Always
	initialize a GOT entry to the symbol's st_value.

    Fixes the GOT initailisation for (C).  glibc doesn't use the initial
    contents in this case, so the change is compatible with both loaders.
    Again, see:

        http://sources.redhat.com/ml/binutils/2003-06/msg00525.html

    for a justification.

Patch 2
-------

	* bfd/elfxx-mips.c (mips_elf_create_dynamic_relocation): In SGI-
	compatible objects, add the values of defined external symbols
	to the addend.

    Fixes (B) for irix rld.  This is a variation of the patch posted here:

        http://sources.redhat.com/ml/binutils/2003-06/msg00533.html

    but with the change predicated on SGI_COMPAT since it isn't
    compatible with glibc.

Patch 3
-------

	* bfd/elfxx-mips.c (mips_elf_create_dynamic_relocation): Treat
	forced-local symbols like other locals.  Don't create relocations
	against STN_UNDEF in irix objects.

    Disables this patch:

        http://sources.redhat.com/ml/binutils/2003-03/msg00148.html

    for SGI objects since relocations against symbol 0 do not have
    the desired effect ((A) above).

    Also treats forced-local symbols in the same way as other locals.
    At the moment, relocations against forced-local symbols are always
    turned into relocations against symbol 0.  The patch prevents this
    for irix targets but keeps it for glibc.

Patch 4
-------

	* elfxx-mips.c (mips_elf_link_hash_entry): Remove min_dyn_reloc_index.
	(mips_elf_link_hash_newfunc): Don't set it.
	(mips_elf_create_dynamic_relocation): Likewise.
	(_bfd_mips_elf_copy_indirect_symbol): Likewise.
	(bfd_mips_elf_swap_msym_in): Reenable.
	(mips_elf_adjust_msym_indices): New function.
	(_bfd_mips_elf_finish_dynamic_symbol): Just use a 0 symbol index.
	(_bfd_mips_elf_finish_dynamic_sections): After sorting .rel.dyn,
	go through .msym and set up the ms_info fields appropriately.

    This is the same as the patch posted here:
    
        http://sources.redhat.com/ml/binutils/2003-06/msg00533.html

    except that the new version should use more canonical types.
    See the message for a full explanation.

Patch 5
-------

	* elfxx-mips.c (_bfd_mips_elf_finish_dynamic_symbol): Don't try to
	create .msym entries for forced-local symbols.

    At the moment we try this and corrupt the end of the previous section.

Patch 6
-------

	* elfxx-mips.c (mips_elf_create_dynamic_relocation): Fix handling
	of relocations whose offset is -2.

    Fix the handling of .eh_frame if things like language-specific
    data are made relative.  The .eh_frame code then expects to
    have fully-relocated lsda fields, but we never add in the
    symbol value.

Patch 7
-------

	* elfxx-mips.c (mips_elf_irix6_finish_dynamic_symbol): Make the
	symbols protected.

    This is something I noticed while looking at other stuff.
    It copies the behaviour of the native linker and it seems
    fairly obvious, but I'm not aware of anything specific
    that breaks without it.

Are these patches likely to be accepted?  If so, I'll come up
with something for the testsuite.

The patches were tested on a mipsel-linux-gnu cross compiler and by
bootstrapping and regression testing mips-sgi-irix6.5 --with-gnu-as
--with-gnu-ld.  I needed some gcc patches for the irix config: I'll
post them to gcc-patches if the bfd side is accepted.

Richard

*** elfxx-mips.c.cvs	Sat Jun 21 15:19:37 2003
--- elfxx-mips.c.1	Sat Jun 21 15:21:02 2003
*************** _bfd_mips_elf_finish_dynamic_symbol (out
*** 6749,6770 ****
        bfd_vma offset;
        bfd_vma value;
  
!       if (sym->st_value)
! 	value = sym->st_value;
!       else
! 	{
! 	  /* For an entity defined in a shared object, this will be
! 	     NULL.  (For functions in shared objects for
! 	     which we have created stubs, ST_VALUE will be non-NULL.
! 	     That's because such the functions are now no longer defined
! 	     in a shared object.)  */
! 
! 	  if ((info->shared && h->root.type == bfd_link_hash_undefined)
! 	      || h->root.type == bfd_link_hash_undefweak)
! 	    value = 0;
! 	  else
! 	    value = h->root.u.def.value;
! 	}
        offset = mips_elf_global_got_index (dynobj, output_bfd, h);
        MIPS_ELF_PUT_WORD (output_bfd, value, sgot->contents + offset);
      }
--- 6749,6755 ----
        bfd_vma offset;
        bfd_vma value;
  
!       value = sym->st_value;
        offset = mips_elf_global_got_index (dynobj, output_bfd, h);
        MIPS_ELF_PUT_WORD (output_bfd, value, sgot->contents + offset);
      }
--- elfxx-mips.c.1	Sat Jun 21 15:21:02 2003
+++ elfxx-mips.c.2	Sat Jun 21 16:50:00 2003
@@ -3886,6 +3886,7 @@ mips_elf_create_dynamic_relocation (outp
   else
     {
       long indx;
+      bfd_boolean defined_p;
 
       /* We must now calculate the dynamic symbol table index to use
 	 in the relocation.  */
@@ -3898,6 +3899,15 @@ mips_elf_create_dynamic_relocation (outp
 	     become local.  */
 	  if (indx == -1)
 	    indx = 0;
+	  if (SGI_COMPAT (output_bfd))
+	    defined_p = ((h->root.elf_link_hash_flags
+			  & ELF_LINK_HASH_DEF_REGULAR) != 0);
+	  else
+	    /* ??? glibc's ld.so just adds the final GOT entry to the
+	       relocation field.  It therefore treats relocs against
+	       defined symbols in the same way as relocs against
+	       undefined symbols.  */
+	    defined_p = FALSE;
 	}
       else
 	{
@@ -3927,13 +3937,14 @@ mips_elf_create_dynamic_relocation (outp
 	     useful, after all.  This should be a bit more efficient
 	     as well.  */
 	  indx = 0;
+	  defined_p = TRUE;
 	}
 
       /* If the relocation was previously an absolute relocation and
 	 this symbol will not be referred to by the relocation, we must
 	 adjust it by the value we give it in the dynamic symbol table.
 	 Otherwise leave the job up to the dynamic linker.  */
-      if (!indx && r_type != R_MIPS_REL32)
+      if (defined_p && r_type != R_MIPS_REL32)
 	*addendp += symbol;
 
       /* The relocation is always an REL32 relocation because we don't
*** elfxx-mips.c.2	Sat Jun 21 15:45:55 2003
--- elfxx-mips.c.3	Sat Jun 21 16:30:40 2003
*************** mips_elf_create_dynamic_relocation (outp
*** 3892,3904 ****
  	 in the relocation.  */
        if (h != NULL
  	  && (! info->symbolic || (h->root.elf_link_hash_flags
! 				   & ELF_LINK_HASH_DEF_REGULAR) == 0))
! 	{
! 	  indx = h->root.dynindx;
  	  /* h->root.dynindx may be -1 if this symbol was marked to
  	     become local.  */
! 	  if (indx == -1)
! 	    indx = 0;
  	  if (SGI_COMPAT (output_bfd))
  	    defined_p = ((h->root.elf_link_hash_flags
  			  & ELF_LINK_HASH_DEF_REGULAR) != 0);
--- 3892,3903 ----
  	 in the relocation.  */
        if (h != NULL
  	  && (! info->symbolic || (h->root.elf_link_hash_flags
! 				   & ELF_LINK_HASH_DEF_REGULAR) == 0)
  	  /* h->root.dynindx may be -1 if this symbol was marked to
  	     become local.  */
! 	  && h->root.dynindx != -1)
! 	{
! 	  indx = h->root.dynindx;
  	  if (SGI_COMPAT (output_bfd))
  	    defined_p = ((h->root.elf_link_hash_flags
  			  & ELF_LINK_HASH_DEF_REGULAR) != 0);
*************** mips_elf_create_dynamic_relocation (outp
*** 3936,3942 ****
  	     section-relative relocations.  It's not like they're
  	     useful, after all.  This should be a bit more efficient
  	     as well.  */
! 	  indx = 0;
  	  defined_p = TRUE;
  	}
  
--- 3935,3946 ----
  	     section-relative relocations.  It's not like they're
  	     useful, after all.  This should be a bit more efficient
  	     as well.  */
! 	  /* ??? Although this behavior is compatible with glibc's ld.so,
! 	     the ABI says that relocations against STN_UNDEF should have
! 	     a symbol value of 0.  Irix rld honors this, so relocations
! 	     against STN_UNDEF have no effect.  */
! 	  if (!SGI_COMPAT (output_bfd))
! 	    indx = 0;
  	  defined_p = TRUE;
  	}
  
*** elfxx-mips.c.3	Sat Jun 21 16:30:40 2003
--- elfxx-mips.c.4	Sat Jun 21 16:30:48 2003
*************** struct mips_elf_link_hash_entry
*** 189,198 ****
       a readonly section.  */
    bfd_boolean readonly_reloc;
  
-   /* The index of the first dynamic relocation (in the .rel.dyn
-      section) against this symbol.  */
-   unsigned int min_dyn_reloc_index;
- 
    /* We must not create a stub for a symbol that has relocations
       related to taking the function's address, i.e. any but
       R_MIPS_CALL*16 ones -- see "MIPS ABI Supplement, 3rd Edition",
--- 189,194 ----
*************** static void bfd_elf32_swap_compact_rel_o
*** 391,400 ****
    PARAMS ((bfd *, const Elf32_compact_rel *, Elf32_External_compact_rel *));
  static void bfd_elf32_swap_crinfo_out
    PARAMS ((bfd *, const Elf32_crinfo *, Elf32_External_crinfo *));
- #if 0
  static void bfd_mips_elf_swap_msym_in
    PARAMS ((bfd *, const Elf32_External_Msym *, Elf32_Internal_Msym *));
- #endif
  static void bfd_mips_elf_swap_msym_out
    PARAMS ((bfd *, const Elf32_Internal_Msym *, Elf32_External_Msym *));
  static int sort_dynamic_relocs
--- 387,394 ----
*************** static bfd_boolean mips_elf_create_got_s
*** 446,451 ****
--- 440,447 ----
    PARAMS ((bfd *, struct bfd_link_info *, bfd_boolean));
  static asection *mips_elf_create_msym_section
    PARAMS ((bfd *));
+ static void mips_elf_adjust_msym_indices
+   PARAMS ((bfd *, asection *, asection *));
  static bfd_reloc_status_type mips_elf_calculate_relocation
    PARAMS ((bfd *, bfd *, asection *, struct bfd_link_info *,
  	   const Elf_Internal_Rela *, bfd_vma, reloc_howto_type *,
*************** mips_elf_link_hash_newfunc (entry, table
*** 732,738 ****
        ret->esym.ifd = -2;
        ret->possibly_dynamic_relocs = 0;
        ret->readonly_reloc = FALSE;
-       ret->min_dyn_reloc_index = 0;
        ret->no_fn_stub = FALSE;
        ret->fn_stub = NULL;
        ret->need_fn_stub = FALSE;
--- 728,733 ----
*************** bfd_elf32_swap_crinfo_out (abfd, in, ex)
*** 1194,1200 ****
    H_PUT_32 (abfd, in->vaddr, ex->vaddr);
  }
  
- #if 0
  /* Swap in an MSYM entry.  */
  
  static void
--- 1189,1194 ----
*************** bfd_mips_elf_swap_msym_in (abfd, ex, in)
*** 1206,1212 ****
    in->ms_hash_value = H_GET_32 (abfd, ex->ms_hash_value);
    in->ms_info = H_GET_32 (abfd, ex->ms_info);
  }
! #endif
  /* Swap out an MSYM entry.  */
  
  static void
--- 1200,1206 ----
    in->ms_hash_value = H_GET_32 (abfd, ex->ms_hash_value);
    in->ms_info = H_GET_32 (abfd, ex->ms_info);
  }
! 
  /* Swap out an MSYM entry.  */
  
  static void
*************** mips_elf_create_msym_section (abfd)
*** 2944,2949 ****
--- 2938,2981 ----
  
    return s;
  }
+ 
+ /* Adjust the contents of .msym after sorting the dynamic relocations.
+    RELDYN and MSYM are the two sections involved.  */
+ 
+ static void
+ mips_elf_adjust_msym_indices (abfd, reldyn, msym)
+      bfd *abfd;
+      asection *reldyn, *msym;
+ {
+   bfd_size_type i, entsize;
+   bfd_vma lastsym;
+ 
+   entsize = MIPS_ELF_REL_SIZE (abfd);
+   lastsym = (bfd_vma) -1;
+ 
+   for (i = entsize; i < reldyn->_raw_size; i += entsize)
+     {
+       bfd_vma sym;
+       Elf_Internal_Rela reloc[3];
+ 
+       (*get_elf_backend_data (abfd)->s->swap_reloc_in)
+ 	(abfd, reldyn->contents + i, reloc);
+       sym = ELF_R_SYM (abfd, reloc[0].r_info);
+       if (sym != lastsym)
+ 	{
+ 	  /* This is the first relocation against SYM.  Get its .msym
+ 	     record and adjust the ms_info field appropriately.  */
+ 	  Elf32_Internal_Msym entry;
+ 
+ 	  bfd_mips_elf_swap_msym_in
+ 	    (abfd, (Elf32_External_Msym *) msym->contents + sym, &entry);
+ 	  entry.ms_info = ELF32_MS_INFO (i / entsize, 1);
+ 	  bfd_mips_elf_swap_msym_out
+ 	    (abfd, &entry, (Elf32_External_Msym *) msym->contents + sym);
+ 	  lastsym = sym;
+ 	}
+     }
+ }
  
  /* Calculate the value produced by the RELOCATION (which comes from
     the INPUT_BFD).  The ADDEND is the addend to use for this
*************** mips_elf_create_dynamic_relocation (outp
*** 3999,4011 ****
        (output_bfd, &outrel[0],
         (sreloc->contents + sreloc->reloc_count * sizeof (Elf32_External_Rel)));
  
-   /* Record the index of the first relocation referencing H.  This
-      information is later emitted in the .msym section.  */
-   if (h != NULL
-       && (h->min_dyn_reloc_index == 0
- 	  || sreloc->reloc_count < h->min_dyn_reloc_index))
-     h->min_dyn_reloc_index = sreloc->reloc_count;
- 
    /* We've now added another relocation.  */
    ++sreloc->reloc_count;
  
--- 4031,4036 ----
*************** _bfd_mips_elf_finish_dynamic_symbol (out
*** 6704,6714 ****
    asection *smsym;
    struct mips_got_info *g, *gg;
    const char *name;
-   struct mips_elf_link_hash_entry *mh;
  
    dynobj = elf_hash_table (info)->dynobj;
    gval = sym->st_value;
-   mh = (struct mips_elf_link_hash_entry *) h;
  
    if (h->plt.offset != (bfd_vma) -1)
      {
--- 6729,6737 ----
*************** _bfd_mips_elf_finish_dynamic_symbol (out
*** 6831,6837 ****
        msym.ms_hash_value = bfd_elf_hash (h->root.root.string);
        /* It is undocumented what the `1' indicates, but IRIX6 uses
  	 this value.  */
!       msym.ms_info = ELF32_MS_INFO (mh->min_dyn_reloc_index, 1);
        bfd_mips_elf_swap_msym_out
  	(dynobj, &msym,
  	 ((Elf32_External_Msym *) smsym->contents) + h->dynindx);
--- 6854,6860 ----
        msym.ms_hash_value = bfd_elf_hash (h->root.root.string);
        /* It is undocumented what the `1' indicates, but IRIX6 uses
  	 this value.  */
!       msym.ms_info = ELF32_MS_INFO (0, 1);
        bfd_mips_elf_swap_msym_out
  	(dynobj, &msym,
  	 ((Elf32_External_Msym *) smsym->contents) + h->dynindx);
*************** _bfd_mips_elf_finish_dynamic_sections (o
*** 7236,7242 ****
  		 (size_t) s->reloc_count - 1,
  		 sizeof (Elf32_External_Rel), sort_dynamic_relocs);
        }
!   }
  
    return TRUE;
  }
--- 7259,7268 ----
  		 (size_t) s->reloc_count - 1,
  		 sizeof (Elf32_External_Rel), sort_dynamic_relocs);
        }
! 
!     if (s != 0 && smsym != 0)
!       mips_elf_adjust_msym_indices (output_bfd, s, smsym);
!   }		
  
    return TRUE;
  }
*************** _bfd_mips_elf_copy_indirect_symbol (bed,
*** 7778,7787 ****
    dirmips->possibly_dynamic_relocs += indmips->possibly_dynamic_relocs;
    if (indmips->readonly_reloc)
      dirmips->readonly_reloc = TRUE;
-   if (dirmips->min_dyn_reloc_index == 0
-       || (indmips->min_dyn_reloc_index != 0
- 	  && indmips->min_dyn_reloc_index < dirmips->min_dyn_reloc_index))
-     dirmips->min_dyn_reloc_index = indmips->min_dyn_reloc_index;
    if (indmips->no_fn_stub)
      dirmips->no_fn_stub = TRUE;
  }
--- 7804,7809 ----
--- elfxx-mips.c.4	Sat Jun 21 16:30:48 2003
+++ elfxx-mips.c.5	Sat Jun 21 16:30:53 2003
@@ -6847,7 +6847,7 @@ _bfd_mips_elf_finish_dynamic_symbol (out
 
   /* Create a .msym entry, if appropriate.  */
   smsym = bfd_get_section_by_name (dynobj, ".msym");
-  if (smsym)
+  if (smsym && h->dynindx != -1)
     {
       Elf32_Internal_Msym msym;
 
*** elfxx-mips.c.5	Sat Jun 21 15:42:14 2003
--- elfxx-mips.c.6	Sat Jun 21 15:42:07 2003
*************** mips_elf_create_dynamic_relocation (outp
*** 3906,3914 ****
      }
  #endif
  
!   if (outrel[0].r_offset == (bfd_vma) -1
!       || outrel[0].r_offset == (bfd_vma) -2)
      skip = TRUE;
  
    /* If we've decided to skip this relocation, just output an empty
       record.  Note that R_MIPS_NONE == 0, so that this call to memset
--- 3906,3922 ----
      }
  #endif
  
!   if (outrel[0].r_offset == (bfd_vma) -1)
!     /* The relocation field has been deleted.  */
      skip = TRUE;
+   else if (outrel[0].r_offset == (bfd_vma) -2)
+     {
+       /* The relocation field has been converted into a relative value of
+ 	 some sort.  Functions like _bfd_elf_write_section_eh_frame expect
+ 	 the field to be fully relocated, so add in the symbol's value.  */
+       skip = TRUE;
+       *addendp += symbol;
+     }
  
    /* If we've decided to skip this relocation, just output an empty
       record.  Note that R_MIPS_NONE == 0, so that this call to memset
*** elfxx-mips.c.6	Sat Jun 21 16:31:01 2003
--- elfxx-mips.c.7	Sat Jun 21 16:31:10 2003
*************** mips_elf_irix6_finish_dynamic_symbol (ab
*** 6710,6715 ****
--- 6710,6716 ----
  	  /* All of these symbols are given type STT_SECTION by the
  	     IRIX6 linker.  */
  	  sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION);
+ 	  sym->st_other = STO_PROTECTED;
  
  	  /* The IRIX linker puts these symbols in special sections.  */
  	  if (i == 0)

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