190075Sobrien/*
290075Sobrien * Special support for eabi and SVR4
390075Sobrien *
490075Sobrien *   Copyright (C) 1995, 1996, 1998, 2000, 2001 Free Software Foundation, Inc.
590075Sobrien *   Written By Michael Meissner
690075Sobrien * 
790075Sobrien * This file is free software; you can redistribute it and/or modify it
890075Sobrien * under the terms of the GNU General Public License as published by the
990075Sobrien * Free Software Foundation; either version 2, or (at your option) any
1090075Sobrien * later version.
1190075Sobrien * 
1290075Sobrien * In addition to the permissions in the GNU General Public License, the
1390075Sobrien * Free Software Foundation gives you unlimited permission to link the
1490075Sobrien * compiled version of this file with other programs, and to distribute
1590075Sobrien * those programs without any restriction coming from the use of this
1690075Sobrien * file.  (The General Public License restrictions do apply in other
1790075Sobrien * respects; for example, they cover modification of the file, and
1890075Sobrien * distribution when not linked into another program.)
1990075Sobrien * 
2090075Sobrien * This file is distributed in the hope that it will be useful, but
2190075Sobrien * WITHOUT ANY WARRANTY; without even the implied warranty of
2290075Sobrien * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
2390075Sobrien * General Public License for more details.
2490075Sobrien * 
2590075Sobrien * You should have received a copy of the GNU General Public License
2690075Sobrien * along with this program; see the file COPYING.  If not, write to
27169689Skan * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
28169689Skan * Boston, MA 02110-1301, USA.
2990075Sobrien * 
3090075Sobrien *    As a special exception, if you link this library with files
3190075Sobrien *    compiled with GCC to produce an executable, this does not cause
3290075Sobrien *    the resulting executable to be covered by the GNU General Public License.
3390075Sobrien *    This exception does not however invalidate any other reasons why
3490075Sobrien *    the executable file might be covered by the GNU General Public License.
3590075Sobrien */ 
3690075Sobrien
3790075Sobrien/* Do any initializations needed for the eabi environment */
3890075Sobrien
3990075Sobrien	.file	"eabi.asm"
4090075Sobrien	.section ".text"
4190075Sobrien	#include "ppc-asm.h"
4290075Sobrien
4390075Sobrien#ifndef __powerpc64__
4490075Sobrien
4590075Sobrien	 .section ".got2","aw"
4690075Sobrien	.align	2
4790075Sobrien.LCTOC1 = . /* +32768 */
4890075Sobrien
4990075Sobrien/* Table of addresses */
5090075Sobrien.Ltable = .-.LCTOC1
5190075Sobrien	.long	.LCTOC1				/* address we are really at */
5290075Sobrien
5390075Sobrien.Lsda = .-.LCTOC1
5490075Sobrien	.long	_SDA_BASE_			/* address of the first small data area */
5590075Sobrien
5690075Sobrien.Lsdas = .-.LCTOC1
5790075Sobrien	.long	__SDATA_START__			/* start of .sdata/.sbss section */
5890075Sobrien
5990075Sobrien.Lsdae = .-.LCTOC1
6090075Sobrien	.long	__SBSS_END__			/* end of .sdata/.sbss section */
6190075Sobrien
6290075Sobrien.Lsda2 = .-.LCTOC1
6390075Sobrien	.long	_SDA2_BASE_			/* address of the second small data area */
6490075Sobrien
6590075Sobrien.Lsda2s = .-.LCTOC1
6690075Sobrien	.long	__SDATA2_START__		/* start of .sdata2/.sbss2 section */
6790075Sobrien
6890075Sobrien.Lsda2e = .-.LCTOC1
6990075Sobrien	.long	__SBSS2_END__			/* end of .sdata2/.sbss2 section */
7090075Sobrien
7190075Sobrien#ifdef _RELOCATABLE
7290075Sobrien.Lgots = .-.LCTOC1
7390075Sobrien	.long	__GOT_START__			/* Global offset table start */
7490075Sobrien
7590075Sobrien.Lgotm1 = .-.LCTOC1
7690075Sobrien	.long	_GLOBAL_OFFSET_TABLE_-4		/* end of GOT ptrs before BLCL + 3 reserved words */
7790075Sobrien
7890075Sobrien.Lgotm2 = .-.LCTOC1
7990075Sobrien	.long	_GLOBAL_OFFSET_TABLE_+12	/* start of GOT ptrs after BLCL + 3 reserved words */
8090075Sobrien
8190075Sobrien.Lgote = .-.LCTOC1
8290075Sobrien	.long	__GOT_END__			/* Global offset table end */
8390075Sobrien
8490075Sobrien.Lgot2s = .-.LCTOC1
8590075Sobrien	.long	__GOT2_START__			/* -mrelocatable GOT pointers start */
8690075Sobrien
8790075Sobrien.Lgot2e = .-.LCTOC1
8890075Sobrien	.long	__GOT2_END__			/* -mrelocatable GOT pointers end */
8990075Sobrien
9090075Sobrien.Lfixups = .-.LCTOC1
9190075Sobrien	.long	__FIXUP_START__			/* start of .fixup section */
9290075Sobrien
9390075Sobrien.Lfixupe = .-.LCTOC1
9490075Sobrien	.long	__FIXUP_END__			/* end of .fixup section */
9590075Sobrien
9690075Sobrien.Lctors = .-.LCTOC1
9790075Sobrien	.long	__CTOR_LIST__			/* start of .ctor section */
9890075Sobrien
9990075Sobrien.Lctore = .-.LCTOC1
10090075Sobrien	.long	__CTOR_END__			/* end of .ctor section */
10190075Sobrien
10290075Sobrien.Ldtors = .-.LCTOC1
10390075Sobrien	.long	__DTOR_LIST__			/* start of .dtor section */
10490075Sobrien
10590075Sobrien.Ldtore = .-.LCTOC1
10690075Sobrien	.long	__DTOR_END__			/* end of .dtor section */
10790075Sobrien
10890075Sobrien.Lexcepts = .-.LCTOC1
10990075Sobrien	.long	__EXCEPT_START__		/* start of .gcc_except_table section */
11090075Sobrien
11190075Sobrien.Lexcepte = .-.LCTOC1
11290075Sobrien	.long	__EXCEPT_END__			/* end of .gcc_except_table section */
11390075Sobrien
11490075Sobrien.Linit = .-.LCTOC1
11590075Sobrien	.long	.Linit_p			/* address of variable to say we've been called */
11690075Sobrien
11790075Sobrien	.text
11890075Sobrien	.align	2
11990075Sobrien.Lptr:
12090075Sobrien	.long	.LCTOC1-.Laddr			/* PC relative pointer to .got2 */
12190075Sobrien#endif
12290075Sobrien
12390075Sobrien	.data
12490075Sobrien	.align	2
12590075Sobrien.Linit_p:
12690075Sobrien	.long	0
12790075Sobrien
12890075Sobrien	.text
12990075Sobrien
13090075SobrienFUNC_START(__eabi)
13190075Sobrien
13290075Sobrien/* Eliminate -mrelocatable code if not -mrelocatable, so that this file can
13390075Sobrien   be assembled with other assemblers than GAS.  */
13490075Sobrien
13590075Sobrien#ifndef _RELOCATABLE
13690075Sobrien	addis	10,0,.Linit_p@ha		/* init flag */
13790075Sobrien	addis	11,0,.LCTOC1@ha			/* load address of .LCTOC1 */
13890075Sobrien	lwz	9,.Linit_p@l(10)		/* init flag */
13990075Sobrien	addi	11,11,.LCTOC1@l
14090075Sobrien	cmplwi	2,9,0				/* init flag != 0? */
14190075Sobrien	bnelr	2				/* return now, if we've been called already */
142117395Skan	stw	1,.Linit_p@l(10)		/* store a nonzero value in the done flag */
14390075Sobrien
14490075Sobrien#else /* -mrelocatable */
14590075Sobrien	mflr	0
14690075Sobrien	bl	.Laddr				/* get current address */
14790075Sobrien.Laddr:
14890075Sobrien	mflr	12				/* real address of .Laddr */
14990075Sobrien	lwz	11,(.Lptr-.Laddr)(12)		/* linker generated address of .LCTOC1 */
15090075Sobrien	add	11,11,12			/* correct to real pointer */
15190075Sobrien	lwz	12,.Ltable(11)			/* get linker's idea of where .Laddr is */
15290075Sobrien	lwz	10,.Linit(11)			/* address of init flag */
15390075Sobrien	subf.	12,12,11			/* calculate difference */
15490075Sobrien	lwzx	9,10,12				/* done flag */
15590075Sobrien	cmplwi	2,9,0				/* init flag != 0? */
15690075Sobrien	mtlr	0				/* restore in case branch was taken */
15790075Sobrien	bnelr	2				/* return now, if we've been called already */
158117395Skan	stwx	1,10,12				/* store a nonzero value in the done flag */
15990075Sobrien	beq+	0,.Lsdata			/* skip if we don't need to relocate */
16090075Sobrien
16190075Sobrien/* We need to relocate the .got2 pointers.  */
16290075Sobrien
16390075Sobrien	lwz	3,.Lgot2s(11)			/* GOT2 pointers start */
16490075Sobrien	lwz	4,.Lgot2e(11)			/* GOT2 pointers end */
16590075Sobrien	add	3,12,3				/* adjust pointers */
16690075Sobrien	add	4,12,4
16790075Sobrien	bl	FUNC_NAME(__eabi_convert)	/* convert pointers in .got2 section */
16890075Sobrien
16990075Sobrien/* Fixup the .ctor section for static constructors */
17090075Sobrien
17190075Sobrien	lwz	3,.Lctors(11)			/* constructors pointers start */
17290075Sobrien	lwz	4,.Lctore(11)			/* constructors pointers end */
17390075Sobrien	bl	FUNC_NAME(__eabi_convert)	/* convert constructors */
17490075Sobrien
17590075Sobrien/* Fixup the .dtor section for static destructors */
17690075Sobrien
17790075Sobrien	lwz	3,.Ldtors(11)			/* destructors pointers start */
17890075Sobrien	lwz	4,.Ldtore(11)			/* destructors pointers end */
17990075Sobrien	bl	FUNC_NAME(__eabi_convert)	/* convert destructors */
18090075Sobrien
18190075Sobrien/* Fixup the .gcc_except_table section for G++ exceptions */
18290075Sobrien
18390075Sobrien	lwz	3,.Lexcepts(11)			/* exception table pointers start */
18490075Sobrien	lwz	4,.Lexcepte(11)			/* exception table pointers end */
18590075Sobrien	bl	FUNC_NAME(__eabi_convert)	/* convert exceptions */
18690075Sobrien
18790075Sobrien/* Fixup the addresses in the GOT below _GLOBAL_OFFSET_TABLE_-4 */
18890075Sobrien
18990075Sobrien	lwz	3,.Lgots(11)			/* GOT table pointers start */
19090075Sobrien	lwz	4,.Lgotm1(11)			/* GOT table pointers below _GLOBAL_OFFSET_TABLE-4 */
19190075Sobrien	bl	FUNC_NAME(__eabi_convert)	/* convert lower GOT */
19290075Sobrien
19390075Sobrien/* Fixup the addresses in the GOT above _GLOBAL_OFFSET_TABLE_+12 */
19490075Sobrien
19590075Sobrien	lwz	3,.Lgotm2(11)			/* GOT table pointers above _GLOBAL_OFFSET_TABLE+12 */
19690075Sobrien	lwz	4,.Lgote(11)			/* GOT table pointers end */
19790075Sobrien	bl	FUNC_NAME(__eabi_convert)	/* convert lower GOT */
19890075Sobrien
19990075Sobrien/* Fixup any user initialized pointers now (the compiler drops pointers to */
20090075Sobrien/* each of the relocs that it does in the .fixup section).  */
20190075Sobrien
20290075Sobrien.Lfix:
20390075Sobrien	lwz	3,.Lfixups(11)			/* fixup pointers start */
20490075Sobrien	lwz	4,.Lfixupe(11)			/* fixup pointers end */
20590075Sobrien	bl	FUNC_NAME(__eabi_uconvert)	/* convert user initialized pointers */
20690075Sobrien
20790075Sobrien.Lsdata:
20890075Sobrien	mtlr	0				/* restore link register */
20990075Sobrien#endif /* _RELOCATABLE */
21090075Sobrien
21190075Sobrien/* Only load up register 13 if there is a .sdata and/or .sbss section */
21290075Sobrien	lwz	3,.Lsdas(11)			/* start of .sdata/.sbss section */
21390075Sobrien	lwz	4,.Lsdae(11)			/* end of .sdata/.sbss section */
21490075Sobrien	cmpw	1,3,4				/* .sdata/.sbss section non-empty? */
21590075Sobrien	beq-	1,.Lsda2l			/* skip loading r13 */
21690075Sobrien
21790075Sobrien	lwz	13,.Lsda(11)			/* load r13 with _SDA_BASE_ address */
21890075Sobrien
21990075Sobrien/* Only load up register 2 if there is a .sdata2 and/or .sbss2 section */
22090075Sobrien
22190075Sobrien.Lsda2l:	
22290075Sobrien	lwz	3,.Lsda2s(11)			/* start of .sdata/.sbss section */
22390075Sobrien	lwz	4,.Lsda2e(11)			/* end of .sdata/.sbss section */
22490075Sobrien	cmpw	1,3,4				/* .sdata/.sbss section non-empty? */
22590075Sobrien	beq+	1,.Ldone			/* skip loading r2 */
22690075Sobrien
22790075Sobrien	lwz	2,.Lsda2(11)			/* load r2 with _SDA2_BASE_ address */
22890075Sobrien
22990075Sobrien/* Done adjusting pointers, return by way of doing the C++ global constructors.  */
23090075Sobrien
23190075Sobrien.Ldone:
23290075Sobrien	b	FUNC_NAME(__init)	/* do any C++ global constructors (which returns to caller) */
23390075SobrienFUNC_END(__eabi)
23490075Sobrien
23590075Sobrien/* Special subroutine to convert a bunch of pointers directly.
23690075Sobrien   r0		has original link register
23790075Sobrien   r3		has low pointer to convert
23890075Sobrien   r4		has high pointer to convert
23990075Sobrien   r5 .. r10	are scratch registers
24090075Sobrien   r11		has the address of .LCTOC1 in it.
24190075Sobrien   r12		has the value to add to each pointer
24290075Sobrien   r13 .. r31	are unchanged */
24390075Sobrien	
24490075SobrienFUNC_START(__eabi_convert)
24590075Sobrien        cmplw	1,3,4				/* any pointers to convert? */
24690075Sobrien        subf	5,3,4				/* calculate number of words to convert */
24790075Sobrien        bclr	4,4				/* return if no pointers */
24890075Sobrien
24990075Sobrien        srawi	5,5,2
25090075Sobrien	addi	3,3,-4				/* start-4 for use with lwzu */
25190075Sobrien        mtctr	5
25290075Sobrien
25390075Sobrien.Lcvt:
25490075Sobrien	lwzu	6,4(3)				/* pointer to convert */
255146895Skan	cmpwi	0,6,0
25690075Sobrien	beq-	.Lcvt2				/* if pointer is null, don't convert */
25790075Sobrien
25890075Sobrien        add	6,6,12				/* convert pointer */
25990075Sobrien        stw	6,0(3)
26090075Sobrien.Lcvt2:
26190075Sobrien        bdnz+	.Lcvt
26290075Sobrien        blr
26390075Sobrien
26490075SobrienFUNC_END(__eabi_convert)
26590075Sobrien
26690075Sobrien/* Special subroutine to convert the pointers the user has initialized.  The
26790075Sobrien   compiler has placed the address of the initialized pointer into the .fixup
26890075Sobrien   section.
26990075Sobrien
27090075Sobrien   r0		has original link register
27190075Sobrien   r3		has low pointer to convert
27290075Sobrien   r4		has high pointer to convert
27390075Sobrien   r5 .. r10	are scratch registers
27490075Sobrien   r11		has the address of .LCTOC1 in it.
27590075Sobrien   r12		has the value to add to each pointer
27690075Sobrien   r13 .. r31	are unchanged */
27790075Sobrien	
27890075SobrienFUNC_START(__eabi_uconvert)
27990075Sobrien        cmplw	1,3,4				/* any pointers to convert? */
28090075Sobrien        subf	5,3,4				/* calculate number of words to convert */
28190075Sobrien        bclr	4,4				/* return if no pointers */
28290075Sobrien
28390075Sobrien        srawi	5,5,2
28490075Sobrien	addi	3,3,-4				/* start-4 for use with lwzu */
28590075Sobrien        mtctr	5
28690075Sobrien
28790075Sobrien.Lucvt:
28890075Sobrien	lwzu	6,4(3)				/* next pointer to pointer to convert */
28990075Sobrien	add	6,6,12				/* adjust pointer */
29090075Sobrien	lwz	7,0(6)				/* get the pointer it points to */
29190075Sobrien	stw	6,0(3)				/* store adjusted pointer */
29290075Sobrien	add	7,7,12				/* adjust */
29390075Sobrien	stw	7,0(6)
29490075Sobrien        bdnz+	.Lucvt
29590075Sobrien        blr
29690075Sobrien
29790075SobrienFUNC_END(__eabi_uconvert)
29890075Sobrien
29990075Sobrien#endif
300