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]

powerpc STT_GNU_IFUNC support, 2 of 2


This patch modifies the ifunc testcase for powerpc.  The changes are:

a) Don't use external global vars in indirect functions.  Any variable
used in an indirect function must be locally defined, ie. at least
with protected visibility.  Otherwise you must use a GOT entry to
access the variable, and it's trivially easy to construct cases where
the GOT entry won't be relocated at the time the ifunc runs.  Or else
ld.so will need to run two passes over relocations or somesuch to
guarantee that ifunc relocs are applied last, globally.  I figure it
is bad to write testcases that might lead to wrong user expectations.

b) Implement powerpc indirect functions in assembly.  Returning
pic function addresses in C on powerpc requires GOT entries.

c) Define abort() to an illegal instruction.  I find this much more
usefull when debugging code, since you get all the register state.
Backtracing from abort() typically loses some volatile register
of interest.

Close inspection of the ppc assembly below will reveal I've referenced
&global as input to the asm but then written "global" rather than %1
in the instructions.  This is deliberate.  &global on powerpc64
generates a toc entry reference, even for "X" constraint, when I want
just the raw symbol name.

2009-07-30  Alan Modra  <amodra@bigpond.net.au>

	* elf/ifuncdep2.c: Don't use external global in ifunc.  Add
	powerpc assembly ifuncs.
	* elf/ifuncmod1.c: Likewise.
	* elf/ifuncmod5.c: Likewise.
	* elf/ifuncmain1.c (global): Delete.
	(abort): Define to generate illegal insn.
	* elf/ifuncmain1vis.c: Likewise.
	* elf/ifuncmain2.c: Likewise.
	* elf/ifuncmain3.c: Likewise.
	* elf/ifuncmain5.c: Likewise.
	* elf/ifuncmain6pie.c: Likewise.  Add powerpc assembly ifunc.
	* elf/ifuncmain7.c: Likewise.
	* elf/ifuncmod3.c (global): Delete.

diff --git a/elf/ifuncdep2.c b/elf/ifuncdep2.c
index fb21eef..9edade9 100644
--- a/elf/ifuncdep2.c
+++ b/elf/ifuncdep2.c
@@ -1,6 +1,6 @@
 /* Test 3 STT_GNU_IFUNC symbols.  */
 
-extern int global;
+int global __attribute__ ((visibility ("protected"))) = -1;
 
 static int
 one (void)
@@ -26,6 +26,28 @@ __asm__(".type foo1, %gnu_indirect_function");
 void * 
 foo1_ifunc (void)
 {
+#if defined (__powerpc__)
+  register void *ret __asm__ ("r3");
+  __asm__ ("mflr 12\n\t"
+	   "bcl 20,31,1f\n"
+	   "1:\tmflr 11\n\t"
+	   "mtlr 12\n\t"
+	   "addis 12,11,global-1b@ha\n\t"
+	   "lwz 12,global-1b@l(12)\n\t"
+	   "addis %0,11,%2-1b@ha\n\t"
+	   "addi %0,%0,%2-1b@l\n\t"
+	   "cmpwi 12,1\n\t"
+	   "beqlr\n\t"
+	   "addis %0,11,%3-1b@ha\n\t"
+	   "addi %0,%0,%3-1b@l\n\t"
+	   "cmpwi 12,-1\n\t"
+	   "beqlr\n\t"
+	   "addis %0,11,%4-1b@ha\n\t"
+	   "addi %0,%0,%4-1b@l"
+	   : "=r" (ret)
+	   : "X" (&global), "X" (one), "X" (minus_one), "X" (zero));
+  return ret;
+#else
   switch (global)
     {
     case 1:
@@ -35,6 +57,7 @@ foo1_ifunc (void)
     default:
       return zero;
     }
+#endif
 }
 
 void * foo2_ifunc (void) __asm__ ("foo2");
