This is the mail archive of the
libc-alpha@sources.redhat.com
mailing list for the glibc project.
PPC startup code
- From: Paul Mackerras <paulus at samba dot org>
- To: Franz Sirl <Franz dot Sirl-kernel at lauterbach dot com>,Roland McGrath <roland at redhat dot com>, sjmunroe at us dot ibm dot com
- Cc: libc-alpha at sources dot redhat dot com
- Date: Sat, 15 Mar 2003 12:05:06 +1100 (EST)
- Subject: PPC startup code
- Reply-to: paulus at samba dot org
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