Blame sysdeps/powerpc/powerpc32/dl-start.S

Packit 6c4009
/* Machine-dependent ELF startup code.  PowerPC version.
Packit 6c4009
   Copyright (C) 1995-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <sysdep.h>
Packit 6c4009
Packit 6c4009
/* Initial entry point code for the dynamic linker.
Packit 6c4009
   The C function `_dl_start' is the real entry point;
Packit 6c4009
   its return value is the user program's entry point.	*/
Packit 6c4009
ENTRY(_start)
Packit 6c4009
/* We start with the following on the stack, from top:
Packit 6c4009
   argc (4 bytes);
Packit 6c4009
   arguments for program (terminated by NULL);
Packit 6c4009
   environment variables (terminated by NULL);
Packit 6c4009
   arguments for the program loader. */
Packit 6c4009
Packit 6c4009
/* Call _dl_start with one parameter pointing at argc */
Packit 6c4009
	mr	r3,r1
Packit 6c4009
/* (we have to frob the stack pointer a bit to allow room for
Packit 6c4009
   _dl_start to save the link register).  */
Packit 6c4009
	li	r4,0
Packit 6c4009
	addi	r1,r1,-16
Packit 6c4009
	stw	r4,0(r1)
Packit 6c4009
	bl	_dl_start@local
Packit 6c4009
Packit 6c4009
	/* FALLTHRU */
Packit 6c4009
_dl_start_user:
Packit 6c4009
/* Now, we do our main work of calling initialisation procedures.
Packit 6c4009
   The ELF ABI doesn't say anything about parameters for these,
Packit 6c4009
   so we just pass argc, argv, and the environment.
Packit 6c4009
   Changing these is strongly discouraged (not least because argc is
Packit 6c4009
   passed by value!).  */
Packit 6c4009
Packit 6c4009
/*  Put our GOT pointer in r31, */
Packit 6c4009
	SETUP_GOT_ACCESS(r31,got_label)
Packit 6c4009
	addis	r31,r31,_GLOBAL_OFFSET_TABLE_-got_label@ha
Packit 6c4009
	addi	r31,r31,_GLOBAL_OFFSET_TABLE_-got_label@l
Packit 6c4009
/*  the address of _start in r30, */
Packit 6c4009
	mr	r30,r3
Packit 6c4009
/*  &_dl_argc in 29, &_dl_argv in 27, and _dl_loaded in 28.  */
Packit 6c4009
	lwz	r28,_rtld_local@got(r31)
Packit 6c4009
	lwz	r29,_dl_argc@got(r31)
Packit 6c4009
	lwz	r27,__GI__dl_argv@got(r31)
Packit 6c4009
Packit 6c4009
/* Call _dl_init (_dl_loaded, _dl_argc, _dl_argv, _dl_argv+_dl_argc+1). */
Packit 6c4009
	lwz	r3,0(r28)
Packit 6c4009
	lwz	r4,0(r29)
Packit 6c4009
	lwz	r5,0(r27)
Packit 6c4009
	slwi	r6,r4,2
Packit 6c4009
	add	r6,r5,r6
Packit 6c4009
	addi	r6,r6,4
Packit 6c4009
	bl	_dl_init@local
Packit 6c4009
Packit 6c4009
/* Now, to conform to the ELF ABI, we have to: */
Packit 6c4009
/* Pass argc (actually _dl_argc) in r3; */
Packit 6c4009
	lwz	r3,0(r29)
Packit 6c4009
/* pass argv (actually _dl_argv) in r4; */
Packit 6c4009
	lwz	r4,0(r27)
Packit 6c4009
/* pass envp (actually _dl_argv+_dl_argc+1) in r5; */
Packit 6c4009
	slwi	r5,r3,2
Packit 6c4009
	add	r6,r4,r5
Packit 6c4009
	addi	r5,r6,4
Packit 6c4009
/* pass the auxiliary vector in r6. This is passed to us just after _envp.  */
Packit 6c4009
2:	lwzu	r0,4(r6)
Packit 6c4009
	cmpwi	r0,0
Packit 6c4009
	bne	2b
Packit 6c4009
	addi	r6,r6,4
Packit 6c4009
/* Pass a termination function pointer (in this case _dl_fini) in r7.  */
Packit 6c4009
	lwz	r7,_dl_fini@got(r31)
Packit 6c4009
/* Now, call the start function in r30... */
Packit 6c4009
	mtctr	r30
Packit 6c4009
/* Pass the stack pointer in r1 (so far so good), pointing to a NULL value.
Packit 6c4009
   (This lets our startup code distinguish between a program linked statically,
Packit 6c4009
   which linux will call with argc on top of the stack which will hopefully
Packit 6c4009
   never be zero, and a dynamically linked program which will always have
Packit 6c4009
   a NULL on the top of the stack).
Packit 6c4009
   Take the opportunity to clear LR, so anyone who accidentally returns
Packit 6c4009
   from _start gets SEGV.  Also clear the next few words of the stack.  */
Packit 6c4009
Packit 6c4009
_dl_main_dispatch:
Packit 6c4009
	li	r31,0
Packit 6c4009
	stw	r31,0(r1)
Packit 6c4009
	mtlr	r31
Packit 6c4009
	stw	r31,4(r1)
Packit 6c4009
	stw	r31,8(r1)
Packit 6c4009
	stw	r31,12(r1)
Packit 6c4009
/* Go do it!  */
Packit 6c4009
	bctr
Packit 6c4009
END(_start)