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 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * amd64 specific setup routine - relocate ld.so's symbols, setup its
29 * environment, map in loadable sections of the executable.
30 *
31 * Takes base address ld.so was loaded at, address of ld.so's dynamic
32 * structure, address of process environment pointers, address of auxiliary
33 * vector and * argv[0] (process name).
34 * If errors occur, send process signal - otherwise
35 * return executable's entry point to the bootstrap routine.
36 */
37
38 #include <signal.h>
39 #include <stdlib.h>
40 #include <sys/auxv.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <link.h>
44 #include <dlfcn.h>
45 #include "_rtld.h"
46 #include "_audit.h"
47 #include "msg.h"
48
49 /* VARARGS */
50 unsigned long
_setup(Boot * ebp,Dyn * ld_dyn)51 _setup(Boot *ebp, Dyn *ld_dyn)
52 {
53 ulong_t reladdr, relacount, ld_base = 0;
54 ulong_t relaent = 0, pltrelsz = 0;
55 ulong_t strtab, soname, interp_base = 0;
56 char *_rt_name, **_envp, **_argv;
57 int _syspagsz = 0, fd = -1;
58 uint_t _flags = 0, hwcap_1 = 0;
59 Dyn *dyn_ptr;
60 Phdr *phdr = NULL;
61 Rt_map *lmp;
62 auxv_t *auxv, *_auxv;
63 uid_t uid = (uid_t)-1, euid = (uid_t)-1;
64 gid_t gid = (gid_t)-1, egid = (gid_t)-1;
65 char *_platform = NULL, *_execname = NULL, *_emulator = NULL;
66 int auxflags = -1;
67
68 /*
69 * Scan the bootstrap structure to pick up the basics.
70 */
71 for (; ebp->eb_tag != EB_NULL; ebp++)
72 switch (ebp->eb_tag) {
73 case EB_LDSO_BASE:
74 ld_base = (unsigned long)ebp->eb_un.eb_val;
75 break;
76 case EB_ARGV:
77 _argv = (char **)ebp->eb_un.eb_ptr;
78 break;
79 case EB_ENVP:
80 _envp = (char **)ebp->eb_un.eb_ptr;
81 break;
82 case EB_AUXV:
83 _auxv = (auxv_t *)ebp->eb_un.eb_ptr;
84 break;
85 case EB_PAGESIZE:
86 _syspagsz = (int)ebp->eb_un.eb_val;
87 break;
88 }
89
90 /*
91 * Search the aux. vector for the information passed by exec.
92 */
93 for (auxv = _auxv; auxv->a_type != AT_NULL; auxv++) {
94 switch (auxv->a_type) {
95 case AT_EXECFD:
96 /* this is the old exec that passes a file descriptor */
97 fd = (int)auxv->a_un.a_val;
98 break;
99 case AT_FLAGS:
100 /* processor flags (MAU available, etc) */
101 _flags = auxv->a_un.a_val;
102 break;
103 case AT_PAGESZ:
104 /* system page size */
105 _syspagsz = (int)auxv->a_un.a_val;
106 break;
107 case AT_PHDR:
108 /* address of the segment table */
109 phdr = (Phdr *)auxv->a_un.a_ptr;
110 break;
111 case AT_BASE:
112 /* interpreter base address */
113 if (ld_base == 0)
114 ld_base = auxv->a_un.a_val;
115 interp_base = auxv->a_un.a_val;
116 break;
117 case AT_SUN_UID:
118 /* effective user id for the executable */
119 euid = (uid_t)auxv->a_un.a_val;
120 break;
121 case AT_SUN_RUID:
122 /* real user id for the executable */
123 uid = (uid_t)auxv->a_un.a_val;
124 break;
125 case AT_SUN_GID:
126 /* effective group id for the executable */
127 egid = (gid_t)auxv->a_un.a_val;
128 break;
129 case AT_SUN_RGID:
130 /* real group id for the executable */
131 gid = (gid_t)auxv->a_un.a_val;
132 break;
133 case AT_SUN_PLATFORM:
134 /* platform name */
135 _platform = auxv->a_un.a_ptr;
136 break;
137 case AT_SUN_EXECNAME:
138 /* full pathname of execed object */
139 _execname = auxv->a_un.a_ptr;
140 break;
141 case AT_SUN_AUXFLAGS:
142 /* auxiliary flags */
143 auxflags = (int)auxv->a_un.a_val;
144 break;
145 case AT_SUN_HWCAP:
146 /* hardware capabilities */
147 hwcap_1 = (uint_t)auxv->a_un.a_val;
148 break;
149 case AT_SUN_EMULATOR:
150 /* name of emulation library, if any */
151 _emulator = auxv->a_un.a_ptr;
152 break;
153 }
154 }
155
156 /*
157 * Get needed info from ld.so's dynamic structure.
158 */
159 /* LINTED */
160 dyn_ptr = (Dyn *)((char *)ld_dyn + ld_base);
161 for (ld_dyn = dyn_ptr; ld_dyn->d_tag != DT_NULL; ld_dyn++) {
162 switch (ld_dyn->d_tag) {
163 case DT_RELA:
164 reladdr = ld_dyn->d_un.d_ptr + ld_base;
165 break;
166 case DT_RELACOUNT:
167 relacount = ld_dyn->d_un.d_val;
168 break;
169 case DT_RELAENT:
170 relaent = ld_dyn->d_un.d_val;
171 break;
172 case DT_PLTRELSZ:
173 pltrelsz = ld_dyn->d_un.d_val;
174 break;
175 case DT_STRTAB:
176 strtab = ld_dyn->d_un.d_ptr + ld_base;
177 break;
178 case DT_SONAME:
179 soname = ld_dyn->d_un.d_val;
180 break;
181 }
182 }
183 _rt_name = (char *)strtab + soname;
184
185 /*
186 * If we don't have a RELAENT, just assume the size.
187 */
188 if (relaent == 0)
189 relaent = sizeof (Rela);
190
191 /*
192 * As all global symbol references within ld.so.1 are protected
193 * (symbolic), only RELATIVE and JMPSLOT relocations should be left
194 * to process at runtime. Process all relocations now.
195 */
196 relacount += (pltrelsz / relaent);
197 for (; relacount; relacount--) {
198 ulong_t roffset;
199
200 roffset = ((Rela *)reladdr)->r_offset + ld_base;
201 *((ulong_t *)roffset) += ld_base +
202 ((Rela *)reladdr)->r_addend;
203 reladdr += relaent;
204 }
205
206 /*
207 * If an emulation library is being used, use that as the linker's
208 * effective executable name. The real executable is not linked by this
209 * linker.
210 */
211 if (_emulator != NULL) {
212 _execname = _emulator;
213 rtld_flags2 |= RT_FL2_BRANDED;
214 }
215
216 /*
217 * Initialize the dyn_plt_ent_size field. It currently contains the
218 * size of the dyn_plt_template. It still needs to be aligned and have
219 * space for the 'dyn_data' area added.
220 */
221 dyn_plt_ent_size = ROUND(dyn_plt_ent_size, M_WORD_ALIGN) +
222 sizeof (uintptr_t) + sizeof (uintptr_t) + sizeof (ulong_t) +
223 sizeof (ulong_t) + sizeof (Sym);
224
225 /*
226 * Continue with generic startup processing.
227 */
228 if ((lmp = setup((char **)_envp, (auxv_t *)_auxv, _flags, _platform,
229 _syspagsz, _rt_name, ld_base, interp_base, fd, phdr,
230 _execname, _argv, uid, euid, gid, egid, NULL, auxflags,
231 hwcap_1)) == NULL) {
232 rtldexit(&lml_main, 1);
233 }
234
235 return (LM_ENTRY_PT(lmp)());
236 }
237