_setup.c revision 4321:a8930ec16e52
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 *	Copyright (c) 1988 AT&T
24 *	  All Rights Reserved
25 *
26 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
27 * Use is subject to license terms.
28 */
29#pragma ident	"%Z%%M%	%I%	%E% SMI"
30
31/*
32 * SPARCV9-specific setup routine  -  relocate ld.so's symbols, setup its
33 * environment, map in loadable sections of the executable.
34 *
35 * Takes base address ld.so was loaded at, address of ld.so's dynamic
36 * structure, address of process environment pointers, address of auxiliary
37 * vector and * argv[0] (process name).
38 * If errors occur, send process signal - otherwise
39 * return executable's entry point to the bootstrap routine.
40 */
41#include	"_synonyms.h"
42
43#include	<signal.h>
44#include	<stdlib.h>
45#include	<sys/auxv.h>
46#include	<sys/types.h>
47#include	<sys/stat.h>
48#include	<link.h>
49#include	<dlfcn.h>
50#include	"_rtld.h"
51#include	"_audit.h"
52#include	"msg.h"
53
54extern int	_end;
55extern int	_etext;
56extern void	_init(void);
57
58
59/* VARARGS */
60unsigned long
61_setup(Boot *ebp, Dyn *ld_dyn)
62{
63	unsigned long	reladdr, relacount, ld_base = 0;
64	unsigned long	relaent = 0;
65	unsigned long	strtab, soname, interp_base = 0;
66	char		*_rt_name, **_envp, **_argv;
67	int		_syspagsz = 0, fd = -1, dz_fd = FD_UNAVAIL;
68	uint_t		_flags = 0, hwcap_1 = 0;
69	Dyn		*dyn_ptr;
70	Phdr		*phdr = 0;
71	Rt_map		*lmp;
72	auxv_t		*auxv, *_auxv;
73	uid_t		uid = (uid_t)-1, euid = (uid_t)-1;
74	gid_t		gid = (gid_t)-1, egid = (gid_t)-1;
75	char		*_platform = 0, *_execname = 0;
76	int		auxflags = -1;
77
78	/*
79	 * Scan the bootstrap structure to pick up the basics.
80	 */
81	for (; ebp->eb_tag != EB_NULL; ebp++)
82		switch (ebp->eb_tag) {
83		case EB_LDSO_BASE:
84			ld_base = (unsigned long)ebp->eb_un.eb_val;
85			break;
86		case EB_ARGV:
87			_argv = (char **)ebp->eb_un.eb_ptr;
88			break;
89		case EB_ENVP:
90			_envp = (char **)ebp->eb_un.eb_ptr;
91			break;
92		case EB_AUXV:
93			_auxv = (auxv_t *)ebp->eb_un.eb_ptr;
94			break;
95		case EB_DEVZERO:
96			/* LINTED */
97			dz_fd = (int)ebp->eb_un.eb_val;
98			break;
99		case EB_PAGESIZE:
100			/* LINTED */
101			_syspagsz = (int)ebp->eb_un.eb_val;
102			break;
103		}
104
105	/*
106	 * Search the aux. vector for the information passed by exec.
107	 */
108	for (auxv = _auxv; auxv->a_type != AT_NULL; auxv++) {
109		switch (auxv->a_type) {
110		case AT_EXECFD:
111			/* this is the old exec that passes a file descriptor */
112			/* LINTED */
113			fd = (int)auxv->a_un.a_val;
114			break;
115		case AT_FLAGS:
116			/* processor flags (MAU available, etc) */
117			/* LINTED */
118			_flags = (Word)auxv->a_un.a_val;
119			break;
120		case AT_PAGESZ:
121			/* system page size */
122			/* LINTED */
123			_syspagsz = (int)auxv->a_un.a_val;
124			break;
125		case AT_PHDR:
126			/* address of the segment table */
127			phdr = (Phdr *)auxv->a_un.a_ptr;
128			break;
129		case AT_BASE:
130			/* interpreter base address */
131			if (ld_base == 0)
132				ld_base = auxv->a_un.a_val;
133			interp_base = auxv->a_un.a_val;
134			break;
135		case AT_SUN_UID:
136			/* effective user id for the executable */
137			/* LINTED */
138			euid = (uid_t)auxv->a_un.a_val;
139			break;
140		case AT_SUN_RUID:
141			/* real user id for the executable */
142			/* LINTED */
143			uid = (uid_t)auxv->a_un.a_val;
144			break;
145		case AT_SUN_GID:
146			/* effective group id for the executable */
147			/* LINTED */
148			egid = (gid_t)auxv->a_un.a_val;
149			break;
150		case AT_SUN_RGID:
151			/* real group id for the executable */
152			/* LINTED */
153			gid = (gid_t)auxv->a_un.a_val;
154			break;
155#ifdef	AT_SUN_PLATFORM			/* Defined on SunOS 5.5 & greater. */
156		case AT_SUN_PLATFORM:
157			/* platform name */
158			_platform = auxv->a_un.a_ptr;
159			break;
160#endif
161#ifdef	AT_SUN_EXECNAME			/* Defined on SunOS 5.6 & greater. */
162		case AT_SUN_EXECNAME:
163			/* full pathname of execed object */
164			_execname = auxv->a_un.a_ptr;
165			break;
166#endif
167#ifdef	AT_SUN_AUXFLAGS			/* At the behest of PSARC 2002/188 */
168		case AT_SUN_AUXFLAGS:
169			auxflags = (int)auxv->a_un.a_val;
170			break;
171#endif
172#ifdef	AT_SUN_HWCAP		/* Hardware capabilities */
173		case AT_SUN_HWCAP:
174			hwcap_1 = (uint_t)auxv->a_un.a_val;
175			break;
176#endif
177		}
178	}
179
180	/*
181	 * Get needed info from ld.so's dynamic structure.
182	 */
183	/* LINTED */
184	dyn_ptr = (Dyn *)((char *)ld_dyn + ld_base);
185	for (ld_dyn = dyn_ptr; ld_dyn->d_tag != DT_NULL; ld_dyn++) {
186		switch (ld_dyn->d_tag) {
187		case DT_RELA:
188			reladdr = ld_dyn->d_un.d_ptr + ld_base;
189			break;
190		case DT_RELACOUNT:
191			relacount = ld_dyn->d_un.d_val;
192			break;
193		case DT_RELAENT:
194			relaent = ld_dyn->d_un.d_val;
195			break;
196		case DT_STRTAB:
197			strtab = ld_dyn->d_un.d_ptr + ld_base;
198			break;
199		case DT_SONAME:
200			soname = ld_dyn->d_un.d_val;
201			break;
202		}
203	}
204	_rt_name = (char *)strtab + soname;
205
206	/*
207	 * If we don't have a RELAENT, just assume
208	 * the size.
209	 */
210	if (relaent == 0)
211		relaent = sizeof (Rela);
212
213	/*
214	 * Because ld.so.1 is built with -Bsymbolic there should only be
215	 * RELATIVE and JMPSLOT relocations.  Process all relatives first.
216	 */
217	for (; relacount; relacount--) {
218		ulong_t	roffset;
219
220		roffset = ((Rela *)reladdr)->r_offset + ld_base;
221		*((ulong_t *)roffset) = ld_base +
222		    ((Rela *)reladdr)->r_addend;
223		reladdr += relaent;
224	}
225
226	/*
227	 * Continue with generic startup processing.
228	 */
229	if ((lmp = setup((char **)_envp, (auxv_t *)_auxv, _flags, _platform,
230	    _syspagsz, _rt_name, dyn_ptr, ld_base, interp_base, fd, phdr,
231	    _execname, _argv, dz_fd, uid, euid, gid, egid, NULL, auxflags,
232	    hwcap_1)) == NULL) {
233		rtldexit(&lml_main, 1);
234	}
235
236	return (LM_ENTRY_PT(lmp)());
237}
238