@@ -43,6 +66,28 @@ __asm__(".type foo2, %gnu_indirect_function");
 void * 
 foo2_ifunc (void)
 {
+#if defined (__powerpc__)
+  register void *ret __asm__ ("r3");
+  __asm__ ("mflr 12\n\t"
+	   "bcl 20,31,1f\n"
+	   "1:\tmflr 11\n\t"
+	   "mtlr 12\n\t"
+	   "addis 12,11,global-1b@ha\n\t"
+	   "lwz 12,global-1b@l(12)\n\t"
+	   "addis %0,11,%2-1b@ha\n\t"
+	   "addi %0,%0,%2-1b@l\n\t"
+	   "cmpwi 12,1\n\t"
+	   "beqlr\n\t"
+	   "addis %0,11,%3-1b@ha\n\t"
+	   "addi %0,%0,%3-1b@l\n\t"
+	   "cmpwi 12,-1\n\t"
+	   "beqlr\n\t"
+	   "addis %0,11,%4-1b@ha\n\t"
+	   "addi %0,%0,%4-1b@l"
+	   : "=r" (ret)
+	   : "X" (&global), "X" (minus_one), "X" (one), "X" (zero));
+  return ret;
+#else
   switch (global)
     {
     case 1:
@@ -52,6 +97,7 @@ foo2_ifunc (void)
     default:
       return zero;
     }
+#endif
 }
 
 void * foo3_ifunc (void) __asm__ ("foo3");
@@ -60,6 +106,28 @@ __asm__(".type foo3, %gnu_indirect_function");
 void * 
 foo3_ifunc (void)
 {
+#if defined (__powerpc__)
+  register void *ret __asm__ ("r3");
+  __asm__ ("mflr 12\n\t"
+	   "bcl 20,31,1f\n"
+	   "1:\tmflr 11\n\t"
+	   "mtlr 12\n\t"
+	   "addis 12,11,global-1b@ha\n\t"
+	   "lwz 12,global-1b@l(12)\n\t"
+	   "addis %0,11,%2-1b@ha\n\t"
+	   "addi %0,%0,%2-1b@l\n\t"
+	   "cmpwi 12,1\n\t"
+	   "beqlr\n\t"
+	   "addis %0,11,%3-1b@ha\n\t"
+	   "addi %0,%0,%3-1b@l\n\t"
+	   "cmpwi 12,-1\n\t"
+	   "beqlr\n\t"
+	   "addis %0,11,%4-1b@ha\n\t"
+	   "addi %0,%0,%4-1b@l"
+	   : "=r" (ret)
+	   : "X" (&global), "X" (one), "X" (zero), "X" (minus_one));
+  return ret;
+#else
   switch (global)
     {
     case 1:
@@ -69,4 +137,5 @@ foo3_ifunc (void)
     default:
       return minus_one;
     }
+#endif
 }
diff --git a/elf/ifuncmain1.c b/elf/ifuncmain1.c
index de7ffe8..f395cca 100644
--- a/elf/ifuncmain1.c
+++ b/elf/ifuncmain1.c
@@ -7,8 +7,6 @@
 
 #include <stdlib.h>
 
-int global = -1;
-
 int ret_foo;
 int ret_foo_hidden;
 int ret_foo_protected;
@@ -20,6 +18,10 @@ extern int foo_protected (void);
 typedef int (*foo_p) (void);
 #endif
 
+#ifdef __powerpc__
+#define abort() __asm__ (".long 0")
+#endif
+
 foo_p foo_ptr = foo;
 foo_p foo_procted_ptr = foo_protected;
 
diff --git a/elf/ifuncmain1vis.c b/elf/ifuncmain1vis.c
index a239d2d..2b12197 100644
--- a/elf/ifuncmain1vis.c
+++ b/elf/ifuncmain1vis.c
@@ -7,8 +7,6 @@
 
 #include <stdlib.h>
 
-int global = -1;
-
 int ret_foo;
 int ret_foo_hidden;
 int ret_foo_protected;
@@ -19,6 +17,9 @@ extern int foo_protected (void);
 #ifndef FOO_P
 typedef int (*foo_p) (void);
 #endif
+#ifdef __powerpc__
+#define abort() __asm__ (".long 0")
+#endif
 
 foo_p foo_ptr = foo;
 foo_p foo_procted_ptr = foo_protected;
diff --git a/elf/ifuncmain2.c b/elf/ifuncmain2.c
index cd9b2c8..96efc37 100644
--- a/elf/ifuncmain2.c
+++ b/elf/ifuncmain2.c
@@ -2,8 +2,9 @@
    STT_GNU_IFUNC definitions.  */
 
 #include <stdlib.h>
-
-int global = -1;
+#ifdef __powerpc__
+#define abort() __asm__ (".long 0")
+#endif
 
 extern int foo1 (void);
 
diff --git a/elf/ifuncmain3.c b/elf/ifuncmain3.c
index 5d067cc..1ba9c60 100644
--- a/elf/ifuncmain3.c
+++ b/elf/ifuncmain3.c
@@ -8,6 +8,9 @@
 #include <dlfcn.h>
 #include <stdlib.h>
 #include <stdio.h>
