xref: /titanic_50/usr/src/cmd/sgs/rtld/common/a.out.c (revision 672986541be54a7a471bb088e60780c37e371d7e)
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 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * Object file dependent support for a.out format objects.
30  */
31 #include	"_synonyms.h"
32 
33 #include	<a.out.h>		/* Explicitly override M_SEGSIZE */
34 #include	<machdep.h>		/*	used in M_SROUND */
35 
36 #include	<sys/mman.h>
37 #include	<unistd.h>
38 #include	<string.h>
39 #include	<limits.h>
40 #include	<stdio.h>
41 #include	<dlfcn.h>
42 #include	<errno.h>
43 #include	<debug.h>
44 #include	"_a.out.h"
45 #include	"cache_a.out.h"
46 #include	"msg.h"
47 #include	"_rtld.h"
48 
49 /*
50  * Default and secure dependency search paths.
51  */
52 static Pnode		aout_dflt_dirs[] = {
53 	{ MSG_ORIG(MSG_PTH_USR4LIB),	0,	MSG_PTH_USR4LIB_SIZE,
54 		LA_SER_DEFAULT,		0,	&aout_dflt_dirs[1] },
55 	{ MSG_ORIG(MSG_PTH_USRLIB),	0,	MSG_PTH_USRLIB_SIZE,
56 		LA_SER_DEFAULT,		0,	&aout_dflt_dirs[2] },
57 	{ MSG_ORIG(MSG_PTH_USRLCLIB),	0,	MSG_PTH_USRLCLIB_SIZE,
58 		LA_SER_DEFAULT,		0, 0 }
59 };
60 
61 static Pnode		aout_secure_dirs[] = {
62 	{ MSG_ORIG(MSG_PTH_USR4LIB),	0,	MSG_PTH_USR4LIB_SIZE,
63 		LA_SER_SECURE,		0,	&aout_secure_dirs[1] },
64 	{ MSG_ORIG(MSG_PTH_USRLIB),	0,	MSG_PTH_USRLIB_SIZE,
65 		LA_SER_SECURE,		0,	&aout_secure_dirs[2] },
66 	{ MSG_ORIG(MSG_PTH_USRUCBLIB),	0,	MSG_PTH_USRUCBLIB_SIZE,
67 		LA_SER_SECURE,		0,	&aout_secure_dirs[3] },
68 	{ MSG_ORIG(MSG_PTH_USRLCLIB),	0,	MSG_PTH_USRLCLIB_SIZE,
69 		LA_SER_SECURE,		0, 0 }
70 };
71 
72 /*
73  * Defines for local functions.
74  */
75 static int		aout_are_u();
76 static ulong_t		aout_entry_pt();
77 static Rt_map		*aout_map_so();
78 static void		aout_unmap_so();
79 static int		aout_needed();
80 extern Sym		*aout_lookup_sym();
81 static Sym		*aout_find_sym();
82 static char		*aout_get_so();
83 static Pnode		*aout_fix_name();
84 static void		aout_dladdr();
85 static Sym		*aout_dlsym_handle();
86 static int		aout_verify_vers();
87 
88 /*
89  * Functions and data accessed through indirect pointers.
90  */
91 Fct aout_fct = {
92 	aout_are_u,
93 	aout_entry_pt,
94 	aout_map_so,
95 	aout_unmap_so,
96 	aout_needed,
97 	aout_lookup_sym,
98 	aout_reloc,
99 	aout_dflt_dirs,
100 	aout_secure_dirs,
101 	aout_fix_name,
102 	aout_get_so,
103 	aout_dladdr,
104 	aout_dlsym_handle,
105 	aout_verify_vers,
106 	aout_set_prot
107 };
108 
109 
110 /*
111  * In 4.x, a needed file or a dlopened file that was a simple file name implied
112  * that the file be found in the present working directory.  To simulate this
113  * lookup within the elf rules it is necessary to add a proceeding `./' to the
114  * filename.
115  */
116 static Pnode *
117 aout_fix_name(const char *name, Rt_map *clmp)
118 {
119 	size_t	len;
120 	Pnode	*pnp;
121 
122 	if ((pnp = calloc(1, sizeof (Pnode))) == 0)
123 		return (0);
124 
125 	/*
126 	 * Check for slash in name, if none, prepend "./", otherwise just
127 	 * return name given.
128 	 */
129 	if (strchr(name, '/')) {
130 		len = strlen(name) + 1;
131 		if ((pnp->p_name = malloc(len)) != 0)
132 			(void) strcpy((char *)pnp->p_name, name);
133 	} else {
134 		len = strlen(name) + 3;
135 		if ((pnp->p_name = malloc(len)) != 0)
136 			(void) snprintf((char *)pnp->p_name, len,
137 			    MSG_ORIG(MSG_FMT_4XPATH), name);
138 	}
139 
140 	if (pnp->p_name) {
141 		pnp->p_len = len;
142 		pnp->p_orig = PN_SER_NEEDED;
143 		DBG_CALL(Dbg_file_fixname(LIST(clmp), pnp->p_name, name));
144 		return (pnp);
145 	}
146 	free(pnp);
147 	return (0);
148 }
149 
150 /*
151  * Determine if we have been given an A_OUT file.  Returns 1 if true.
152  */
153 static int
154 aout_are_u()
155 {
156 	struct exec *exec;
157 
158 	/* LINTED */
159 	exec = (struct exec *)fmap->fm_maddr;
160 	if (fmap->fm_fsize < sizeof (exec) || (exec->a_machtype != M_SPARC) ||
161 	    (N_BADMAG(*exec))) {
162 		return (0);
163 	}
164 	return (1);
165 }
166 
167 /*
168  * Return the entry point the A_OUT executable. This is always zero.
169  */
170 static ulong_t
171 aout_entry_pt()
172 {
173 	return (0);
174 }
175 
176 /*
177  * Unmap a given A_OUT shared object from the address space.
178  */
179 static void
180 aout_unmap_so(Rt_map *lmp)
181 {
182 	Mmap	*immap = MMAPS(lmp);
183 
184 	(void) munmap(immap->m_vaddr, immap->m_msize);
185 }
186 
187 /*
188  * Dummy versioning interface - real functionality is only applicable to elf.
189  */
190 static int
191 aout_verify_vers()
192 {
193 	return (1);
194 }
195 
196 /*
197  * Search through the dynamic section for DT_NEEDED entries and perform one
198  * of two functions.  If only the first argument is specified then load the
199  * defined shared object, otherwise add the link map representing the
200  * defined link map the the dlopen list.
201  */
202 static int
203 aout_needed(Lm_list *lml, Aliste lmco, Rt_map *clmp)
204 {
205 	void	*need;
206 
207 	for (need = &TEXTBASE(clmp)[AOUTDYN(clmp)->v2->ld_need];
208 	    need != &TEXTBASE(clmp)[0];
209 	    need = &TEXTBASE(clmp)[((Lnk_obj *)(need))->lo_next]) {
210 		Rt_map	*nlmp;
211 		char	*name;
212 		Pnode	*pnp;
213 
214 		name = &TEXTBASE(clmp)[((Lnk_obj *)(need))->lo_name];
215 
216 		if (((Lnk_obj *)(need))->lo_library) {
217 			/*
218 			 * If lo_library field is not NULL then this needed
219 			 * library was linked in using the "-l" option.
220 			 * Thus we need to rebuild the library name before
221 			 * trying to load it.
222 			 */
223 			Pnode	*dir, *dirlist = (Pnode *)0;
224 			char	*file;
225 			size_t	len;
226 
227 			/*
228 			 * Allocate name length plus 20 for full library name.
229 			 * lib.so.. = 7 + (2 * short) + NULL = 7 + 12 + 1 = 20
230 			 */
231 			len = strlen(name) + 20;
232 			if ((file = malloc(len)) == 0)
233 				return (0);
234 			(void) snprintf(file, len, MSG_ORIG(MSG_FMT_4XLIB),
235 			    name, ((Lnk_obj *)(need))->lo_major,
236 			    ((Lnk_obj *)(need))->lo_minor);
237 
238 			DBG_CALL(Dbg_libs_find(lml, file));
239 
240 			/*
241 			 * We need to determine what filename will match the
242 			 * the filename specified (ie, a libc.so.1.2 may match
243 			 * to a libc.so.1.3).  It's the real pathname that is
244 			 * recorded in the link maps.  If we are presently
245 			 * being traced, skip this pathname generation so
246 			 * that we fall through into load_so() to print the
247 			 * appropriate diagnostics.  I don't like this at all.
248 			 */
249 			if (lml->lm_flags & LML_FLG_TRC_ENABLE)
250 				name = file;
251 			else {
252 				char	*path = (char *)0;
253 
254 				for (dir = get_next_dir(&dirlist, clmp, 0); dir;
255 				    dir = get_next_dir(&dirlist, clmp, 0)) {
256 					if (dir->p_name == 0)
257 						continue;
258 
259 					if (path =
260 					    aout_get_so(dir->p_name, file))
261 						break;
262 				}
263 				if (!path) {
264 					eprintf(lml, ERR_FATAL,
265 					    MSG_INTL(MSG_SYS_OPEN), file,
266 					    strerror(ENOENT));
267 					return (0);
268 				}
269 				name = path;
270 			}
271 			if ((pnp = expand_paths(clmp, name,
272 			    PN_SER_NEEDED, 0)) == 0)
273 				return (0);
274 		} else {
275 			/*
276 			 * If the library is specified as a pathname, see if
277 			 * it must be fixed to specify the current working
278 			 * directory (ie. libc.so.1.2 -> ./libc.so.1.2).
279 			 */
280 			if ((pnp = aout_fix_name(name, clmp)) == 0)
281 				return (0);
282 		}
283 
284 		DBG_CALL(Dbg_file_needed(clmp, name));
285 
286 		nlmp = load_one(lml, lmco, pnp, clmp, MODE(clmp), 0, 0);
287 		remove_pnode(pnp);
288 		if (((nlmp == 0) || (bind_one(clmp, nlmp, BND_NEEDED) == 0)) &&
289 		    ((lml->lm_flags & LML_FLG_TRC_ENABLE) == 0))
290 			return (0);
291 	}
292 
293 	return (1);
294 }
295 
296 static Sym *
297 aout_symconvert(struct nlist *sp)
298 {
299 	static Sym	sym;
300 
301 	sym.st_value = sp->n_value;
302 	sym.st_size = 0;
303 	sym.st_info = 0;
304 	sym.st_other = 0;
305 	switch (sp->n_type) {
306 		case N_EXT + N_ABS:
307 			sym.st_shndx = SHN_ABS;
308 			break;
309 		case N_COMM:
310 			sym.st_shndx = SHN_COMMON;
311 			break;
312 		case N_EXT + N_UNDF:
313 			sym.st_shndx = SHN_UNDEF;
314 			break;
315 		default:
316 			sym.st_shndx = 0;
317 			break;
318 	}
319 	return (&sym);
320 }
321 
322 /*
323  * Process a.out format commons.
324  */
325 static struct nlist *
326 aout_find_com(struct nlist *sp, const char *name)
327 {
328 	static struct rtc_symb	*rtcp = 0;
329 	struct rtc_symb		*rs, * trs;
330 	const char		*sl;
331 	char			*cp;
332 
333 	/*
334 	 * See if common is already allocated.
335 	 */
336 	trs = rtcp;
337 	while (trs) {
338 		sl = name;
339 		cp = trs->rtc_sp->n_un.n_name;
340 		while (*sl == *cp++)
341 			if (*sl++ == '\0')
342 				return (trs->rtc_sp);
343 		trs = trs->rtc_next;
344 	}
345 
346 	/*
347 	 * If we got here, common is not already allocated so allocate it.
348 	 */
349 	if ((rs = malloc(sizeof (struct rtc_symb))) == 0)
350 		return (0);
351 	if ((rs->rtc_sp = malloc(sizeof (struct nlist))) == 0)
352 		return (0);
353 	trs = rtcp;
354 	rtcp = rs;
355 	rs->rtc_next = trs;
356 	*(rs->rtc_sp) = *sp;
357 	if ((rs->rtc_sp->n_un.n_name = malloc(strlen(name) + 1)) == 0)
358 		return (0);
359 	(void) strcpy(rs->rtc_sp->n_un.n_name, name);
360 	rs->rtc_sp->n_type = N_COMM;
361 	if ((rs->rtc_sp->n_value = (long)calloc(rs->rtc_sp->n_value, 1)) == 0)
362 		return (0);
363 	return (rs->rtc_sp);
364 }
365 
366 /*
367  * Find a.out format symbol in the specified link map.  Unlike the sister
368  * elf routine we re-calculate the symbols hash value for each link map
369  * we're looking at.
370  */
371 static struct nlist *
372 aout_findsb(const char *aname, Rt_map *lmp, int flag)
373 {
374 	const char	*name = aname;
375 	char		*cp;
376 	struct fshash	*p;
377 	int		i;
378 	struct nlist	*sp;
379 	ulong_t		hval = 0;
380 
381 #define	HASHMASK	0x7fffffff
382 #define	RTHS		126
383 
384 	/*
385 	 * The name passed to us is in ELF format, thus it is necessary to
386 	 * map this back to the A_OUT format to compute the hash value (see
387 	 * mapping rules in aout_lookup_sym()).  Basically the symbols are
388 	 * mapped according to whether a leading `.' exists.
389 	 *
390 	 *	elf symbol		a.out symbol
391 	 * i.	   .bar		->	   .bar		(LKUP_LDOT)
392 	 * ii.	   .nuts	->	    nuts
393 	 * iii.	    foo		->	   _foo
394 	 */
395 	if (*name == '.') {
396 		if (!(flag & LKUP_LDOT))
397 			name++;
398 	} else
399 		hval = '_';
400 
401 	while (*name)
402 		hval = (hval << 1) + *name++;
403 	hval = hval & HASHMASK;
404 
405 	i = hval % (AOUTDYN(lmp)->v2->ld_buckets == 0 ? RTHS :
406 		AOUTDYN(lmp)->v2->ld_buckets);
407 	p = LM2LP(lmp)->lp_hash + i;
408 
409 	if (p->fssymbno != -1)
410 		do {
411 			sp = &LM2LP(lmp)->lp_symtab[p->fssymbno];
412 			cp = &LM2LP(lmp)->lp_symstr[sp->n_un.n_strx];
413 			name = aname;
414 			if (*name == '.') {
415 				if (!(flag & LKUP_LDOT))
416 					name++;
417 			} else {
418 				cp++;
419 			}
420 			while (*name == *cp++) {
421 				if (*name++ == '\0')
422 					return (sp);	/* found */
423 			}
424 			if (p->next == 0)
425 				return (0);		/* not found */
426 			else
427 				continue;
428 		} while ((p = &LM2LP(lmp)->lp_hash[p->next]) != 0);
429 	return (0);
430 }
431 
432 /*
433  * The symbol name we have been asked to look up is in A_OUT format, this
434  * symbol is mapped to the appropriate ELF format which is the standard by
435  * which symbols are passed around ld.so.1.  The symbols are mapped
436  * according to whether a leading `_' or `.' exists.
437  *
438  *	a.out symbol		elf symbol
439  * i.	   _foo		->	    foo
440  * ii.	   .bar		->	   .bar		(LKUP_LDOT)
441  * iii.	    nuts	->	   .nuts
442  */
443 Sym *
444 aout_lookup_sym(Slookup *slp, Rt_map **dlmp, uint_t *binfo)
445 {
446 	char	name[PATH_MAX];
447 	Slookup	sl = *slp;
448 
449 	DBG_CALL(Dbg_syms_lookup_aout(LIST(slp->sl_imap), slp->sl_name));
450 
451 	if (*sl.sl_name == '_')
452 		++sl.sl_name;
453 	else if (*sl.sl_name == '.')
454 		sl.sl_flags |= LKUP_LDOT;
455 	else {
456 		name[0] = '.';
457 		(void) strcpy(&name[1], sl.sl_name);
458 		sl.sl_name = name;
459 	}
460 
461 	/*
462 	 * Call the generic lookup routine to cycle through the specified
463 	 * link maps.
464 	 */
465 	return (lookup_sym(&sl, dlmp, binfo));
466 }
467 
468 /*
469  * Symbol lookup for an a.out format module.
470  */
471 static Sym *
472 aout_find_sym(Slookup *slp, Rt_map **dlmp, uint_t *binfo)
473 {
474 	const char	*name = slp->sl_name;
475 	Rt_map		*ilmp = slp->sl_imap;
476 	struct nlist	*sp;
477 
478 	DBG_CALL(Dbg_syms_lookup(ilmp, name, MSG_ORIG(MSG_STR_AOUT)));
479 
480 	if (sp = aout_findsb(name, ilmp, slp->sl_flags)) {
481 		if (sp->n_value != 0) {
482 			/*
483 			 * is it a common?
484 			 */
485 			if (sp->n_type == (N_EXT + N_UNDF)) {
486 				if ((sp = aout_find_com(sp, name)) == 0)
487 					return ((Sym *)0);
488 			}
489 			*dlmp = ilmp;
490 			*binfo |= DBG_BINFO_FOUND;
491 			return (aout_symconvert(sp));
492 		}
493 	}
494 	return ((Sym *)0);
495 }
496 
497 /*
498  * Map in an a.out format object.
499  * Takes an open file descriptor for the object to map and
500  * its pathname; returns a pointer to a Rt_map structure
501  * for this object, or 0 on error.
502  */
503 static Rt_map *
504 aout_map_so(Lm_list *lml, Aliste lmco, const char *pname, const char *oname,
505     int fd)
506 {
507 	struct exec	*exec;		/* working area for object headers */
508 	caddr_t		addr;		/* mmap result temporary */
509 	struct link_dynamic *ld;	/* dynamic pointer of object mapped */
510 	size_t		size;		/* size of object */
511 	Rt_map		*lmp;		/* link map created */
512 	int		err;
513 	struct nlist	*nl;
514 
515 	/*
516 	 * Map text and allocate enough address space to fit the whole
517 	 * library.  Note that we map enough to catch the first symbol
518 	 * in the symbol table and thereby avoid an "lseek" & "read"
519 	 * pair to pick it up.
520 	 */
521 	/* LINTED */
522 	exec = (struct exec *)fmap->fm_maddr;
523 	size = max(SIZE(*exec), N_SYMOFF(*exec) + sizeof (struct nlist));
524 	if ((addr = mmap(0, size, (PROT_READ | PROT_EXEC), MAP_PRIVATE,
525 	    fd, 0)) == MAP_FAILED) {
526 		err = errno;
527 		eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_MMAP), pname,
528 		    strerror(err));
529 		return (0);
530 	}
531 
532 	/*
533 	 * Grab the first symbol entry while we've got it mapped aligned
534 	 * to file addresses.  We assume that this symbol describes the
535 	 * object's link_dynamic.
536 	 */
537 	/* LINTED */
538 	nl = (struct nlist *)&addr[N_SYMOFF(*exec)];
539 	/* LINTED */
540 	ld = (struct link_dynamic *)&addr[nl->n_value];
541 
542 	/*
543 	 * Map the initialized data portion of the file to the correct
544 	 * point in the range of allocated addresses.  This will leave
545 	 * some portion of the data segment "doubly mapped" on machines
546 	 * where the text/data relocation alignment is not on a page
547 	 * boundaries.  However, leaving the file mapped has the double
548 	 * advantage of both saving the munmap system call and of leaving
549 	 * us a contiguous chunk of address space devoted to the object --
550 	 * in case we need to unmap it all later.
551 	 */
552 	if (mmap((caddr_t)(addr + M_SROUND(exec->a_text)),
553 	    (int)exec->a_data, (PROT_READ | PROT_WRITE | PROT_EXEC),
554 	    (MAP_FIXED | MAP_PRIVATE), fd, (off_t)exec->a_text) == MAP_FAILED) {
555 		err = errno;
556 		eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_MMAP), pname,
557 		    strerror(err));
558 		return (0);
559 	}
560 
561 	/*
562 	 * Allocate pages for the object's bss, if necessary.
563 	 */
564 	if (exec->a_bss != 0) {
565 		if (dz_map(lml, addr + M_SROUND(exec->a_text) + exec->a_data,
566 		    (int)exec->a_bss, PROT_READ | PROT_WRITE | PROT_EXEC,
567 		    MAP_FIXED | MAP_PRIVATE) == MAP_FAILED)
568 			goto error;
569 	}
570 
571 	/*
572 	 * Create link map structure for newly mapped shared object.
573 	 */
574 	ld->v2 = (struct link_dynamic_2 *)((int)ld->v2 + (int)addr);
575 	if (!(lmp = aout_new_lm(lml, pname, oname, ld, addr, size, lmco)))
576 		goto error;
577 
578 	return (lmp);
579 
580 	/*
581 	 * Error returns: close off file and free address space.
582 	 */
583 error:
584 	(void) munmap((caddr_t)addr, size);
585 	return (0);
586 }
587 
588 /*
589  * Create a new Rt_map structure for an a.out format object and
590  * initializes all values.
591  */
592 Rt_map *
593 aout_new_lm(Lm_list *lml, const char *pname, const char *oname,
594     struct link_dynamic *ld, caddr_t addr, size_t size, Aliste lmco)
595 {
596 	Rt_map	*lmp;
597 	caddr_t offset;
598 
599 	DBG_CALL(Dbg_file_aout(lml, pname, (ulong_t)ld, (ulong_t)addr,
600 	    (ulong_t)size, lml->lm_lmidstr, lmco));
601 
602 	/*
603 	 * Allocate space for the link-map and private a.out information.  Once
604 	 * these are allocated and initialized, we can use remove_so(0, lmp) to
605 	 * tear down the link-map should any failures occur.
606 	 */
607 	if ((lmp = calloc(sizeof (Rt_map), 1)) == 0)
608 		return (0);
609 	if ((AOUTPRV(lmp) = calloc(sizeof (Rt_aoutp), 1)) == 0) {
610 		free(lmp);
611 		return (0);
612 	}
613 	if ((((Rt_aoutp *)AOUTPRV(lmp))->lm_lpd =
614 	    calloc(sizeof (struct ld_private), 1)) == 0) {
615 		free(AOUTPRV(lmp));
616 		free(lmp);
617 		return (0);
618 	}
619 
620 	/*
621 	 * All fields not filled in were set to 0 by calloc.
622 	 */
623 	ORIGNAME(lmp) = PATHNAME(lmp) = NAME(lmp) = (char *)pname;
624 	ADDR(lmp) = (ulong_t)addr;
625 	MSIZE(lmp) = (ulong_t)size;
626 	SYMINTP(lmp) = aout_find_sym;
627 	FCT(lmp) = &aout_fct;
628 	LIST(lmp) = lml;
629 	THREADID(lmp) = rt_thr_self();
630 	OBJFLTRNDX(lmp) = FLTR_DISABLED;
631 	SORTVAL(lmp) = -1;
632 
633 	/*
634 	 * Specific settings for a.out format.
635 	 */
636 	if (lml->lm_head == 0) {
637 		offset = (caddr_t)MAIN_BASE;
638 		FLAGS(lmp) |= FLG_RT_FIXED;
639 	} else
640 		offset = addr;
641 
642 	ETEXT(lmp) = (ulong_t)&offset[ld->v2->ld_text];
643 
644 	/*
645 	 * Create a mapping descriptor to describe the whole object as a single
646 	 * mapping.
647 	 */
648 	if ((MMAPS(lmp) = calloc(2, sizeof (Mmap))) == 0)
649 		return (0);
650 	MMAPS(lmp)->m_vaddr = offset;
651 	/* LINTED */
652 	MMAPS(lmp)->m_msize = max(SIZE(*(struct exec *)offset),
653 	    N_SYMOFF((*(struct exec *)offset)) + sizeof (struct nlist));
654 	MMAPS(lmp)->m_fsize = MMAPS(lmp)->m_msize;
655 	MMAPCNT(lmp) = 1;
656 
657 	/*
658 	 * Fill in all AOUT information.
659 	 */
660 	AOUTDYN(lmp) = ld;
661 	if ((RPATH(lmp) = (char *)&offset[ld->v2->ld_rules]) == offset)
662 		RPATH(lmp) = 0;
663 	LM2LP(lmp)->lp_symbol_base = addr;
664 	/* LINTED */
665 	LM2LP(lmp)->lp_plt = (struct jbind *)(&addr[JMPOFF(ld)]);
666 	LM2LP(lmp)->lp_rp =
667 	/* LINTED */
668 	    (struct relocation_info *)(&offset[RELOCOFF(ld)]);
669 	/* LINTED */
670 	LM2LP(lmp)->lp_hash = (struct fshash *)(&offset[HASHOFF(ld)]);
671 	/* LINTED */
672 	LM2LP(lmp)->lp_symtab = (struct nlist *)(&offset[SYMOFF(ld)]);
673 	LM2LP(lmp)->lp_symstr = &offset[STROFF(ld)];
674 	LM2LP(lmp)->lp_textbase = offset;
675 	LM2LP(lmp)->lp_refcnt++;
676 	LM2LP(lmp)->lp_dlp = NULL;
677 
678 	if (rtld_flags & RT_FL_RELATIVE)
679 		FLAGS1(lmp) |= FL1_RT_RELATIVE;
680 
681 	if ((CONDVAR(lmp) = rt_cond_create()) == 0) {
682 		remove_so(0, lmp);
683 		return (0);
684 	}
685 	if (oname && ((append_alias((lmp), oname, 0)) == 0)) {
686 		remove_so(0, lmp);
687 		return (0);
688 	}
689 
690 	/*
691 	 * Add the mapped object to the end of the link map list.
692 	 */
693 	lm_append(lml, lmco, lmp);
694 	return (lmp);
695 }
696 
697 /*
698  * Function to correct protection settings.
699  * Segments are all mapped initially with permissions as given in
700  * the segment header, but we need to turn on write permissions
701  * on a text segment if there are any relocations against that segment,
702  * and them turn write permission back off again before returning control
703  * to the program.  This function turns the permission on or off depending
704  * on the value of the argument.
705  */
706 int
707 aout_set_prot(Rt_map *lmp, int permission)
708 {
709 	int		prot;		/* protection setting */
710 	caddr_t		et;		/* cached _etext of object */
711 	size_t		size;		/* size of text segment */
712 
713 	DBG_CALL(Dbg_file_prot(lmp, permission));
714 
715 	et = (caddr_t)ETEXT(lmp);
716 	size = M_PROUND((ulong_t)(et - TEXTBASE(lmp)));
717 	prot = PROT_READ | PROT_EXEC | permission;
718 	if (mprotect((caddr_t)TEXTBASE(lmp), size, prot) == -1) {
719 		int	err = errno;
720 
721 		eprintf(LIST(lmp), ERR_FATAL, MSG_INTL(MSG_SYS_MPROT),
722 		    NAME(lmp), strerror(err));
723 		return (0);
724 	}
725 	return (1);
726 }
727 
728 /*
729  * Build full pathname of shared object from the given directory name and
730  * filename.
731  */
732 static char *
733 aout_get_so(const char *dir, const char *file)
734 {
735 	struct db	*dbp;
736 	char		*path = NULL;
737 
738 	if (dbp = lo_cache(dir)) {
739 		path = ask_db(dbp, file);
740 	}
741 	return (path);
742 }
743 
744 /*
745  * Determine the symbol location of an address within a link-map.  Look for
746  * the nearest symbol (whoes value is less than or equal to the required
747  * address).  This is the object specific part of dladdr().
748  */
749 static void
750 aout_dladdr(ulong_t addr, Rt_map *lmp, Dl_info *dlip, void **info,
751     int flags)
752 {
753 	ulong_t		ndx, cnt, base, _value;
754 	struct nlist	*sym, *_sym;
755 
756 	cnt = ((int)LM2LP(lmp)->lp_symstr - (int)LM2LP(lmp)->lp_symtab) /
757 		sizeof (struct nlist);
758 	sym = LM2LP(lmp)->lp_symtab;
759 
760 	if (FLAGS(lmp) & FLG_RT_FIXED)
761 		base = 0;
762 	else
763 		base = ADDR(lmp);
764 
765 	for (_sym = 0, _value = 0, ndx = 0; ndx < cnt; ndx++, sym++) {
766 		ulong_t	value;
767 
768 		if (sym->n_type == (N_EXT + N_UNDF))
769 			continue;
770 
771 		value = sym->n_value + base;
772 		if (value > addr)
773 			continue;
774 		if (value < _value)
775 			continue;
776 
777 		_sym = sym;
778 		_value = value;
779 
780 		if (value == addr)
781 			break;
782 	}
783 
784 	if (_sym) {
785 		int	_flags = flags & RTLD_DL_MASK;
786 
787 		/*
788 		 * The only way we can create a symbol entry is to use
789 		 * aout_symconvert(), however this results in us pointing to
790 		 * static data that could be overridden.  In addition the AOUT
791 		 * symbol format doesn't give us everything an ELF symbol does.
792 		 * So, unless we get convinced otherwise, don't bother returning
793 		 * a symbol entry for AOUT's.
794 		 */
795 		if (_flags == RTLD_DL_SYMENT)
796 			*info = 0;
797 		else if (_flags == RTLD_DL_LINKMAP)
798 			*info = (void *)lmp;
799 
800 		dlip->dli_sname = &LM2LP(lmp)->lp_symstr[_sym->n_un.n_strx];
801 		dlip->dli_saddr = (void *)_value;
802 	}
803 }
804 
805 /*
806  * Continue processing a dlsym request.  Lookup the required symbol in each
807  * link-map specified by the handle.  Note, that because this lookup is against
808  * individual link-maps we don't need to supply a starting link-map to the
809  * lookup routine (see lookup_sym():analyze.c).
810  */
811 Sym *
812 aout_dlsym_handle(Grp_hdl * ghp, Slookup *slp, Rt_map **_lmp, uint_t *binfo)
813 {
814 	Sym	*sym;
815 	char	buffer[PATH_MAX];
816 	Slookup	sl;
817 
818 	buffer[0] = '_';
819 	(void) strcpy(&buffer[1], slp->sl_name);
820 
821 	if ((sym = dlsym_handle(ghp, slp, _lmp, binfo)) != 0)
822 		return (sym);
823 
824 	/*
825 	 * Symbol not found as supplied.  However, most of our symbols will
826 	 * be in the "C" name space, where the implementation prepends a "_"
827 	 * to the symbol as it emits it.  Therefore, attempt to find the
828 	 * symbol with the "_" prepend.
829 	 */
830 	sl = *slp;
831 	sl.sl_name = (const char *)buffer;
832 
833 	return (dlsym_handle(ghp, &sl, _lmp, binfo));
834 }
835