diff options
Diffstat (limited to 'sysdeps/powerpc/dl-start.S')
-rw-r--r-- | sysdeps/powerpc/dl-start.S | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/sysdeps/powerpc/dl-start.S b/sysdeps/powerpc/dl-start.S new file mode 100644 index 0000000000..91c0896a8f --- /dev/null +++ b/sysdeps/powerpc/dl-start.S @@ -0,0 +1,111 @@ +/* Machine-dependent ELF startup code. PowerPC version. + Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <sysdep.h> + +/* Initial entry point code for the dynamic linker. + The C function `_dl_start' is the real entry point; + its return value is the user program's entry point. */ +ENTRY(_start) +/* We start with the following on the stack, from top: + argc (4 bytes); + arguments for program (terminated by NULL); + environment variables (terminated by NULL); + arguments for the program loader. */ + +/* Call _dl_start with one parameter pointing at argc */ + mr %r3,%r1 +/* (we have to frob the stack pointer a bit to allow room for + _dl_start to save the link register). */ + li %r4,0 + addi %r1,%r1,-16 + stw %r4,0(%r1) + bl _dl_start@local + +/* Now, we do our main work of calling initialisation procedures. + The ELF ABI doesn't say anything about parameters for these, + so we just pass argc, argv, and the environment. + Changing these is strongly discouraged (not least because argc is + passed by value!). */ + +/* Put our GOT pointer in r31, */ + bl _GLOBAL_OFFSET_TABLE_-4@local + mflr %r31 +/* the address of _start in r30, */ + mr %r30,%r3 +/* &_dl_argc in 29, &_dl_argv in 27, and _dl_default_scope in 28. */ + lwz %r28,_dl_default_scope@got(%r31) + lwz %r29,_dl_argc@got(%r31) + lwz %r27,_dl_argv@got(%r31) +0: +/* Set initfunc = _dl_init_next(_dl_default_scope[2]) */ + lwz %r3,8(%r28) + bl _dl_init_next@plt +/* If initfunc is NULL, we exit the loop; otherwise, */ + cmpwi %r3,0 + beq 1f +/* call initfunc(_dl_argc, _dl_argv, _dl_argv+_dl_argc+1) */ + mtlr %r3 + lwz %r3,0(%r29) + lwz %r4,0(%r27) + slwi %r5,%r3,2 + add %r5,%r4,%r5 + addi %r5,%r5,4 + blrl +/* and loop. */ + b 0b +1: +/* Now, to conform to the ELF ABI, we have to: */ +/* Pass argc (actually _dl_argc) in r3; */ + lwz %r3,0(%r29) +/* pass argv (actually _dl_argv) in r4; */ + lwz %r4,0(%r27) +/* pass envp (actually _dl_argv+_dl_argc+1) in r5; */ + slwi %r5,%r3,2 + add %r6,%r4,%r5 + addi %r5,%r6,4 +/* pass the auxilary vector in r6. This is passed to us just after _envp. */ +2: lwzu %r0,4(%r6) + cmpwi %r0,0 + bne 2b + addi %r6,%r6,4 +/* Pass a termination function pointer (in this case _dl_fini) in r7. */ + lwz %r7,_dl_fini@got(%r31) +/* Now, call the start function in r30... */ + mtctr %r30 + lwz %r26,_dl_starting_up@got(%r31) +/* Pass the stack pointer in r1 (so far so good), pointing to a NULL value. + (This lets our startup code distinguish between a program linked statically, + which linux will call with argc on top of the stack which will hopefully + never be zero, and a dynamically linked program which will always have + a NULL on the top of the stack). + Take the opportunity to clear LR, so anyone who accidentally returns + from _start gets SEGV. Also clear the next few words of the stack. */ + + li %r31,0 + stw %r31,0(%r1) + mtlr %r31 + stw %r31,4(%r1) + stw %r31,8(%r1) + stw %r31,12(%r1) +/* Clear _dl_starting_up. */ + stw %r31,0(%r26) +/* Go do it! */ + bctr +END(_start) |