+#ifdef __powerpc__
+#define abort() __asm__ (".long 0")
+#endif
 
 typedef int (*foo_p) (void);
 
diff --git a/elf/ifuncmain5.c b/elf/ifuncmain5.c
index 7f128d0..ddb134e 100644
--- a/elf/ifuncmain5.c
+++ b/elf/ifuncmain5.c
@@ -1,8 +1,9 @@
 /* Test STT_GNU_IFUNC symbols with dynamic function pointer only.  */
 
 #include <stdlib.h>
-
-int global = -1;
+#ifdef __powerpc__
+#define abort() __asm__ (".long 0")
+#endif
 
 extern int foo (void);
 extern int foo_protected (void);
diff --git a/elf/ifuncmain6pie.c b/elf/ifuncmain6pie.c
index 06f179b..247e4ff 100644
--- a/elf/ifuncmain6pie.c
+++ b/elf/ifuncmain6pie.c
@@ -6,6 +6,9 @@
  */
 
 #include <stdlib.h>
+#ifdef __powerpc__
+#define abort() __asm__ (".long 0")
+#endif
 
 typedef int (*foo_p) (void);
 extern foo_p foo_ptr;
@@ -22,7 +25,20 @@ __asm__(".type foo, %gnu_indirect_function");
 void *
 foo_ifunc (void)
 {
+#if defined (__powerpc__)
+  register void *ret __asm__ ("r3");
+  __asm__ ("mflr 12\n\t"
+	   "bcl 20,31,1f\n"
+	   "1:\tmflr %0\n\t"
+	   "mtlr 12\n\t"
+	   "addis %0,%0,%1-1b@ha\n\t"
+	   "addi %0,%0,%1-1b@l"
+	   : "=r" (ret)
+	   : "X" (one));
+  return ret;
+#else
   return one;
+#endif
 }
 
 extern int foo (void);
diff --git a/elf/ifuncmain7.c b/elf/ifuncmain7.c
index 099e929..a09ed7f 100644
--- a/elf/ifuncmain7.c
+++ b/elf/ifuncmain7.c
@@ -5,6 +5,9 @@
  */
 
 #include <stdlib.h>
+#ifdef __powerpc__
+#define abort() __asm__ (".long 0")
+#endif
 
 extern int foo (void);
 
@@ -21,7 +24,20 @@ static void *
 __attribute__ ((used))
 foo_ifunc (void)
 {
+#if defined (__powerpc__)
+  register void *ret __asm__ ("r3");
+  __asm__ ("mflr 12\n\t"
+	   "bcl 20,31,1f\n"
+	   "1:\tmflr %0\n\t"
+	   "mtlr 12\n\t"
+	   "addis %0,%0,%1-1b@ha\n\t"
+	   "addi %0,%0,%1-1b@l"
+	   : "=r" (ret)
+	   : "X" (one));
+  return ret;
+#else
   return one;
+#endif
 }
 
 typedef int (*foo_p) (void);
diff --git a/elf/ifuncmod1.c b/elf/ifuncmod1.c
index a1697b5..e0dc97e 100644
--- a/elf/ifuncmod1.c
+++ b/elf/ifuncmod1.c
@@ -5,7 +5,7 @@
    3. Visibility.
  */
 
-extern int global;
+int global __attribute__ ((visibility ("protected"))) = -1;
 
 static int
 one (void)
@@ -20,7 +20,7 @@ minus_one (void)
 }
 
 static int
-zero (void) 
+zero (void)
 {
   return 0;
 }
@@ -28,9 +28,31 @@ zero (void)
 void * foo_ifunc (void) __asm__ ("foo");
 __asm__(".type foo, %gnu_indirect_function");
 
