xref: /openbsd-src/libexec/ld.so/loader.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: loader.c,v 1.150 2014/07/10 09:03:01 otto Exp $ */
2 
3 /*
4  * Copyright (c) 1998 Per Fogelstrom, Opsycon AB
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  */
28 
29 #define	_DYN_LOADER
30 
31 #include <sys/types.h>
32 #include <sys/mman.h>
33 #include <sys/exec.h>
34 #include <sys/param.h>
35 #include <sys/sysctl.h>
36 #include <nlist.h>
37 #include <string.h>
38 #include <link.h>
39 #include <dlfcn.h>
40 
41 #include "syscall.h"
42 #include "archdep.h"
43 #include "path.h"
44 #include "resolve.h"
45 #include "sod.h"
46 #include "stdlib.h"
47 #include "dl_prebind.h"
48 
49 /*
50  * Local decls.
51  */
52 unsigned long _dl_boot(const char **, char **, const long, long *);
53 void _dl_debug_state(void);
54 void _dl_setup_env(char **);
55 void _dl_dtors(void);
56 void _dl_fixup_user_env(void);
57 void _dl_call_init_recurse(elf_object_t *object, int initfirst);
58 
59 const char *_dl_progname;
60 int  _dl_pagesz;
61 
62 char **_dl_libpath;
63 
64 char *_dl_preload;
65 char *_dl_bindnow;
66 char *_dl_traceld;
67 char *_dl_debug;
68 char *_dl_showmap;
69 char *_dl_noprebind;
70 char *_dl_prebind_validate;
71 char *_dl_tracefmt1, *_dl_tracefmt2, *_dl_traceprog;
72 
73 int _dl_trust;
74 
75 struct r_debug *_dl_debug_map;
76 
77 void _dl_dopreload(char *paths);
78 
79 /*
80  * Run dtors for all objects that are eligible.
81  */
82 
83 void
84 _dl_run_all_dtors(void)
85 {
86 	elf_object_t *node;
87 	struct dep_node *dnode;
88 	int fini_complete;
89 	int skip_initfirst;
90 	int initfirst_skipped;
91 
92 	fini_complete = 0;
93 	skip_initfirst = 1;
94 	initfirst_skipped = 0;
95 
96 	while (fini_complete == 0) {
97 		fini_complete = 1;
98 		for (node = _dl_objects->next;
99 		    node != NULL;
100 		    node = node->next) {
101 			if ((node->dyn.fini) &&
102 			    (OBJECT_REF_CNT(node) == 0) &&
103 			    (node->status & STAT_INIT_DONE) &&
104 			    ((node->status & STAT_FINI_DONE) == 0)) {
105 				if (skip_initfirst &&
106 				    (node->obj_flags & DF_1_INITFIRST))
107 					initfirst_skipped = 1;
108 				else
109 					node->status |= STAT_FINI_READY;
110 			    }
111 		}
112 		for (node = _dl_objects->next;
113 		    node != NULL;
114 		    node = node->next ) {
115 			if ((node->dyn.fini) &&
116 			    (OBJECT_REF_CNT(node) == 0) &&
117 			    (node->status & STAT_INIT_DONE) &&
118 			    ((node->status & STAT_FINI_DONE) == 0) &&
119 			    (!skip_initfirst ||
120 			    (node->obj_flags & DF_1_INITFIRST) == 0))
121 				TAILQ_FOREACH(dnode, &node->child_list,
122 				    next_sib)
123 					dnode->data->status &= ~STAT_FINI_READY;
124 		}
125 
126 
127 		for (node = _dl_objects->next;
128 		    node != NULL;
129 		    node = node->next ) {
130 			if (node->status & STAT_FINI_READY) {
131 				DL_DEB(("doing dtors obj %p @%p: [%s]\n",
132 				    node, node->dyn.fini,
133 				    node->load_name));
134 
135 				fini_complete = 0;
136 				node->status |= STAT_FINI_DONE;
137 				node->status &= ~STAT_FINI_READY;
138 				(*node->dyn.fini)();
139 			}
140 		}
141 
142 		if (fini_complete && initfirst_skipped)
143                         fini_complete = initfirst_skipped = skip_initfirst = 0;
144 	}
145 }
146 
147 /*
148  * Routine to walk through all of the objects except the first
149  * (main executable).
150  *
151  * Big question, should dlopen()ed objects be unloaded before or after
152  * the destructor for the main application runs?
153  */
154 void
155 _dl_dtors(void)
156 {
157 	_dl_thread_kern_stop();
158 
159 	/* ORDER? */
160 	_dl_unload_dlopen();
161 
162 	DL_DEB(("doing dtors\n"));
163 
164 	/* main program runs its dtors itself
165 	 * but we want to run dtors on all it's children);
166 	 */
167 	_dl_objects->status |= STAT_FINI_DONE;
168 
169 	_dl_objects->opencount--;
170 	_dl_notify_unload_shlib(_dl_objects);
171 
172 	_dl_run_all_dtors();
173 }
174 
175 void
176 _dl_dopreload(char *paths)
177 {
178 	char		*cp, *dp;
179 	elf_object_t	*shlib;
180 
181 	dp = paths = _dl_strdup(paths);
182 	if (dp == NULL) {
183 		_dl_printf("preload: out of memory");
184 		_dl_exit(1);
185 	}
186 
187 	while ((cp = _dl_strsep(&dp, ":")) != NULL) {
188 		shlib = _dl_load_shlib(cp, _dl_objects, OBJTYPE_LIB,
189 		_dl_objects->obj_flags);
190 		if (shlib == NULL) {
191 			_dl_printf("%s: can't preload library '%s'\n",
192 			    _dl_progname, cp);
193 			_dl_exit(4);
194 		}
195 		_dl_add_object(shlib);
196 		_dl_link_child(shlib, _dl_objects);
197 	}
198 	_dl_free(paths);
199 	return;
200 }
201 
202 /*
203  * grab interesting environment variables, zap bad env vars if
204  * issetugid
205  */
206 char **_dl_so_envp;
207 void
208 _dl_setup_env(char **envp)
209 {
210 	/*
211 	 * Get paths to various things we are going to use.
212 	 */
213 	_dl_debug = _dl_getenv("LD_DEBUG", envp);
214 	_dl_libpath = _dl_split_path(_dl_getenv("LD_LIBRARY_PATH", envp));
215 	_dl_preload = _dl_getenv("LD_PRELOAD", envp);
216 	_dl_bindnow = _dl_getenv("LD_BIND_NOW", envp);
217 	_dl_traceld = _dl_getenv("LD_TRACE_LOADED_OBJECTS", envp);
218 	_dl_tracefmt1 = _dl_getenv("LD_TRACE_LOADED_OBJECTS_FMT1", envp);
219 	_dl_tracefmt2 = _dl_getenv("LD_TRACE_LOADED_OBJECTS_FMT2", envp);
220 	_dl_traceprog = _dl_getenv("LD_TRACE_LOADED_OBJECTS_PROGNAME", envp);
221 	_dl_noprebind = _dl_getenv("LD_NOPREBIND", envp);
222 	_dl_prebind_validate = _dl_getenv("LD_PREBINDVALIDATE", envp);
223 
224 	/*
225 	 * Don't allow someone to change the search paths if he runs
226 	 * a suid program without credentials high enough.
227 	 */
228 	_dl_trust = !_dl_issetugid();
229 	if (!_dl_trust) {	/* Zap paths if s[ug]id... */
230 		if (_dl_libpath) {
231 			_dl_free_path(_dl_libpath);
232 			_dl_libpath = NULL;
233 			_dl_unsetenv("LD_LIBRARY_PATH", envp);
234 		}
235 		if (_dl_preload) {
236 			_dl_preload = NULL;
237 			_dl_unsetenv("LD_PRELOAD", envp);
238 		}
239 		if (_dl_bindnow) {
240 			_dl_bindnow = NULL;
241 			_dl_unsetenv("LD_BIND_NOW", envp);
242 		}
243 		if (_dl_debug) {
244 			_dl_debug = NULL;
245 			_dl_unsetenv("LD_DEBUG", envp);
246 		}
247 	}
248 	_dl_so_envp = envp;
249 
250 	_dl_trace_setup(envp);
251 }
252 
253 int
254 _dl_load_dep_libs(elf_object_t *object, int flags, int booting)
255 {
256 	elf_object_t *dynobj;
257 	Elf_Dyn *dynp;
258 	unsigned int loop;
259 	int libcount;
260 	int depflags;
261 
262 	dynobj = object;
263 	while (dynobj) {
264 		DL_DEB(("examining: '%s'\n", dynobj->load_name));
265 		libcount = 0;
266 
267 		/* propagate DF_1_NOW to deplibs (can be set by dynamic tags) */
268 		depflags = flags | (dynobj->obj_flags & DF_1_NOW);
269 
270 		for (dynp = dynobj->load_dyn; dynp->d_tag; dynp++) {
271 			if (dynp->d_tag == DT_NEEDED) {
272 				libcount++;
273 			}
274 		}
275 
276 		if ( libcount != 0) {
277 			struct listent {
278 				Elf_Dyn *dynp;
279 				elf_object_t *depobj;
280 			} *liblist;
281 			int *randomlist;
282 
283 			liblist = _dl_reallocarray(NULL, libcount,
284 			    sizeof(struct listent));
285 			randomlist =  _dl_reallocarray(NULL, libcount,
286 			    sizeof(int));
287 
288 			if (liblist == NULL || randomlist == NULL)
289 				_dl_exit(5);
290 
291 			for (dynp = dynobj->load_dyn, loop = 0; dynp->d_tag;
292 			    dynp++)
293 				if (dynp->d_tag == DT_NEEDED)
294 					liblist[loop++].dynp = dynp;
295 
296 			/* Randomize these */
297 			for (loop = 0; loop < libcount; loop++)
298 				randomlist[loop] = loop;
299 
300 			for (loop = 1; loop < libcount; loop++) {
301 				unsigned int rnd;
302 				int cur;
303 				rnd = _dl_random();
304 				rnd = rnd % (loop+1);
305 				cur = randomlist[rnd];
306 				randomlist[rnd] = randomlist[loop];
307 				randomlist[loop] = cur;
308 			}
309 
310 			for (loop = 0; loop < libcount; loop++) {
311 				elf_object_t *depobj;
312 				const char *libname;
313 				libname = dynobj->dyn.strtab;
314 				libname +=
315 				    liblist[randomlist[loop]].dynp->d_un.d_val;
316 				DL_DEB(("loading: %s required by %s\n", libname,
317 				    dynobj->load_name));
318 				depobj = _dl_load_shlib(libname, dynobj,
319 				    OBJTYPE_LIB, depflags);
320 				if (depobj == 0) {
321 					if (booting) {
322 						_dl_printf(
323 						    "%s: can't load library '%s'\n",
324 						    _dl_progname, libname);
325 						_dl_exit(4);
326 					} else  {
327 						DL_DEB(("dlopen: failed to open %s\n",
328 						    libname));
329 						_dl_free(liblist);
330 						return (1);
331 					}
332 				}
333 				liblist[randomlist[loop]].depobj = depobj;
334 			}
335 
336 			for (loop = 0; loop < libcount; loop++) {
337 				_dl_add_object(liblist[loop].depobj);
338 				_dl_link_child(liblist[loop].depobj, dynobj);
339 			}
340 			_dl_free(liblist);
341 		}
342 		dynobj = dynobj->next;
343 	}
344 
345 	/* add first object manually */
346 	_dl_link_grpsym(object, 1);
347 	_dl_cache_grpsym_list_setup(object);
348 
349 	return(0);
350 }
351 
352 
353 #define PFLAGS(X) ((((X) & PF_R) ? PROT_READ : 0) | \
354 		   (((X) & PF_W) ? PROT_WRITE : 0) | \
355 		   (((X) & PF_X) ? PROT_EXEC : 0))
356 
357 /*
358  * This is the dynamic loader entrypoint. When entering here, depending
359  * on architecture type, the stack and registers are set up according
360  * to the architectures ABI specification. The first thing required
361  * to do is to dig out all information we need to accomplish our task.
362  */
363 unsigned long
364 _dl_boot(const char **argv, char **envp, const long dyn_loff, long *dl_data)
365 {
366 	struct elf_object *exe_obj;	/* Pointer to executable object */
367 	struct elf_object *dyn_obj;	/* Pointer to executable object */
368 	struct r_debug **map_link;	/* Where to put pointer for gdb */
369 	struct r_debug *debug_map;
370 	struct load_list *next_load, *load_list = NULL;
371 	Elf_Dyn *dynp;
372 	Elf_Phdr *phdp;
373 	Elf_Ehdr *ehdr;
374 	char *us = NULL;
375 	unsigned int loop;
376 	int failed;
377 	struct dep_node *n;
378 	Elf_Addr minva, maxva, exe_loff;
379 	int align;
380 
381 	_dl_setup_env(envp);
382 
383 	_dl_progname = argv[0];
384 	if (dl_data[AUX_pagesz] != 0)
385 		_dl_pagesz = dl_data[AUX_pagesz];
386 	else
387 		_dl_pagesz = 4096;
388 
389 	align = _dl_pagesz - 1;
390 
391 #define ROUND_PG(x) (((x) + align) & ~(align))
392 #define TRUNC_PG(x) ((x) & ~(align))
393 
394 	/*
395 	 * now that GOT and PLT have been relocated, and we know
396 	 * page size, protect them from modification
397 	 */
398 #ifndef  RTLD_NO_WXORX
399 	{
400 		extern char *__got_start;
401 		extern char *__got_end;
402 #ifdef RTLD_PROTECT_PLT
403 		extern char *__plt_start;
404 		extern char *__plt_end;
405 #endif
406 
407 		_dl_mprotect((void *)ELF_TRUNC((long)&__got_start, _dl_pagesz),
408 		    ELF_ROUND((long)&__got_end,_dl_pagesz) -
409 		    ELF_TRUNC((long)&__got_start, _dl_pagesz),
410 		    GOT_PERMS);
411 
412 #ifdef RTLD_PROTECT_PLT
413 		/* only for DATA_PLT or BSS_PLT */
414 		_dl_mprotect((void *)ELF_TRUNC((long)&__plt_start, _dl_pagesz),
415 		    ELF_ROUND((long)&__plt_end,_dl_pagesz) -
416 		    ELF_TRUNC((long)&__plt_start, _dl_pagesz),
417 		    PROT_READ|PROT_EXEC);
418 #endif
419 	}
420 #endif
421 
422 	DL_DEB(("rtld loading: '%s'\n", _dl_progname));
423 
424 	/* init this in runtime, not statically */
425 	TAILQ_INIT(&_dlopened_child_list);
426 
427 	exe_obj = NULL;
428 	_dl_loading_object = NULL;
429 
430 	minva = ELFDEFNNAME(NO_ADDR);
431 	maxva = exe_loff = 0;
432 
433 	/*
434 	 * Examine the user application and set up object information.
435 	 */
436 	phdp = (Elf_Phdr *)dl_data[AUX_phdr];
437 	for (loop = 0; loop < dl_data[AUX_phnum]; loop++) {
438 		switch (phdp->p_type) {
439 		case PT_PHDR:
440 			exe_loff = (Elf_Addr)dl_data[AUX_phdr] - phdp->p_vaddr;
441 			us += exe_loff;
442 			DL_DEB(("exe load offset:  0x%lx\n", exe_loff));
443 			break;
444 		case PT_DYNAMIC:
445 			minva = TRUNC_PG(minva);
446 			maxva = ROUND_PG(maxva);
447 			exe_obj = _dl_finalize_object(argv[0] ? argv[0] : "",
448 			    (Elf_Dyn *)(phdp->p_vaddr + exe_loff),
449 			    (Elf_Phdr *)dl_data[AUX_phdr],
450 			    dl_data[AUX_phnum], OBJTYPE_EXE, minva + exe_loff,
451 			    exe_loff);
452 			_dl_add_object(exe_obj);
453 			break;
454 		case PT_INTERP:
455 			us += phdp->p_vaddr;
456 			break;
457 		case PT_LOAD:
458 			if (phdp->p_vaddr < minva)
459 				minva = phdp->p_vaddr;
460 			if (phdp->p_vaddr > maxva)
461 				maxva = phdp->p_vaddr + phdp->p_memsz;
462 
463 			next_load = _dl_calloc(1, sizeof(struct load_list));
464 			if (next_load == NULL)
465 				_dl_exit(5);
466 			next_load->next = load_list;
467 			load_list = next_load;
468 			next_load->start = (char *)TRUNC_PG(phdp->p_vaddr) + exe_loff;
469 			next_load->size = (phdp->p_vaddr & align) + phdp->p_filesz;
470 			next_load->prot = PFLAGS(phdp->p_flags);
471 
472 			if (phdp->p_flags & 0x08000000) {
473 //				dump_prelink(phdp->p_vaddr + exe_loff, phdp->p_memsz);
474 				prebind_load_exe(phdp, exe_obj);
475 			}
476 			break;
477 		case PT_TLS:
478 			_dl_printf("%s: unsupported TLS program header\n",
479 			    _dl_progname);
480 			_dl_exit(1);
481 			break;
482 		}
483 		phdp++;
484 	}
485 	exe_obj->load_list = load_list;
486 	exe_obj->obj_flags |= DF_1_GLOBAL;
487 	exe_obj->load_size = maxva - minva;
488 	_dl_set_sod(exe_obj->load_name, &exe_obj->sod);
489 
490 	n = _dl_malloc(sizeof *n);
491 	if (n == NULL)
492 		_dl_exit(5);
493 	n->data = exe_obj;
494 	TAILQ_INSERT_TAIL(&_dlopened_child_list, n, next_sib);
495 	exe_obj->opencount++;
496 
497 	if (_dl_preload != NULL)
498 		_dl_dopreload(_dl_preload);
499 
500 	_dl_load_dep_libs(exe_obj, exe_obj->obj_flags, 1);
501 
502 	/*
503 	 * Now add the dynamic loader itself last in the object list
504 	 * so we can use the _dl_ code when serving dl.... calls.
505 	 * Intentionally left off the exe child_list.
506 	 */
507 	dynp = (Elf_Dyn *)((void *)_DYNAMIC);
508 	ehdr = (Elf_Ehdr *)dl_data[AUX_base];
509         dyn_obj = _dl_finalize_object(us, dynp,
510 	    (Elf_Phdr *)((char *)dl_data[AUX_base] + ehdr->e_phoff),
511 	    ehdr->e_phnum, OBJTYPE_LDR, dl_data[AUX_base], dyn_loff);
512 	_dl_add_object(dyn_obj);
513 
514 	dyn_obj->refcount++;
515 	_dl_link_grpsym(dyn_obj, 1);
516 
517 	dyn_obj->status |= STAT_RELOC_DONE;
518 	_dl_set_sod(dyn_obj->load_name, &dyn_obj->sod);
519 
520 	/*
521 	 * Everything should be in place now for doing the relocation
522 	 * and binding. Call _dl_rtld to do the job. Fingers crossed.
523 	 */
524 
525 	_dl_prebind_pre_resolve();
526 	failed = 0;
527 	if (_dl_traceld == NULL)
528 		failed = _dl_rtld(_dl_objects);
529 
530 	_dl_prebind_post_resolve();
531 
532 	if (_dl_debug || _dl_traceld)
533 		_dl_show_objects();
534 
535 	DL_DEB(("dynamic loading done, %s.\n",
536 	    (failed == 0) ? "success":"failed"));
537 
538 	if (failed != 0)
539 		_dl_exit(1);
540 
541 	if (_dl_traceld)
542 		_dl_exit(0);
543 
544 	_dl_loading_object = NULL;
545 
546 	_dl_fixup_user_env();
547 
548 	/*
549 	 * Finally make something to help gdb when poking around in the code.
550 	 */
551 	map_link = NULL;
552 #ifdef __mips__
553 	map_link = (struct r_debug **)(exe_obj->Dyn.info[DT_MIPS_RLD_MAP -
554 	    DT_LOPROC + DT_NUM]);
555 #endif
556 	if (map_link == NULL) {
557 		for (dynp = exe_obj->load_dyn; dynp->d_tag; dynp++) {
558 			if (dynp->d_tag == DT_DEBUG) {
559 				map_link = (struct r_debug **)&dynp->d_un.d_ptr;
560 				break;
561 			}
562 		}
563 		if (dynp->d_tag != DT_DEBUG)
564 			DL_DEB(("failed to mark DTDEBUG\n"));
565 	}
566 	if (map_link) {
567 		debug_map = (struct r_debug *)_dl_malloc(sizeof(*debug_map));
568 		if (debug_map == NULL)
569 			_dl_exit(5);
570 		debug_map->r_version = 1;
571 		debug_map->r_map = (struct link_map *)_dl_objects;
572 		debug_map->r_brk = (Elf_Addr)_dl_debug_state;
573 		debug_map->r_state = RT_CONSISTENT;
574 		debug_map->r_ldbase = dyn_loff;
575 		_dl_debug_map = debug_map;
576 #ifdef __mips__
577 		if (dynp->d_tag == DT_DEBUG)
578 			_dl_mprotect(map_link, sizeof(*map_link),
579 			    PROT_READ|PROT_WRITE|PROT_EXEC);
580 #endif
581 		*map_link = _dl_debug_map;
582 #ifdef __mips__
583 		if (dynp->d_tag == DT_DEBUG)
584 			_dl_mprotect(map_link, sizeof(*map_link),
585 			    PROT_READ|PROT_EXEC);
586 #endif
587 	}
588 
589 	_dl_debug_state();
590 
591 	/*
592 	 * The first object is the executable itself,
593 	 * it is responsible for running it's own ctors/dtors
594 	 * thus do NOT run the ctors for the executable, all of
595 	 * the shared libraries which follow.
596 	 * Do not run init code if run from ldd.
597 	 */
598 	if (_dl_objects->next != NULL) {
599 		_dl_objects->status |= STAT_INIT_DONE;
600 		_dl_call_init(_dl_objects);
601 	}
602 
603 	DL_DEB(("entry point: 0x%lx\n", dl_data[AUX_entry]));
604 
605 	/*
606 	 * Return the entry point.
607 	 */
608 	return(dl_data[AUX_entry]);
609 }
610 
611 #define DL_SM_SYMBUF_CNT 512
612 sym_cache _dl_sm_symcache_buffer[DL_SM_SYMBUF_CNT];
613 
614 int
615 _dl_rtld(elf_object_t *object)
616 {
617 	size_t sz;
618 	int fails = 0;
619 
620 	if (object->next)
621 		fails += _dl_rtld(object->next);
622 
623 	if (object->status & STAT_RELOC_DONE)
624 		return 0;
625 
626 	sz = 0;
627 	if (object->nchains < DL_SM_SYMBUF_CNT) {
628 		_dl_symcache = _dl_sm_symcache_buffer;
629 //		DL_DEB(("using static buffer for %d entries\n",
630 //		    object->nchains));
631 		_dl_memset(_dl_symcache, 0,
632 		    sizeof (sym_cache) * object->nchains);
633 	} else {
634 		sz = ELF_ROUND(sizeof (sym_cache) * object->nchains,
635 		    _dl_pagesz);
636 //		DL_DEB(("allocating symcache sz %x with mmap\n", sz));
637 
638 		_dl_symcache = (void *)_dl_mmap(0, sz, PROT_READ|PROT_WRITE,
639 		    MAP_PRIVATE|MAP_ANON, -1, 0);
640 		if (_dl_mmap_error(_dl_symcache)) {
641 			sz = 0;
642 			_dl_symcache = NULL;
643 		}
644 	}
645 	prebind_symcache(object, SYM_NOTPLT);
646 
647 	/*
648 	 * Do relocation information first, then GOT.
649 	 */
650 	fails =_dl_md_reloc(object, DT_REL, DT_RELSZ);
651 	fails += _dl_md_reloc(object, DT_RELA, DT_RELASZ);
652 	prebind_symcache(object, SYM_PLT);
653 	fails += _dl_md_reloc_got(object, !(_dl_bindnow ||
654 	    object->obj_flags & DF_1_NOW));
655 
656 	if (_dl_symcache != NULL) {
657 		if (sz != 0)
658 			_dl_munmap( _dl_symcache, sz);
659 		_dl_symcache = NULL;
660 	}
661 	if (fails == 0)
662 		object->status |= STAT_RELOC_DONE;
663 
664 	return (fails);
665 }
666 
667 void
668 _dl_call_init(elf_object_t *object)
669 {
670 	_dl_call_init_recurse(object, 1);
671 	_dl_call_init_recurse(object, 0);
672 }
673 
674 void
675 _dl_call_init_recurse(elf_object_t *object, int initfirst)
676 {
677 	struct dep_node *n;
678 
679 	object->status |= STAT_VISITED;
680 
681 	TAILQ_FOREACH(n, &object->child_list, next_sib) {
682 		if (n->data->status & STAT_VISITED)
683 			continue;
684 		_dl_call_init_recurse(n->data, initfirst);
685 	}
686 
687 	object->status &= ~STAT_VISITED;
688 
689 	if (object->status & STAT_INIT_DONE)
690 		return;
691 
692 	if (initfirst && (object->obj_flags & DF_1_INITFIRST) == 0)
693 		return;
694 
695 	if (object->dyn.init) {
696 		DL_DEB(("doing ctors obj %p @%p: [%s]\n",
697 		    object, object->dyn.init, object->load_name));
698 		(*object->dyn.init)();
699 	}
700 
701 	object->status |= STAT_INIT_DONE;
702 }
703 
704 char *
705 _dl_getenv(const char *var, char **env)
706 {
707 	const char *ep;
708 
709 	while ((ep = *env++)) {
710 		const char *vp = var;
711 
712 		while (*vp && *vp == *ep) {
713 			vp++;
714 			ep++;
715 		}
716 		if (*vp == '\0' && *ep++ == '=')
717 			return((char *)ep);
718 	}
719 	return(NULL);
720 }
721 
722 void
723 _dl_unsetenv(const char *var, char **env)
724 {
725 	char *ep;
726 
727 	while ((ep = *env)) {
728 		const char *vp = var;
729 
730 		while (*vp && *vp == *ep) {
731 			vp++;
732 			ep++;
733 		}
734 		if (*vp == '\0' && *ep++ == '=') {
735 			char **P;
736 
737 			for (P = env;; ++P)
738 				if (!(*P = *(P + 1)))
739 					break;
740 		} else
741 			env++;
742 	}
743 }
744 
745 /*
746  * _dl_fixup_user_env()
747  *
748  * Set the user environment so that programs can use the environment
749  * while running constructors. Specifically, MALLOC_OPTIONS= for malloc()
750  */
751 void
752 _dl_fixup_user_env(void)
753 {
754 	const Elf_Sym *sym;
755 	Elf_Addr ooff;
756 	struct elf_object dummy_obj;
757 
758 	dummy_obj.dyn.symbolic = 0;
759 	dummy_obj.load_name = "ld.so";
760 
761 	sym = NULL;
762 	ooff = _dl_find_symbol("environ", &sym,
763 	    SYM_SEARCH_ALL|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, &dummy_obj, NULL);
764 	if (sym != NULL)
765 		*((char ***)(sym->st_value + ooff)) = _dl_so_envp;
766 }
767