Subject: sparc64 xserver vs relocs
To: None <port-sparc64@netbsd.org>
From: Valeriy E. Ushakov <uwe@ptc.spbu.ru>
List: port-sparc64
Date: 05/12/2005 04:05:52
--mYCpIKhGyMATD0i+
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

[sent to port-sparc64 at mrg's request]

Ok, so lest this falls through cracks of icb log, here's the summary
of the "unsupported relocation type" troubles.  Sorry it's terse.

The original error:

    Elf_RelocateEntry() Unsupported relocation type 1057
    Elf_RelocateEntry() Unsupported relocation type 1057

src/gnu/dist/binutils/bfd/elf64-sparc.c has this comment:

   Relocations in the 64 bit SPARC ELF ABI are more complex than in
   standard ELF, because R_SPARC_OLO10 has secondary addend in
   ELF64_R_TYPE_DATA field.


See src/gnu/dist/binutils/include/elf/sparc.h where instead of
generic:

    #define ELF64_R_TYPE(info) ((info) & 0xffffffff)

it defines:

    #define ELF64_R_TYPE_DATA(info) \
      (((bfd_signed_vma)(ELF64_R_TYPE(info) >> 8) ^ 0x800000) - 0x800000)
    #define ELF64_R_TYPE_ID(info) \
      ((info) & 0xff)
    #define ELF64_R_TYPE_INFO(data, type) \
      (((bfd_vma) ((data) & 0xffffff) << 8) | (bfd_vma) (type))

and elf64-sparc.c uses ELF64_R_TYPE_ID instead of ELF64_R_TYPE.


Now, objdump will show you two relocations (_LO10 and _13), but that's
because bfd treats it that way.  In the same file:

   R_SPARC_OLO10 has secondary addend in ELF64_R_TYPE_DATA.  We handle
   it as two relocations for the same location, R_SPARC_LO10 and
   R_SPARC_13.


OTOH, readelf reports _OLO10 correctly.  See the following code in
src/gnu/dist/binutils/binutils/readelf.c

	  else if (elf_header.e_machine == EM_SPARCV9)
	    type = ELF64_R_TYPE_ID (info);
	  else
	    type = ELF64_R_TYPE (info);

anmd later

      if (elf_header.e_machine == EM_SPARCV9
	  && !strcmp (rtype, "R_SPARC_OLO10"))
	printf (" + %lx", (unsigned long) ELF64_R_TYPE_DATA (info));


So, given the above, unsupported reloc type 1057 turns into

    1057 & 0xff = 33 (_OLO10)
    1057 >> 8   =  4 (extra addend)

just as readelf shows.


Why gcc generates different code when run cross and native is beyond
me (mrg suggests that it might be caused by running cross on the
32-bit host), but the "good" native code looks like this

    sethi   %hi(endtab), %g1
    or      %g1, %lo(endtab), %i3
    ld      [%i3+4], %l2

and "bad" crosscompiled code looks like this:

    sethi   %hi(endtab), %i3
    ld      [%i3+%lo(endtab)+4], %l2

and for that ld the _OLO10 reloc is produced.


xsrc/xfree/xc/programs/Xserver/hw/xfree86/loader/elfloader.c is
unaware about _OLO10 relocs, so it errors out.

Attached is a patch that I made without any brain intervention by
copying _LO10 case and tweaking it a bit.  Not even test compiled.


SY, Uwe
-- 
uwe@ptc.spbu.ru                         |       Zu Grunde kommen
http://www.ptc.spbu.ru/~uwe/            |       Ist zu Grunde gehen

--mYCpIKhGyMATD0i+
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="elfloader.diff"

Index: elfloader.c
===================================================================
RCS file: /cvsroot/xsrc/xfree/xc/programs/Xserver/hw/xfree86/loader/elfloader.c,v
retrieving revision 1.4
diff -u --unified -r1.4 elfloader.c
--- elfloader.c	18 Mar 2005 14:55:15 -0000	1.4
+++ elfloader.c	11 May 2005 22:22:59 -0000
@@ -220,7 +220,17 @@
 #define ELF_ST_BIND ELF64_ST_BIND
 #define ELF_ST_TYPE ELF64_ST_TYPE
 #define ELF_R_SYM ELF64_R_SYM
+
+#if !defined(__sparcv9)
 #define ELF_R_TYPE ELF64_R_TYPE
+#else
+/*
+ * bfd says: Relocations in the 64 bit SPARC ELF ABI are more complex
+ * than in standard ELF, because R_SPARC_OLO10 has secondary addend in
+ * ELF64_R_TYPE_DATA field.
+ */
+#define ELF_R_TYPE(info)	((info) & 0xff)
+#endif
 
 # if defined (__alpha__) || defined (__ia64__)
 /*
@@ -2179,6 +2189,15 @@
 	dest64 = (unsigned long *)(secp + rel->r_offset);
 	*dest64 = (unsigned long)secp + rel->r_addend;
 	break;
+
+#ifdef __sparcv9
+    case R_SPARC_OLO10:		/* 33 */
+	dest32 = (unsigned int *)(secp + rel->r_offset);
+	symval += rel->r_addend
+	    + (((ELF64_R_TYPE(rel->r_info) >> 8) ^ 0x800000) - 0x800000);
+	*dest32 = (*dest32 & ~0x3ff) | (symval & 0x3ff);
+	break;
+#endif
 #endif /*__sparc__*/
 #ifdef __ia64__
     case R_IA64_NONE:

--mYCpIKhGyMATD0i+--