-void * 
+void *
 foo_ifunc (void)
 {
+#if defined (__powerpc__)
+  register void *ret __asm__ ("r3");
+  __asm__ ("mflr 12\n\t"
+	   "bcl 20,31,1f\n"
+	   "1:\tmflr 11\n\t"
+	   "mtlr 12\n\t"
+	   "addis 12,11,global-1b@ha\n\t"
+	   "lwz 12,global-1b@l(12)\n\t"
+	   "addis %0,11,%2-1b@ha\n\t"
+	   "addi %0,%0,%2-1b@l\n\t"
+	   "cmpwi 12,1\n\t"
+	   "beqlr\n\t"
+	   "addis %0,11,%3-1b@ha\n\t"
+	   "addi %0,%0,%3-1b@l\n\t"
+	   "cmpwi 12,-1\n\t"
+	   "beqlr\n\t"
+	   "addis %0,11,%4-1b@ha\n\t"
+	   "addi %0,%0,%4-1b@l"
+	   : "=r" (ret)
+	   : "X" (&global), "X" (one), "X" (minus_one), "X" (zero));
+  return ret;
+#else
   switch (global)
     {
     case 1:
@@ -40,14 +62,37 @@ foo_ifunc (void)
     default:
       return zero;
     }
+#endif
 }
 
 void * foo_hidden_ifunc (void) __asm__ ("foo_hidden");
 __asm__(".type foo_hidden, %gnu_indirect_function");
 
-void * 
+void *
 foo_hidden_ifunc (void)
 {
+#if defined (__powerpc__)
+  register void *ret __asm__ ("r3");
+  __asm__ ("mflr 12\n\t"
+	   "bcl 20,31,1f\n"
+	   "1:\tmflr 11\n\t"
+	   "mtlr 12\n\t"
+	   "addis 12,11,global-1b@ha\n\t"
+	   "lwz 12,global-1b@l(12)\n\t"
+	   "addis %0,11,%2-1b@ha\n\t"
+	   "addi %0,%0,%2-1b@l\n\t"
+	   "cmpwi 12,1\n\t"
+	   "beqlr\n\t"
+	   "addis %0,11,%3-1b@ha\n\t"
+	   "addi %0,%0,%3-1b@l\n\t"
+	   "cmpwi 12,-1\n\t"
+	   "beqlr\n\t"
+	   "addis %0,11,%4-1b@ha\n\t"
+	   "addi %0,%0,%4-1b@l"
+	   : "=r" (ret)
+	   : "X" (&global), "X" (minus_one), "X" (one), "X" (zero));
+  return ret;
+#else
   switch (global)
     {
     case 1:
@@ -57,14 +102,37 @@ foo_hidden_ifunc (void)
     default:
       return zero;
     }
+#endif
 }
 
 void * foo_protected_ifunc (void) __asm__ ("foo_protected");
 __asm__(".type foo_protected, %gnu_indirect_function");
 
-void * 
+void *
 foo_protected_ifunc (void)
 {
+#if defined (__powerpc__)
+  register void *ret __asm__ ("r3");
+  __asm__ ("mflr 12\n\t"
+	   "bcl 20,31,1f\n"
+	   "1:\tmflr 11\n\t"
+	   "mtlr 12\n\t"
+	   "addis 12,11,global-1b@ha\n\t"
+	   "lwz 12,global-1b@l(12)\n\t"
+	   "addis %0,11,%2-1b@ha\n\t"
+	   "addi %0,%0,%2-1b@l\n\t"
+	   "cmpwi 12,1\n\t"
+	   "beqlr\n\t"
+	   "addis %0,11,%3-1b@ha\n\t"
+	   "addi %0,%0,%3-1b@l\n\t"
+	   "cmpwi 12,-1\n\t"
+	   "beqlr\n\t"
+	   "addis %0,11,%4-1b@ha\n\t"
+	   "addi %0,%0,%4-1b@l"
+	   : "=r" (ret)
+	   : "X" (&global), "X" (one), "X" (zero), "X" (minus_one));
+  return ret;
+#else
   switch (global)
     {
     case 1:
@@ -74,6 +142,7 @@ foo_protected_ifunc (void)
     default:
       return minus_one;
     }
+#endif
 }
 
 /* Test hidden indirect function.  */
diff --git a/elf/ifuncmod3.c b/elf/ifuncmod3.c
index 379d2c8..ca2d962 100644
--- a/elf/ifuncmod3.c
+++ b/elf/ifuncmod3.c
@@ -5,4 +5,3 @@
 int ret_foo;
 int ret_foo_hidden;
 int ret_foo_protected;
-int global = -1;
diff --git a/elf/ifuncmod5.c b/elf/ifuncmod5.c
index 2ca1c71..121666f 100644
--- a/elf/ifuncmod5.c
+++ b/elf/ifuncmod5.c
@@ -1,6 +1,6 @@
 /* Test STT_GNU_IFUNC symbols without direct function call.  */
 
-extern int global;
+int global __attribute__ ((visibility ("protected"))) = -1;
 
 static int
 one (void)
