This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc 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]

Re: [SPARC] Segfault when resolving STT_GNU_IFUNC functions


From: David Miller <davem@davemloft.net>
Date: Wed, 25 May 2011 15:16:29 -0700 (PDT)

> From: Aurelien Jarno <aurelien@aurel32.net>
> Date: Sun, 8 May 2011 20:25:09 +0200
> 
>> I am experiencing an issue with glibc 2.13 on sparc32 and sparc64 when
>> multiarch is enabled. In some cases, probably depending on order the
>> relocations are done, the resolution of STT_GNU_IFUNC functions
>> (typically memset or memcpy) does a segmentation fault, with a
>> backtrace looking like that:
>  ...
>> Help to solve this issue would be appreciated.
> 
> Thanks for reporting this bug, I'll try to figure out what's wrong
> and fix it.

Can you give this patch a try?

As you discovered we can't depend upon GOT relocations being resolved
at this point.  The only way I could come up to get the dl_hwcap value
passed down to the IFUNC resolvers is to pass it in directly from the
dynamic linker (where such symbol references are safe by the time we
get to these things).

This doesn't have an influence on IFUNC resolved implementations
outside of GLIBC, they can still assume that no arguments are being
passed in and still work fine.  This convention only exists privately
inside of GLIBC.

diff --git a/sysdeps/sparc/sparc32/dl-irel.h b/sysdeps/sparc/sparc32/dl-irel.h
index 1891938..2753fb4 100644
--- a/sysdeps/sparc/sparc32/dl-irel.h
+++ b/sysdeps/sparc/sparc32/dl-irel.h
@@ -24,6 +24,7 @@
 #include <stdio.h>
 #include <unistd.h>
 #include <dl-plt.h>
+#include <ldsodefs.h>
 
 #define ELF_MACHINE_IRELA	1
 
@@ -36,13 +37,13 @@ elf_irela (const Elf32_Rela *reloc)
   if (__builtin_expect (r_type == R_SPARC_IRELATIVE, 1))
     {
       Elf32_Addr *const reloc_addr = (void *) reloc->r_offset;
-      Elf32_Addr value = ((Elf32_Addr (*) (void)) reloc->r_addend) ();
+      Elf32_Addr value = ((Elf32_Addr (*) (int)) reloc->r_addend) (GLRO(dl_hwcap));
       *reloc_addr = value;
     }
   else if (__builtin_expect (r_type == R_SPARC_JMP_IREL, 1))
     {
       Elf32_Addr *const reloc_addr = (void *) reloc->r_offset;
-      Elf32_Addr value = ((Elf32_Addr (*) (void)) reloc->r_addend) ();
+      Elf32_Addr value = ((Elf32_Addr (*) (int)) reloc->r_addend) (GLRO(dl_hwcap));
 
       sparc_fixup_plt (reloc, reloc_addr, value, 0, 1);
     }
diff --git a/sysdeps/sparc/sparc32/dl-machine.h b/sysdeps/sparc/sparc32/dl-machine.h
index 9631db3..f8e8fe4 100644
--- a/sysdeps/sparc/sparc32/dl-machine.h
+++ b/sysdeps/sparc/sparc32/dl-machine.h
@@ -399,7 +399,7 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
       && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0)
       && __builtin_expect (sym->st_shndx != SHN_UNDEF, 1))
     {
-      value = ((Elf32_Addr (*) (void)) value) ();
+      value = ((Elf32_Addr (*) (int)) value) (GLRO(dl_hwcap));
     }
 
   switch (r_type)
@@ -430,11 +430,11 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
       *reloc_addr = value;
       break;
     case R_SPARC_IRELATIVE:
-      value = ((Elf32_Addr (*) (void)) value) ();
+      value = ((Elf32_Addr (*) (int)) value) (GLRO(dl_hwcap));
       *reloc_addr = value;
       break;
     case R_SPARC_JMP_IREL:
