This is the mail archive of the libc-alpha@sources.redhat.com 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]

PPC startup code


I just compiled up and tested glibc with the following patch to
start.S and libc-start.c, using the generic libc-start.c with a hack
to do the __aux_cache_init thing (inside #ifdef __powerpc__).  It all
works just fine.  With this patch we do the detection of static
binaries inside start.S.  We end up doing the same computations as
before, though, so it shouldn't break anything.  Some of the work that
the PPC dl-start.S does is now redundant and could be eliminated.

Roland, is this the sort of thing you wanted?  I assume there is a
cleaner way to do the __aux_cache_init thing in libc-start.c.

Paul.

diff -urN cvs/libc/sysdeps/powerpc/powerpc32/elf/start.S libc/sysdeps/powerpc/powerpc32/elf/start.S
--- cvs/libc/sysdeps/powerpc/powerpc32/elf/start.S	2002-12-10 07:37:22.000000000 +1100
+++ libc/sysdeps/powerpc/powerpc32/elf/start.S	2003-03-14 22:37:08.000000000 +1100
@@ -30,21 +30,49 @@
 	.long 	JUMPTARGET(__libc_csu_fini)
 	ASM_SIZE_DIRECTIVE(L(start_addresses))
 
+/* We get called in one of two ways.  If this is a statically linked
+   program, we get called directly from the kernel with r1 (stack pointer)
+   pointing to argc, followed by argv, NULL, environment, NULL,
+   auxiliary vector.  If this is a dynamically linked program, we get
+   called from dl-start.S with argc in r3, argv in r4, envp in r5,
+   auxvec in r6, _dl_fini in r7.  In this case r1 points to a 16-byte
+   stack frame which is all zeroes.
+
+   We distinguish between the two cases by looking at the word pointed
+   to by r1.  If it is non-zero we assume it is argc and therefore this
+   is a statically linked program.  */
+
 	.section ".text"
 ENTRY(_start)
- /* Save the stack pointer, in case we're statically linked under Linux.  */
+ /* Pass the top of stack pointer to __libc_start_main.  */
 	mr	r9,r1
+ /* Check if we were invoked from the kernel (i.e. statically linked).  */
+	lwz	r0,0(r1)
+	cmpwi	r0,0
+	beq	1f
+ /* Statically linked, so get argc and argv. */
+	mr	r3,r0
+	addi	r4,r1,4
+	li	r7,0		/* no termination procedure */
  /* Set up an initial stack frame, and clear the LR.  */
-	clrrwi	r1,r1,4
+ /* Strictly speaking we don't really need to do this for the dynamically
+    linked case since _start in dl-start.S has done it already... */
+1:	clrrwi	r1,r1,4
+	addi	r1,r1,-16
 	li	r0,0
-	stwu	r1,-16(r1)
 	mtlr	r0
 	stw	r0,0(r1)
- /* Set r13 to point at the 'small data area', and put the address of
-    start_addresses in r8...  */
-	lis	r8,L(start_addresses)@ha
-	lwzu	r13,L(start_addresses)@l(r8)
- /* and continue in libc-start, in glibc.  */
+ /* Set r13 to point at the 'small data area'. */
+	lis	r10,L(start_addresses)@ha
+	lwzu	r13,L(start_addresses)@l(r10)
+ /* Shuffle things around a bit to get the arguments in the
+    right order for the generic __libc_start_main, and call it.  */
+	mr	r8,r7		/* _dl_fini */
+	mr	r5,r4		/* argv */
+	mr	r4,r3		/* argc */
+	lwz	r3,4(r10)	/* main */
+	lwz	r6,8(r10)	/* __libc_csu_init */
+	lwz	r7,12(r10)	/* __libc_csu_fini */
 	b	JUMPTARGET(BP_SYM (__libc_start_main))
 END(_start)
 
diff -urN cvs/libc/sysdeps/generic/libc-start.c libc/sysdeps/generic/libc-start.c
--- cvs/libc/sysdeps/generic/libc-start.c	2003-03-03 13:50:46.000000000 +1100
+++ libc/sysdeps/generic/libc-start.c	2003-03-14 22:44:07.000000000 +1100
@@ -25,6 +25,11 @@
 
 extern void __libc_init_first (int argc, char **argv, char **envp);
 
+#if defined __powerpc__ && defined HAVE_AUX_VECTOR
+extern int __cache_line_size;
+weak_extern (__cache_line_size)
+#endif
+
 extern int __libc_multiple_libcs;
 extern void *__libc_stack_end;
 
@@ -43,6 +48,27 @@
 # include <atomic.h>
 #endif
 
+#if defined __powerpc__ && defined HAVE_AUX_VECTOR
+/* Scan the Aux Vector for the "Data Cache Block Size" entry.  If found
+   verify that the static extern __cache_line_size is defined by checking
+   for not NULL.  If it is defined then assign the cache block size
+   value to __cache_line_size.  */
+static inline void
+__aux_init_cache (ElfW(auxv_t) *av)
+{
+  for (; av->a_type != AT_NULL; ++av)
+    switch (av->a_type)
+      {
+      case AT_DCACHEBSIZE:
+        {
+          int *cls = & __cache_line_size;
+          if (cls != NULL)
+            *cls = av->a_un.a_val;
+        }
+        break;
+      }
+}
+#endif
 
 extern int BP_SYM (__libc_start_main) (int (*main) (int, char **, char **),
 				       int argc,
@@ -97,6 +123,11 @@
     }
 # endif
 
+#if defined __powerpc__ && defined HAVE_AUX_VECTOR
+  /* Initialize the __cache_line_size variable from the aux vector.  */
+  __aux_init_cache((ElfW(auxv_t) *) auxvec);
+#endif
+
   /* Initialize the thread library at least a bit since the libgcc
      functions are using thread functions if these are available and
      we need to setup errno.  If there is no thread library and we


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