@@ -26,6 +26,28 @@ __asm__(".type foo, %gnu_indirect_function");
 void *
 foo_ifunc (void)
 {
+#if defined (__powerpc__)
+  register void *ret __asm__ ("r3");
+  __asm__ ("mflr 12\n\t"
+	   "bcl 20,31,1f\n"
+	   "1:\tmflr 11\n\t"
+	   "mtlr 12\n\t"
+	   "addis 12,11,global-1b@ha\n\t"
+	   "lwz 12,global-1b@l(12)\n\t"
+	   "addis %0,11,%2-1b@ha\n\t"
+	   "addi %0,%0,%2-1b@l\n\t"
+	   "cmpwi 12,1\n\t"
+	   "beqlr\n\t"
+	   "addis %0,11,%3-1b@ha\n\t"
+	   "addi %0,%0,%3-1b@l\n\t"
+	   "cmpwi 12,-1\n\t"
+	   "beqlr\n\t"
+	   "addis %0,11,%4-1b@ha\n\t"
+	   "addi %0,%0,%4-1b@l"
+	   : "=r" (ret)
+	   : "X" (&global), "X" (one), "X" (minus_one), "X" (zero));
+  return ret;
+#else
   switch (global)
     {
     case 1:
@@ -35,6 +57,7 @@ foo_ifunc (void)
     default:
       return zero;
     }
+#endif
 }
 
 void * foo_hidden_ifunc (void) __asm__ ("foo_hidden");
@@ -43,6 +66,28 @@ __asm__(".type foo_hidden, %gnu_indirect_function");
 void *
 foo_hidden_ifunc (void)
 {
+#if defined (__powerpc__)
+  register void *ret __asm__ ("r3");
+  __asm__ ("mflr 12\n\t"
+	   "bcl 20,31,1f\n"
+	   "1:\tmflr 11\n\t"
+	   "mtlr 12\n\t"
+	   "addis 12,11,global-1b@ha\n\t"
+	   "lwz 12,global-1b@l(12)\n\t"
+	   "addis %0,11,%2-1b@ha\n\t"
+	   "addi %0,%0,%2-1b@l\n\t"
+	   "cmpwi 12,1\n\t"
+	   "beqlr\n\t"
+	   "addis %0,11,%3-1b@ha\n\t"
+	   "addi %0,%0,%3-1b@l\n\t"
+	   "cmpwi 12,-1\n\t"
+	   "beqlr\n\t"
+	   "addis %0,11,%4-1b@ha\n\t"
+	   "addi %0,%0,%4-1b@l"
+	   : "=r" (ret)
+	   : "X" (&global), "X" (minus_one), "X" (one), "X" (zero));
+  return ret;
+#else
   switch (global)
     {
     case 1:
@@ -52,6 +97,7 @@ foo_hidden_ifunc (void)
     default:
       return zero;
     }
+#endif
 }
 
 void * foo_protected_ifunc (void) __asm__ ("foo_protected");
@@ -60,6 +106,28 @@ __asm__(".type foo_protected, %gnu_indirect_function");
 void *
 foo_protected_ifunc (void)
 {
+#if defined (__powerpc__)
+  register void *ret __asm__ ("r3");
+  __asm__ ("mflr 12\n\t"
+	   "bcl 20,31,1f\n"
+	   "1:\tmflr 11\n\t"
+	   "mtlr 12\n\t"
+	   "addis 12,11,global-1b@ha\n\t"
+	   "lwz 12,global-1b@l(12)\n\t"
+	   "addis %0,11,%2-1b@ha\n\t"
+	   "addi %0,%0,%2-1b@l\n\t"
+	   "cmpwi 12,1\n\t"
+	   "beqlr\n\t"
+	   "addis %0,11,%3-1b@ha\n\t"
+	   "addi %0,%0,%3-1b@l\n\t"
+	   "cmpwi 12,-1\n\t"
+	   "beqlr\n\t"
+	   "addis %0,11,%4-1b@ha\n\t"
+	   "addi %0,%0,%4-1b@l"
+	   : "=r" (ret)
+	   : "X" (&global), "X" (one), "X" (zero), "X" (minus_one));
+  return ret;
+#else
   switch (global)
     {
     case 1:
@@ -69,6 +137,7 @@ foo_protected_ifunc (void)
     default:
       return minus_one;
     }
+#endif
 }
 
 /* Test hidden indirect function.  */

-- 
Alan Modra
Australia Development Lab, IBM


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