xref: /onnv-gate/usr/src/cmd/sgs/rtld.4.x/rtld.4.x.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  *
26*0Sstevel@tonic-gate  * Binary compatibility ld.so.  Intercepts the reference of a pre-SVR4
27*0Sstevel@tonic-gate  * SunOS executable to the dynamic linker, and then redirects to the
28*0Sstevel@tonic-gate  * "real" post-SVR4 SunOS ld.so.
29*0Sstevel@tonic-gate  */
30*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
31*0Sstevel@tonic-gate 
32*0Sstevel@tonic-gate /*
33*0Sstevel@tonic-gate  * Import data structures (N.B.: from 5.x).
34*0Sstevel@tonic-gate  */
35*0Sstevel@tonic-gate #include <sys/types.h>
36*0Sstevel@tonic-gate #include <sys/mman.h>
37*0Sstevel@tonic-gate #include <sys/fcntl.h>
38*0Sstevel@tonic-gate #include <sys/stat.h>
39*0Sstevel@tonic-gate #include <sys/sysconfig.h>
40*0Sstevel@tonic-gate #include <sys/auxv.h>
41*0Sstevel@tonic-gate #include <sys/archsystm.h>
42*0Sstevel@tonic-gate #include <elf.h>
43*0Sstevel@tonic-gate #include <link.h>
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate /*
46*0Sstevel@tonic-gate  * Relocation manifest constants and macros.
47*0Sstevel@tonic-gate  */
48*0Sstevel@tonic-gate #define	ALIGN(x, a)		((int)(x) & ~((int)(a) - 1))
49*0Sstevel@tonic-gate #define	ROUND(x, a)		(((int)(x) + ((int)(a) - 1)) & \
50*0Sstevel@tonic-gate 				    ~((int)(a) - 1))
51*0Sstevel@tonic-gate #define	DYNAMIC_VERSION2	2
52*0Sstevel@tonic-gate #define	RELOC_SIZE		(sizeof (struct relocation_info))
53*0Sstevel@tonic-gate #define	RELOCOFF(x)		(x)->v2->ld_rel
54*0Sstevel@tonic-gate #define	MASK(n)			((1<<(n))-1)
55*0Sstevel@tonic-gate #define	IN_RANGE(v, n)		((-(1<<((n)-1))) <= (v) && (v) < (1<<((n)-1)))
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate void	aout_reloc_write();
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate /*
60*0Sstevel@tonic-gate  * 4.x SunOS Dynamic Link Editor public definitions (much derived from
61*0Sstevel@tonic-gate  * SunOS 4.x <link.h>.)
62*0Sstevel@tonic-gate  */
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate /*
65*0Sstevel@tonic-gate  * Dynamic linking information.  With the exception of
66*0Sstevel@tonic-gate  * ld_loaded (determined at execution time) and ld_stab_hash (a special
67*0Sstevel@tonic-gate  * case of relocation handled at execution time), the values in this
68*0Sstevel@tonic-gate  * structure reflect offsets from the containing link_dynamic structure.
69*0Sstevel@tonic-gate  */
70*0Sstevel@tonic-gate struct link_dynamic_1 {
71*0Sstevel@tonic-gate 	struct	link_map *ld_loaded;	/* list of loaded objects */
72*0Sstevel@tonic-gate 	long	ld_need;		/* list of needed objects */
73*0Sstevel@tonic-gate 	long	ld_rules;		/* search rules for library objects */
74*0Sstevel@tonic-gate 	long	ld_got;			/* global offset table */
75*0Sstevel@tonic-gate 	long	ld_plt;			/* procedure linkage table */
76*0Sstevel@tonic-gate 	long	ld_rel;			/* relocation table */
77*0Sstevel@tonic-gate 	long	ld_hash;		/* symbol hash table */
78*0Sstevel@tonic-gate 	long	ld_stab;		/* symbol table itself */
79*0Sstevel@tonic-gate 	long	(*ld_stab_hash)();	/* "pointer" to symbol hash function */
80*0Sstevel@tonic-gate 	long	ld_buckets;		/* number of hash buckets */
81*0Sstevel@tonic-gate 	long	ld_symbols;		/* symbol strings */
82*0Sstevel@tonic-gate 	long	ld_symb_size;		/* size of symbol strings */
83*0Sstevel@tonic-gate 	long	ld_text;		/* size of text area */
84*0Sstevel@tonic-gate };
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate struct link_dynamic_2 {
87*0Sstevel@tonic-gate 	struct	link_map *ld_loaded;	/* list of loaded objects */
88*0Sstevel@tonic-gate 	long	ld_need;		/* list of needed objects */
89*0Sstevel@tonic-gate 	long	ld_rules;		/* search rules for library objects */
90*0Sstevel@tonic-gate 	long	ld_got;			/* global offset table */
91*0Sstevel@tonic-gate 	long	ld_plt;			/* procedure linkage table */
92*0Sstevel@tonic-gate 	long	ld_rel;			/* relocation table */
93*0Sstevel@tonic-gate 	long	ld_hash;		/* symbol hash table */
94*0Sstevel@tonic-gate 	long	ld_stab;		/* symbol table itself */
95*0Sstevel@tonic-gate 	long	(*ld_stab_hash)();	/* "pointer" to symbol hash function */
96*0Sstevel@tonic-gate 	long	ld_buckets;		/* number of hash buckets */
97*0Sstevel@tonic-gate 	long	ld_symbols;		/* symbol strings */
98*0Sstevel@tonic-gate 	long	ld_symb_size;		/* size of symbol strings */
99*0Sstevel@tonic-gate 	long	ld_text;		/* size of text area */
100*0Sstevel@tonic-gate 	long	ld_plt_sz;		/* size of procedure linkage table */
101*0Sstevel@tonic-gate };
102*0Sstevel@tonic-gate 
103*0Sstevel@tonic-gate /*
104*0Sstevel@tonic-gate  * Debugger interface structure.
105*0Sstevel@tonic-gate  */
106*0Sstevel@tonic-gate struct 	ld_debug {
107*0Sstevel@tonic-gate 	int	ldd_version;		/* version # of interface */
108*0Sstevel@tonic-gate 	int	ldd_in_debugger;	/* a debugger is running us */
109*0Sstevel@tonic-gate 	int	ldd_sym_loaded;		/* we loaded some symbols */
110*0Sstevel@tonic-gate 	char    *ldd_bp_addr;		/* place for ld-generated bpt */
111*0Sstevel@tonic-gate 	int	ldd_bp_inst;		/* instruction which was there */
112*0Sstevel@tonic-gate 	struct rtc_symb *ldd_cp;	/* commons we built */
113*0Sstevel@tonic-gate };
114*0Sstevel@tonic-gate 
115*0Sstevel@tonic-gate /*
116*0Sstevel@tonic-gate  * Structure associated with each object which may be or which requires
117*0Sstevel@tonic-gate  * execution-time link editing.  Used by the run-time linkage editor to
118*0Sstevel@tonic-gate  * identify needed objects and symbol definitions and references.
119*0Sstevel@tonic-gate  */
120*0Sstevel@tonic-gate struct	link_dynamic {
121*0Sstevel@tonic-gate 	int	ld_version;
122*0Sstevel@tonic-gate 	struct 	ld_debug *ldd;
123*0Sstevel@tonic-gate 	union {
124*0Sstevel@tonic-gate 		struct link_dynamic_1 *ld_1;
125*0Sstevel@tonic-gate 		struct link_dynamic_2 *ld_2;
126*0Sstevel@tonic-gate 	} ld_un;
127*0Sstevel@tonic-gate };
128*0Sstevel@tonic-gate 
129*0Sstevel@tonic-gate struct 	old_link_dynamic {
130*0Sstevel@tonic-gate 	int	ld_version;		/* version # of this structure */
131*0Sstevel@tonic-gate 	union {
132*0Sstevel@tonic-gate 		struct link_dynamic_1 ld_1;
133*0Sstevel@tonic-gate 	} ld_un;
134*0Sstevel@tonic-gate 
135*0Sstevel@tonic-gate 	int	in_debugging;
136*0Sstevel@tonic-gate 	int	sym_loaded;
137*0Sstevel@tonic-gate 	char    *bp_addr;
138*0Sstevel@tonic-gate 	int	bp_inst;
139*0Sstevel@tonic-gate 	struct rtc_symb *cp; 		/* pointer to an array of runtime */
140*0Sstevel@tonic-gate 					/* allocated common symbols. */
141*0Sstevel@tonic-gate };
142*0Sstevel@tonic-gate 
143*0Sstevel@tonic-gate #define	v2	ld_un.ld_2		/* short hands */
144*0Sstevel@tonic-gate #define	v1	ld_un.ld_1
145*0Sstevel@tonic-gate 
146*0Sstevel@tonic-gate /*
147*0Sstevel@tonic-gate  * SunOS 4.x SPARC relocation types and relocation record.  Note that
148*0Sstevel@tonic-gate  * these, among other things, make this program not portable to things
149*0Sstevel@tonic-gate  * other than SPARC.
150*0Sstevel@tonic-gate  */
151*0Sstevel@tonic-gate enum reloc_type {
152*0Sstevel@tonic-gate 	RELOC_8, RELOC_16, RELOC_32,	/* simplest relocs */
153*0Sstevel@tonic-gate 	RELOC_DISP8, RELOC_DISP16, RELOC_DISP32,
154*0Sstevel@tonic-gate 					/* Disp's (pc-rel) */
155*0Sstevel@tonic-gate 	RELOC_WDISP30, RELOC_WDISP22,	/* SR word disp's */
156*0Sstevel@tonic-gate 	RELOC_HI22, RELOC_22,		/* SR 22-bit relocs */
157*0Sstevel@tonic-gate 	RELOC_13, RELOC_LO10,		/* SR 13&10-bit relocs */
158*0Sstevel@tonic-gate 	RELOC_SFA_BASE, RELOC_SFA_OFF13, /* SR S.F.A. relocs */
159*0Sstevel@tonic-gate 	RELOC_BASE10, RELOC_BASE13, RELOC_BASE22,
160*0Sstevel@tonic-gate 					/* PIC GOT references */
161*0Sstevel@tonic-gate 	RELOC_PC10, RELOC_PC22,		/* PIC reference to GOT */
162*0Sstevel@tonic-gate 	RELOC_JMP_TBL,			/* PIC call */
163*0Sstevel@tonic-gate 	RELOC_SEGOFF16,			/* .so offset-in-segment */
164*0Sstevel@tonic-gate 	RELOC_GLOB_DAT, RELOC_JMP_SLOT, RELOC_RELATIVE,
165*0Sstevel@tonic-gate 					/* ld.so relocation types */
166*0Sstevel@tonic-gate };
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate struct relocation_info {
169*0Sstevel@tonic-gate 	unsigned long int r_address;	/* relocation addr */
170*0Sstevel@tonic-gate 	unsigned int	r_index   :24;	/* segment index or symbol index */
171*0Sstevel@tonic-gate 	unsigned int	r_extern  : 1;	/* if F, r_index==SEG#; if T, SYM idx */
172*0Sstevel@tonic-gate 	int			  : 2;	/* <unused> */
173*0Sstevel@tonic-gate 	enum reloc_type r_type    : 5;	/* type of relocation to perform */
174*0Sstevel@tonic-gate 	long int	r_addend;	/* addend for relocation value */
175*0Sstevel@tonic-gate };
176*0Sstevel@tonic-gate 
177*0Sstevel@tonic-gate /*
178*0Sstevel@tonic-gate  * Size of relocations.
179*0Sstevel@tonic-gate  */
180*0Sstevel@tonic-gate #define	GETRELSZ(x)	\
181*0Sstevel@tonic-gate 	(x->ld_version < 2 ? \
182*0Sstevel@tonic-gate 	((struct old_link_dynamic *)x)->v1.ld_hash - \
183*0Sstevel@tonic-gate 		((struct old_link_dynamic *)x)->v1.ld_rel : \
184*0Sstevel@tonic-gate 	(x)->v2->ld_hash - (x)->v2->ld_rel)
185*0Sstevel@tonic-gate 
186*0Sstevel@tonic-gate /*
187*0Sstevel@tonic-gate  * Interface between crt0 & ld.so.
188*0Sstevel@tonic-gate  */
189*0Sstevel@tonic-gate struct crt_i1 {
190*0Sstevel@tonic-gate 	int	crt_baseaddr;		/* Address ld.so is at */
191*0Sstevel@tonic-gate 	int	crt_dzfd;		/* /dev/zero file descriptor */
192*0Sstevel@tonic-gate 	int	crt_rlfd;		/* ld.so file descriptor */
193*0Sstevel@tonic-gate 	struct	link_dynamic *crt_udp;	/* "main_" dynamic */
194*0Sstevel@tonic-gate 	char	**crt_ep;		/* environment strings */
195*0Sstevel@tonic-gate 	caddr_t	crt_breakp;		/* place to put initial breakpoint */
196*0Sstevel@tonic-gate };
197*0Sstevel@tonic-gate 
198*0Sstevel@tonic-gate /*
199*0Sstevel@tonic-gate  * Structure we provide to ELF ld.so upon entry.
200*0Sstevel@tonic-gate  */
201*0Sstevel@tonic-gate Elf32_Boot	eb[EB_MAX];
202*0Sstevel@tonic-gate 
203*0Sstevel@tonic-gate /*
204*0Sstevel@tonic-gate  * Global data.
205*0Sstevel@tonic-gate  */
206*0Sstevel@tonic-gate char *program_name;			/* used in messages */
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate /*
209*0Sstevel@tonic-gate  * 4.0 ld.so main entry point.
210*0Sstevel@tonic-gate  */
rtld(version,ip,dp,argp)211*0Sstevel@tonic-gate rtld(version, ip, dp, argp)
212*0Sstevel@tonic-gate 	int version;			/* interface version */
213*0Sstevel@tonic-gate 	struct crt_i1 *ip;		/* interface passed from program */
214*0Sstevel@tonic-gate 	register struct link_dynamic *dp; /* ld.so dynamic pointer */
215*0Sstevel@tonic-gate 	caddr_t	argp;			/* pointer to begining of args */
216*0Sstevel@tonic-gate {
217*0Sstevel@tonic-gate 	char *ldso;			/* name of what we really want to be */
218*0Sstevel@tonic-gate 	int i, p;			/* working */
219*0Sstevel@tonic-gate 	int r;				/* working (# of *our* relocations */
220*0Sstevel@tonic-gate 	int page_size = 0;		/* size of a page */
221*0Sstevel@tonic-gate 	struct relocation_info *rp;	/* working pointer to our relocs */
222*0Sstevel@tonic-gate 	int fd;				/* fd assigned to ld.so */
223*0Sstevel@tonic-gate 	Elf32_Ehdr *ehdr;		/* ELF header of ld.so */
224*0Sstevel@tonic-gate 	Elf32_Phdr *phdr;		/* first Phdr in file */
225*0Sstevel@tonic-gate 	Elf32_Phdr *pptr;		/* working Phdr */
226*0Sstevel@tonic-gate 	Elf32_Phdr *lph;		/* last loadable Phdr */
227*0Sstevel@tonic-gate 	Elf32_Phdr *fph = 0;		/* first loadable Phdr */
228*0Sstevel@tonic-gate 	caddr_t maddr;			/* pointer to mapping claim */
229*0Sstevel@tonic-gate 	Elf32_Off mlen;			/* total mapping claim */
230*0Sstevel@tonic-gate 	caddr_t faddr;			/* first program mapping of ld.so */
231*0Sstevel@tonic-gate 	Elf32_Off foff;			/* file offset for segment mapping */
232*0Sstevel@tonic-gate 	Elf32_Off flen;			/* file length for segment mapping */
233*0Sstevel@tonic-gate 	caddr_t addr;			/* working mapping address */
234*0Sstevel@tonic-gate 	caddr_t zaddr;			/* /dev/zero working mapping addr */
235*0Sstevel@tonic-gate 	Elf32_Boot *ebp;		/* communication with ld.so */
236*0Sstevel@tonic-gate 	struct stat sb;			/* stat buffer for sizing */
237*0Sstevel@tonic-gate 	auxv_t *ap;			/* working aux pointer */
238*0Sstevel@tonic-gate 	void (*	wrt)();			/* address of write/iflush routine */
239*0Sstevel@tonic-gate 
240*0Sstevel@tonic-gate 	/*
241*0Sstevel@tonic-gate 	 * ld.so must itself be relocated, take care of this now.
242*0Sstevel@tonic-gate 	 * We can not refer to global data before this step is
243*0Sstevel@tonic-gate 	 * complete.  Perform the relocation by stepping over all
244*0Sstevel@tonic-gate 	 * entries in the relocation table and turn them into
245*0Sstevel@tonic-gate 	 * absolute addresses.  Note that, in order to avoid invoking
246*0Sstevel@tonic-gate 	 * as yet unrelocated items, we perform the relocation count
247*0Sstevel@tonic-gate 	 * by counting rather than risk invoking subroutine calls
248*0Sstevel@tonic-gate 	 * to intrinsic .div or .mul routines.  Note also that we
249*0Sstevel@tonic-gate 	 * assume that there are no symbolic relocations to be
250*0Sstevel@tonic-gate 	 * performed here.
251*0Sstevel@tonic-gate 	 */
252*0Sstevel@tonic-gate 	dp->v2 = (struct link_dynamic_2 *)
253*0Sstevel@tonic-gate 	    ((caddr_t)dp->v2 + ip->crt_baseaddr);
254*0Sstevel@tonic-gate 	r = 0;
255*0Sstevel@tonic-gate 	i = GETRELSZ(dp);
256*0Sstevel@tonic-gate 	while (i != 0) {
257*0Sstevel@tonic-gate 		i -= RELOC_SIZE;
258*0Sstevel@tonic-gate 		r++;
259*0Sstevel@tonic-gate 	}
260*0Sstevel@tonic-gate 	rp = (struct relocation_info *)(RELOCOFF(dp) +
261*0Sstevel@tonic-gate 	    (dp->ld_version < DYNAMIC_VERSION2 ?
262*0Sstevel@tonic-gate 	    (int)dp : ip->crt_baseaddr));
263*0Sstevel@tonic-gate 
264*0Sstevel@tonic-gate 	/*
265*0Sstevel@tonic-gate 	 * Determine the location of the routine that will write the relocation.
266*0Sstevel@tonic-gate 	 * This hasn't yet been relocated so determine the real address using
267*0Sstevel@tonic-gate 	 * our base address.
268*0Sstevel@tonic-gate 	 */
269*0Sstevel@tonic-gate 	wrt = (void (*)())((caddr_t)aout_reloc_write + ip->crt_baseaddr);
270*0Sstevel@tonic-gate 
271*0Sstevel@tonic-gate 	/*
272*0Sstevel@tonic-gate 	 * Relocate ourselves - we only need RELOC_RELATIVE and RELOC_32.
273*0Sstevel@tonic-gate 	 * Note, if panic() was called its probable that it will barf as the
274*0Sstevel@tonic-gate 	 * corresponding plt wouldn't have been relocated yet.
275*0Sstevel@tonic-gate 	 */
276*0Sstevel@tonic-gate 	for (i = 0; i < r; i++) {
277*0Sstevel@tonic-gate 	    long *where = (long *)((caddr_t)rp->r_address + ip->crt_baseaddr);
278*0Sstevel@tonic-gate 	    long what = ip->crt_baseaddr;
279*0Sstevel@tonic-gate 	    long value;
280*0Sstevel@tonic-gate 
281*0Sstevel@tonic-gate 	    switch (rp->r_type) {
282*0Sstevel@tonic-gate 	    case RELOC_RELATIVE:
283*0Sstevel@tonic-gate 		what += *where << (32-22);
284*0Sstevel@tonic-gate 		value = (*where & ~MASK(22)) | ((what >> (32-22)) & MASK(22));
285*0Sstevel@tonic-gate 		wrt(where, value);
286*0Sstevel@tonic-gate 		where++;
287*0Sstevel@tonic-gate 		what += (*where & MASK(10));
288*0Sstevel@tonic-gate 		value = (*where & ~MASK(10)) | (what & MASK(10));
289*0Sstevel@tonic-gate 		wrt(where, value);
290*0Sstevel@tonic-gate 		break;
291*0Sstevel@tonic-gate 
292*0Sstevel@tonic-gate 	    case RELOC_32:
293*0Sstevel@tonic-gate 		what += *where;
294*0Sstevel@tonic-gate 		wrt(where, what);
295*0Sstevel@tonic-gate 		break;
296*0Sstevel@tonic-gate 
297*0Sstevel@tonic-gate 	    default:
298*0Sstevel@tonic-gate 		panic("unknown relocation type %d\n", rp->r_type);
299*0Sstevel@tonic-gate 		break;
300*0Sstevel@tonic-gate 	    }
301*0Sstevel@tonic-gate 	    rp++;
302*0Sstevel@tonic-gate 	}
303*0Sstevel@tonic-gate 
304*0Sstevel@tonic-gate 	/*
305*0Sstevel@tonic-gate 	 * We're relocated, we can now initialize things referencing
306*0Sstevel@tonic-gate 	 * static storage.
307*0Sstevel@tonic-gate 	 */
308*0Sstevel@tonic-gate 	ldso = "/usr/lib/ld.so.1";
309*0Sstevel@tonic-gate 
310*0Sstevel@tonic-gate 	/*
311*0Sstevel@tonic-gate 	 * Close off the file descriptor used to get us here -- let it
312*0Sstevel@tonic-gate 	 * be available for the next (probable) use below.
313*0Sstevel@tonic-gate 	 */
314*0Sstevel@tonic-gate 	(void) close(ip->crt_rlfd);
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate 	/*
317*0Sstevel@tonic-gate 	 * Discover things about our environment: auxiliary vector (if
318*0Sstevel@tonic-gate 	 * any), arguments, program name, and the like.
319*0Sstevel@tonic-gate 	 */
320*0Sstevel@tonic-gate 	ebp = eb;
321*0Sstevel@tonic-gate 	program_name = (char *)(argp + sizeof (int));
322*0Sstevel@tonic-gate 	if (version != 1)
323*0Sstevel@tonic-gate 		panic("bad startup interface version of %d",
324*0Sstevel@tonic-gate 		    version);
325*0Sstevel@tonic-gate 	ebp->eb_tag = EB_DYNAMIC,
326*0Sstevel@tonic-gate 	    (ebp++)->eb_un.eb_ptr = (Elf32_Addr)ip->crt_udp;
327*0Sstevel@tonic-gate 	ebp->eb_tag = EB_ARGV, (ebp++)->eb_un.eb_ptr = (Elf32_Addr)program_name;
328*0Sstevel@tonic-gate 	ebp->eb_tag = EB_ENVP, (ebp++)->eb_un.eb_ptr = (Elf32_Addr)ip->crt_ep;
329*0Sstevel@tonic-gate 	ebp->eb_tag = EB_DEVZERO,
330*0Sstevel@tonic-gate 	    (ebp++)->eb_un.eb_val = (Elf32_Word)ip->crt_dzfd;
331*0Sstevel@tonic-gate 	for (addr = (caddr_t)ip->crt_ep; *addr; addr += sizeof (char *))
332*0Sstevel@tonic-gate 		;
333*0Sstevel@tonic-gate 	addr += sizeof (char *);
334*0Sstevel@tonic-gate 
335*0Sstevel@tonic-gate 	/*
336*0Sstevel@tonic-gate 	 * The kernel sends us an abbreviated aux vector with some
337*0Sstevel@tonic-gate 	 * potentially handy stuff that saves us on syscalls.
338*0Sstevel@tonic-gate 	 *
339*0Sstevel@tonic-gate 	 * Notes on 1226113
340*0Sstevel@tonic-gate 	 *
341*0Sstevel@tonic-gate 	 * The f77 compiler shipped as part of SC1.0 on 4.x creates binaries
342*0Sstevel@tonic-gate 	 * that use the _fix_libc_ feature of acc.  This makes the resulting
343*0Sstevel@tonic-gate 	 * executable object dependent on the undocumented behaviour of
344*0Sstevel@tonic-gate 	 * libc's .rem and .div routines e.g. that .div returns the
345*0Sstevel@tonic-gate 	 * remainder in %o3 (and similarly .rem returns the division in %o3).
346*0Sstevel@tonic-gate 	 *
347*0Sstevel@tonic-gate 	 * The only simple solution is to disable hardware divide for
348*0Sstevel@tonic-gate 	 * all 4.x applications so that the old software routines that have
349*0Sstevel@tonic-gate 	 * this "support" in them are used instead.  And we do that by
350*0Sstevel@tonic-gate 	 * clearing the divide-in-hardware flag from the aux vector before
351*0Sstevel@tonic-gate 	 * libc's .init routine gets to see it.  Awful isn't it.
352*0Sstevel@tonic-gate 	 */
353*0Sstevel@tonic-gate 	ebp->eb_tag = EB_AUXV, (ebp++)->eb_un.eb_ptr = (Elf32_Addr)addr;
354*0Sstevel@tonic-gate 	for (ap = (auxv_t *)addr; ap->a_type != AT_NULL; ap++)
355*0Sstevel@tonic-gate 		if (ap->a_type == AT_PAGESZ) {
356*0Sstevel@tonic-gate 			page_size = ap->a_un.a_val;
357*0Sstevel@tonic-gate 			ebp->eb_tag = EB_PAGESIZE, (ebp++)->eb_un.eb_val =
358*0Sstevel@tonic-gate 			    (Elf32_Word)page_size;
359*0Sstevel@tonic-gate 		} else if (ap->a_type == AT_SUN_HWCAP)
360*0Sstevel@tonic-gate 			ap->a_un.a_val &= ~AV_SPARC_HWDIV_32x32;
361*0Sstevel@tonic-gate 
362*0Sstevel@tonic-gate 	/*
363*0Sstevel@tonic-gate 	 * If we didn't get a page size from looking in the auxiliary
364*0Sstevel@tonic-gate 	 * vector, we need to get one now.
365*0Sstevel@tonic-gate 	 */
366*0Sstevel@tonic-gate 	if (page_size == 0) {
367*0Sstevel@tonic-gate 		page_size = sysconfig(_CONFIG_PAGESIZE);
368*0Sstevel@tonic-gate 		ebp->eb_tag = EB_PAGESIZE, (ebp++)->eb_un.eb_val =
369*0Sstevel@tonic-gate 		    (Elf32_Word)page_size;
370*0Sstevel@tonic-gate 	}
371*0Sstevel@tonic-gate 
372*0Sstevel@tonic-gate 	/*
373*0Sstevel@tonic-gate 	 * Map in the ELF-based ld.so.  Note that we're mapping it as
374*0Sstevel@tonic-gate 	 * an ELF database, not as a program -- we just want to walk it's
375*0Sstevel@tonic-gate 	 * data structures.  Further mappings will actually establish the
376*0Sstevel@tonic-gate 	 * program in the address space.
377*0Sstevel@tonic-gate 	 */
378*0Sstevel@tonic-gate 	if ((fd = open(ldso, O_RDONLY)) == -1)
379*0Sstevel@tonic-gate 		panic("unable to open %s", ldso);
380*0Sstevel@tonic-gate 	if (fstat(fd, &sb) == -1)
381*0Sstevel@tonic-gate 		panic("unable to find size of %s", ldso);
382*0Sstevel@tonic-gate 	ehdr = (Elf32_Ehdr *)mmap(0, sb.st_size, PROT_READ | PROT_EXEC,
383*0Sstevel@tonic-gate 	    MAP_SHARED, fd, 0);
384*0Sstevel@tonic-gate 	if (ehdr == (Elf32_Ehdr *)-1)
385*0Sstevel@tonic-gate 		panic("unable to map %s", ldso);
386*0Sstevel@tonic-gate 
387*0Sstevel@tonic-gate 	/*
388*0Sstevel@tonic-gate 	 * Validate the file we're looking at, ensure it has the correct
389*0Sstevel@tonic-gate 	 * ELF structures, such as: ELF magic numbers, coded for SPARC,
390*0Sstevel@tonic-gate 	 * is a ".so", etc.
391*0Sstevel@tonic-gate 	 */
392*0Sstevel@tonic-gate 	if (ehdr->e_ident[EI_MAG0] != ELFMAG0 ||
393*0Sstevel@tonic-gate 	    ehdr->e_ident[EI_MAG1] != ELFMAG1 ||
394*0Sstevel@tonic-gate 	    ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
395*0Sstevel@tonic-gate 	    ehdr->e_ident[EI_MAG3] != ELFMAG3)
396*0Sstevel@tonic-gate 		panic("%s is not an ELF file", ldso);
397*0Sstevel@tonic-gate 	if (ehdr->e_ident[EI_CLASS] != ELFCLASS32 ||
398*0Sstevel@tonic-gate 	    ehdr->e_ident[EI_DATA] != ELFDATA2MSB)
399*0Sstevel@tonic-gate 		panic("%s has wrong class or data encoding", ldso);
400*0Sstevel@tonic-gate 	if (ehdr->e_type != ET_DYN)
401*0Sstevel@tonic-gate 		panic("%s is not a shared object", ldso);
402*0Sstevel@tonic-gate 	if ((ehdr->e_machine != EM_SPARC) &&
403*0Sstevel@tonic-gate 	    (ehdr->e_machine != EM_SPARC32PLUS))
404*0Sstevel@tonic-gate 		panic("%s is not a valid SPARC object: e_machine: %x",
405*0Sstevel@tonic-gate 		    ldso, ehdr->e_machine);
406*0Sstevel@tonic-gate 	if (ehdr->e_version > EV_CURRENT)
407*0Sstevel@tonic-gate 		panic("%s has bad ELF version of %d", ldso, ehdr->e_version);
408*0Sstevel@tonic-gate 
409*0Sstevel@tonic-gate 	/*
410*0Sstevel@tonic-gate 	 * Point at program headers and start figuring out what to load.
411*0Sstevel@tonic-gate 	 */
412*0Sstevel@tonic-gate 	phdr = (Elf32_Phdr *)((caddr_t)ehdr + ehdr->e_phoff);
413*0Sstevel@tonic-gate 	for (p = 0, pptr = phdr; p < (int)ehdr->e_phnum; p++,
414*0Sstevel@tonic-gate 	    pptr = (Elf32_Phdr *)((caddr_t)pptr + ehdr->e_phentsize))
415*0Sstevel@tonic-gate 		if (pptr->p_type == PT_LOAD) {
416*0Sstevel@tonic-gate 			if (fph == 0) {
417*0Sstevel@tonic-gate 				fph = pptr;
418*0Sstevel@tonic-gate 			} else if (pptr->p_vaddr <= lph->p_vaddr)
419*0Sstevel@tonic-gate 				panic(
420*0Sstevel@tonic-gate 		"%s invalid program header - segments out of order", ldso);
421*0Sstevel@tonic-gate 			lph = pptr;
422*0Sstevel@tonic-gate 		}
423*0Sstevel@tonic-gate 
424*0Sstevel@tonic-gate 	/*
425*0Sstevel@tonic-gate 	 * We'd better have at least one loadable segment.
426*0Sstevel@tonic-gate 	 */
427*0Sstevel@tonic-gate 	if (fph == 0)
428*0Sstevel@tonic-gate 		panic("%s has no loadable segments", ldso);
429*0Sstevel@tonic-gate 
430*0Sstevel@tonic-gate 	/*
431*0Sstevel@tonic-gate 	 * Map enough address space to hold the program (as opposed to the
432*0Sstevel@tonic-gate 	 * file) represented by ld.so.  The amount to be assigned is the
433*0Sstevel@tonic-gate 	 * range between the end of the last loadable segment and the
434*0Sstevel@tonic-gate 	 * beginning of the first PLUS the alignment of the first segment.
435*0Sstevel@tonic-gate 	 * mmap() can assign us any page-aligned address, but the relocations
436*0Sstevel@tonic-gate 	 * assume the alignments included in the program header.  As an
437*0Sstevel@tonic-gate 	 * optimization, however, let's assume that mmap() will actually
438*0Sstevel@tonic-gate 	 * give us an aligned address -- since if it does, we can save
439*0Sstevel@tonic-gate 	 * an munmap() later on.  If it doesn't -- then go try it again.
440*0Sstevel@tonic-gate 	 */
441*0Sstevel@tonic-gate 	mlen = ROUND((lph->p_vaddr + lph->p_memsz) -
442*0Sstevel@tonic-gate 	    ALIGN(fph->p_vaddr, page_size), page_size);
443*0Sstevel@tonic-gate 	maddr = (caddr_t)mmap(0, mlen, PROT_READ | PROT_EXEC,
444*0Sstevel@tonic-gate 	    MAP_SHARED, fd, 0);
445*0Sstevel@tonic-gate 	if (maddr == (caddr_t)-1)
446*0Sstevel@tonic-gate 		panic("unable to reserve space for %s", ldso);
447*0Sstevel@tonic-gate 	faddr = (caddr_t)ROUND(maddr, fph->p_align);
448*0Sstevel@tonic-gate 
449*0Sstevel@tonic-gate 	/*
450*0Sstevel@tonic-gate 	 * Check to see whether alignment skew was really needed.
451*0Sstevel@tonic-gate 	 */
452*0Sstevel@tonic-gate 	if (faddr != maddr) {
453*0Sstevel@tonic-gate 		(void) munmap(maddr, mlen);
454*0Sstevel@tonic-gate 		mlen = ROUND((lph->p_vaddr + lph->p_memsz) -
455*0Sstevel@tonic-gate 		    ALIGN(fph->p_vaddr, fph->p_align) + fph->p_align,
456*0Sstevel@tonic-gate 		    page_size);
457*0Sstevel@tonic-gate 		maddr = (caddr_t)mmap(0, mlen, PROT_READ | PROT_EXEC,
458*0Sstevel@tonic-gate 		    MAP_SHARED, fd, 0);
459*0Sstevel@tonic-gate 		if (maddr == (caddr_t)-1)
460*0Sstevel@tonic-gate 			panic("unable to reserve space for %s", ldso);
461*0Sstevel@tonic-gate 		faddr = (caddr_t)ROUND(maddr, fph->p_align);
462*0Sstevel@tonic-gate 	}
463*0Sstevel@tonic-gate 	ebp->eb_tag = EB_LDSO_BASE, (ebp++)->eb_un.eb_ptr = (Elf32_Addr)faddr;
464*0Sstevel@tonic-gate 
465*0Sstevel@tonic-gate 	/*
466*0Sstevel@tonic-gate 	 * We have the address space reserved, so map each loadable segment.
467*0Sstevel@tonic-gate 	 */
468*0Sstevel@tonic-gate 	for (pptr = phdr; (pptr - phdr) < (int)ehdr->e_phnum; pptr++) {
469*0Sstevel@tonic-gate 
470*0Sstevel@tonic-gate 		/*
471*0Sstevel@tonic-gate 		 * Skip non-loadable segments or segments that don't occupy
472*0Sstevel@tonic-gate 		 * any memory.
473*0Sstevel@tonic-gate 		 */
474*0Sstevel@tonic-gate 		if ((pptr->p_type != PT_LOAD) || (pptr->p_memsz == 0))
475*0Sstevel@tonic-gate 			continue;
476*0Sstevel@tonic-gate 
477*0Sstevel@tonic-gate 		/*
478*0Sstevel@tonic-gate 		 * Determine the file offset to which the mapping will
479*0Sstevel@tonic-gate 		 * directed (must be aligned) and how much to map (might
480*0Sstevel@tonic-gate 		 * be more than the file in the case of .bss.)
481*0Sstevel@tonic-gate 		 */
482*0Sstevel@tonic-gate 		foff = ALIGN(pptr->p_offset, page_size);
483*0Sstevel@tonic-gate 		flen = pptr->p_memsz + (pptr->p_offset - foff);
484*0Sstevel@tonic-gate 
485*0Sstevel@tonic-gate 		/*
486*0Sstevel@tonic-gate 		 * Set address of this segment relative to our base.
487*0Sstevel@tonic-gate 		 */
488*0Sstevel@tonic-gate 		addr = (caddr_t)ALIGN(faddr + pptr->p_vaddr, page_size);
489*0Sstevel@tonic-gate 
490*0Sstevel@tonic-gate 		/*
491*0Sstevel@tonic-gate 		 * Unmap anything form the last mapping address to this
492*0Sstevel@tonic-gate 		 * one.
493*0Sstevel@tonic-gate 		 */
494*0Sstevel@tonic-gate 		if (addr - maddr) {
495*0Sstevel@tonic-gate 			(void) munmap(maddr, addr - maddr);
496*0Sstevel@tonic-gate 			mlen -= addr - maddr;
497*0Sstevel@tonic-gate 		}
498*0Sstevel@tonic-gate 
499*0Sstevel@tonic-gate 		/*
500*0Sstevel@tonic-gate 		 * Determine the mapping protection from the section
501*0Sstevel@tonic-gate 		 * attributes.
502*0Sstevel@tonic-gate 		 */
503*0Sstevel@tonic-gate 		i = 0;
504*0Sstevel@tonic-gate 		if (pptr->p_flags & PF_R)
505*0Sstevel@tonic-gate 			i |= PROT_READ;
506*0Sstevel@tonic-gate 		if (pptr->p_flags & PF_W)
507*0Sstevel@tonic-gate 			i |= PROT_WRITE;
508*0Sstevel@tonic-gate 		if (pptr->p_flags & PF_X)
509*0Sstevel@tonic-gate 			i |= PROT_EXEC;
510*0Sstevel@tonic-gate 		if ((caddr_t)mmap((caddr_t)addr, flen, i,
511*0Sstevel@tonic-gate 		    MAP_FIXED | MAP_PRIVATE, fd, foff) == (caddr_t)-1)
512*0Sstevel@tonic-gate 			panic("unable to map a segment from %s", ldso);
513*0Sstevel@tonic-gate 
514*0Sstevel@tonic-gate 		/*
515*0Sstevel@tonic-gate 		 * If the memory occupancy of the segment overflows the
516*0Sstevel@tonic-gate 		 * definition in the file, we need to "zero out" the
517*0Sstevel@tonic-gate 		 * end of the mapping we've established, and if necessary,
518*0Sstevel@tonic-gate 		 * map some more space from /dev/zero.
519*0Sstevel@tonic-gate 		 */
520*0Sstevel@tonic-gate 		if (pptr->p_memsz > pptr->p_filesz) {
521*0Sstevel@tonic-gate 			foff = (int)faddr + pptr->p_vaddr + pptr->p_filesz;
522*0Sstevel@tonic-gate 			zaddr = (caddr_t)ROUND(foff, page_size);
523*0Sstevel@tonic-gate 			_zero(foff, zaddr - foff);
524*0Sstevel@tonic-gate 			r = (faddr + pptr->p_vaddr + pptr->p_memsz) - zaddr;
525*0Sstevel@tonic-gate 			if (r > 0)
526*0Sstevel@tonic-gate 				if ((caddr_t)mmap((caddr_t)zaddr, r, i,
527*0Sstevel@tonic-gate 				    MAP_FIXED | MAP_PRIVATE, ip->crt_dzfd,
528*0Sstevel@tonic-gate 				    0) == (caddr_t)-1)
529*0Sstevel@tonic-gate 					panic(
530*0Sstevel@tonic-gate 					"unable to map .bss /dev/zero for %s",
531*0Sstevel@tonic-gate 					    ldso);
532*0Sstevel@tonic-gate 		}
533*0Sstevel@tonic-gate 
534*0Sstevel@tonic-gate 		/*
535*0Sstevel@tonic-gate 		 * Update the mapping claim pointer.
536*0Sstevel@tonic-gate 		 */
537*0Sstevel@tonic-gate 		maddr = addr + ROUND(flen, page_size);
538*0Sstevel@tonic-gate 		mlen -= maddr - addr;
539*0Sstevel@tonic-gate 	}
540*0Sstevel@tonic-gate 
541*0Sstevel@tonic-gate 	/*
542*0Sstevel@tonic-gate 	 * Unmap any final reservation.
543*0Sstevel@tonic-gate 	 */
544*0Sstevel@tonic-gate 	if (mlen > 0)
545*0Sstevel@tonic-gate 		(void) munmap(maddr, mlen);
546*0Sstevel@tonic-gate 
547*0Sstevel@tonic-gate 	/*
548*0Sstevel@tonic-gate 	 * Clean up file descriptor space we've consumed.  Pass along
549*0Sstevel@tonic-gate 	 * the /dev/zero file descriptor we got -- every cycle counts.
550*0Sstevel@tonic-gate 	 */
551*0Sstevel@tonic-gate 	(void) close(fd);
552*0Sstevel@tonic-gate 
553*0Sstevel@tonic-gate 	/*
554*0Sstevel@tonic-gate 	 * The call itself.  Note that we start 1 instruction word in.
555*0Sstevel@tonic-gate 	 * The ELF ld.so contains an "entry vector" of branch instructions,
556*0Sstevel@tonic-gate 	 * which, for our interest are:
557*0Sstevel@tonic-gate 	 *	+0:	ba, a	<normal startup>
558*0Sstevel@tonic-gate 	 *	+4:	ba, a	<compatibility startup>
559*0Sstevel@tonic-gate 	 * By starting at the compatibility startup, the ELF ld.so knows
560*0Sstevel@tonic-gate 	 * that a pointer to "eb" is available to it and further knows
561*0Sstevel@tonic-gate 	 * how to calculate the offset to the program's arguments and
562*0Sstevel@tonic-gate 	 * other structures.
563*0Sstevel@tonic-gate 	 */
564*0Sstevel@tonic-gate 	ebp->eb_tag = EB_NULL, ebp->eb_un.eb_val = 0;
565*0Sstevel@tonic-gate 	(*((void (*)())(ehdr->e_entry + faddr + sizeof (long))))(eb);
566*0Sstevel@tonic-gate 	return (0);
567*0Sstevel@tonic-gate }
568