-      value = ((Elf32_Addr (*) (void)) value) ();
+      value = ((Elf32_Addr (*) (int)) value) (GLRO(dl_hwcap));
       /* Fall thru */
     case R_SPARC_JMP_SLOT:
       {
@@ -562,7 +562,7 @@ elf_machine_lazy_rel (struct link_map *map,
   else if (r_type == R_SPARC_JMP_IREL)
     {
       Elf32_Addr value = map->l_addr + reloc->r_addend;
-      value = ((Elf32_Addr (*) (void)) value) ();
+      value = ((Elf32_Addr (*) (int)) value) (GLRO(dl_hwcap));
       sparc_fixup_plt (reloc, reloc_addr, value, 1, 1);
     }
   else if (r_type == R_SPARC_NONE)
diff --git a/sysdeps/sparc/sparc64/dl-irel.h b/sysdeps/sparc/sparc64/dl-irel.h
index 1a2a0a3..0d70e2a 100644
--- a/sysdeps/sparc/sparc64/dl-irel.h
+++ b/sysdeps/sparc/sparc64/dl-irel.h
@@ -24,6 +24,7 @@
 #include <stdio.h>
 #include <unistd.h>
 #include <dl-plt.h>
+#include <ldsodefs.h>
 
 #define ELF_MACHINE_IRELA	1
 
@@ -36,13 +37,13 @@ elf_irela (const Elf64_Rela *reloc)
   if (__builtin_expect (r_type == R_SPARC_IRELATIVE, 1))
     {
       Elf64_Addr *const reloc_addr = (void *) reloc->r_offset;
-      Elf64_Addr value = ((Elf64_Addr (*) (void)) reloc->r_addend) ();
+      Elf64_Addr value = ((Elf64_Addr (*) (int)) reloc->r_addend) (GLRO(dl_hwcap));
       *reloc_addr = value;
     }
   else if (__builtin_expect (r_type == R_SPARC_JMP_IREL, 1))
     {
       Elf64_Addr *const reloc_addr = (void *) reloc->r_offset;
-      Elf64_Addr value = ((Elf64_Addr (*) (void)) reloc->r_addend) ();
+      Elf64_Addr value = ((Elf64_Addr (*) (int)) reloc->r_addend) (GLRO(dl_hwcap));
       struct link_map map = { .l_addr = 0 };
 
       /* 'high' is always zero, for large PLT entries the linker
diff --git a/sysdeps/sparc/sparc64/dl-machine.h b/sysdeps/sparc/sparc64/dl-machine.h
index 82ab5a4..aaa22d6 100644
--- a/sysdeps/sparc/sparc64/dl-machine.h
+++ b/sysdeps/sparc/sparc64/dl-machine.h
@@ -430,7 +430,7 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc,
   if (sym != NULL
       && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0)
       && __builtin_expect (sym->st_shndx != SHN_UNDEF, 1))
-    value = ((Elf64_Addr (*) (void)) value) ();
+    value = ((Elf64_Addr (*) (int)) value) (GLRO(dl_hwcap));
 
   switch (r_type)
     {
@@ -460,11 +460,11 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc,
       *reloc_addr = value;
       break;
     case R_SPARC_IRELATIVE:
-      value = ((Elf64_Addr (*) (void)) value) ();
+      value = ((Elf64_Addr (*) (int)) value) (GLRO(dl_hwcap));
       *reloc_addr = value;
       break;
     case R_SPARC_JMP_IREL:
-      value = ((Elf64_Addr (*) (void)) value) ();
+      value = ((Elf64_Addr (*) (int)) value) (GLRO(dl_hwcap));
       /* Fall thru */
     case R_SPARC_JMP_SLOT:
 #ifdef RESOLVE_CONFLICT_FIND_MAP
@@ -658,7 +658,7 @@ elf_machine_lazy_rel (struct link_map *map,
 	   || r_type == R_SPARC_IRELATIVE)
     {
       Elf64_Addr value = map->l_addr + reloc->r_addend;
-      value = ((Elf64_Addr (*) (void)) value) ();
+      value = ((Elf64_Addr (*) (int)) value) (GLRO(dl_hwcap));
       if (r_type == R_SPARC_JMP_IREL)
 	{
 	  /* 'high' is always zero, for large PLT entries the linker
diff --git a/sysdeps/sparc/sparc64/multiarch/memcpy.S b/sysdeps/sparc/sparc64/multiarch/memcpy.S
index a708de1..c12dc3b 100644
--- a/sysdeps/sparc/sparc64/multiarch/memcpy.S
+++ b/sysdeps/sparc/sparc64/multiarch/memcpy.S
@@ -32,26 +32,10 @@ ENTRY(memcpy)
 	 or	%o3, %lo(_GLOBAL_OFFSET_TABLE_+4), %o3
 1:	add	%o7, %o3, %o3
 	mov	%o5, %o7
-	sethi	%hi(_rtld_global_ro), %o2
-	or	%o2, %lo(_rtld_global_ro), %o2
-#  ifdef __arch64__
-	ldx	[%o3 + %o2], %o2
-	ldx	[%o2 + RTLD_GLOBAL_RO_DL_HWCAP_OFFSET], %o2
-#  else
-	ld	[%o3 + %o2], %o2
-	ld	[%o2 + RTLD_GLOBAL_RO_DL_HWCAP_OFFSET + 4], %o2
-#  endif
-# else
-	set	_dl_hwcap, %o3
-#  ifdef __arch64__
-	ldx	[%o3], %o2
-#  else
-	ld	[%o3 + 4], %o2
-#  endif
 # endif
-	andcc	%o2, 0x80, %g0	! HWCAP_SPARC_N2
+	andcc	%o0, 0x80, %g0	! HWCAP_SPARC_N2
 	be	1f
-	 andcc	%o2, 0x40, %g0	! HWCAP_SPARC_BLKINIT
+	 andcc	%o0, 0x40, %g0	! HWCAP_SPARC_BLKINIT
 # ifdef SHARED
 	sethi	%gdop_hix22(__memcpy_niagara2), %o1
 	xor	%o1, %gdop_lox10(__memcpy_niagara2), %o1
@@ -61,7 +45,7 @@ ENTRY(memcpy)
 	ba	10f
 	 nop
 1:	be	1f
-	 andcc	%o2, 0x20, %g0	! HWCAP_SPARC_ULTRA3
+	 andcc	%o0, 0x20, %g0	! HWCAP_SPARC_ULTRA3
 # ifdef SHARED
 	sethi	%gdop_hix22(__memcpy_niagara1), %o1
 	xor	%o1, %gdop_lox10(__memcpy_niagara1), %o1
diff --git a/sysdeps/sparc/sparc64/multiarch/memset.S b/sysdeps/sparc/sparc64/multiarch/memset.S
index befd7ed..2e27448 100644
--- a/sysdeps/sparc/sparc64/multiarch/memset.S
+++ b/sysdeps/sparc/sparc64/multiarch/memset.S
@@ -32,24 +32,8 @@ ENTRY(memset)
 	 or	%o3, %lo(_GLOBAL_OFFSET_TABLE_+4), %o3
 1:	add	%o7, %o3, %o3
 	mov	%o5, %o7
-	sethi	%hi(_rtld_global_ro), %o2
-	or	%o2, %lo(_rtld_global_ro), %o2
-#  ifdef __arch64__
-	ldx	[%o3 + %o2], %o2
-	ldx	[%o2 + RTLD_GLOBAL_RO_DL_HWCAP_OFFSET], %o2
-#  else
-	ld	[%o3 + %o2], %o2
-	ld	[%o2 + RTLD_GLOBAL_RO_DL_HWCAP_OFFSET + 4], %o2
-#  endif
-# else
-	set	_dl_hwcap, %o3
-#  ifdef __arch64__
-	ldx	[%o3], %o2
-#  else
-	ld	[%o3 + 4], %o2
-#  endif
 # endif
-	andcc	%o2, 0x40, %g0	! HWCAP_SPARC_BLKINIT
+	andcc	%o0, 0x40, %g0	! HWCAP_SPARC_BLKINIT
 	be	9f
 	 nop
 # ifdef SHARED
@@ -84,24 +68,8 @@ ENTRY(__bzero)
 	 or	%o3, %lo(_GLOBAL_OFFSET_TABLE_+4), %o3
 1:	add	%o7, %o3, %o3
 	mov	%o5, %o7
-	sethi	%hi(_rtld_global_ro), %o2
-	or	%o2, %lo(_rtld_global_ro), %o2
-#  ifdef __arch64__
-	ldx	[%o3 + %o2], %o2
-	ldx	[%o2 + RTLD_GLOBAL_RO_DL_HWCAP_OFFSET], %o2
-#  else
-	ld	[%o3 + %o2], %o2
-	ld	[%o2 + RTLD_GLOBAL_RO_DL_HWCAP_OFFSET + 4], %o2
-#  endif
-# else
-	set	_dl_hwcap, %o3
-#  ifdef __arch64__
-	ldx	[%o3], %o2
-#  else
-	ld	[%o3 + 4], %o2
-#  endif
 # endif
-	andcc	%o2, 0x40, %g0	! HWCAP_SPARC_BLKINIT
+	andcc	%o0, 0x40, %g0	! HWCAP_SPARC_BLKINIT
 	be	9f
 	 nop
 # ifdef SHARED


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