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