xref: /titanic_51/usr/src/cmd/sgs/rtld/common/a.out.c (revision 147982cb800a90a2ac06d00d9a79ac50b0ca4ddb)
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 2008 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 		DBG_CALL(Dbg_file_fixname(LIST(clmp), pnp->p_name, name));
143 		return (pnp);
144 	}
145 	free(pnp);
146 	return (0);
147 }
148 
149 /*
150  * Determine if we have been given an A_OUT file.  Returns 1 if true.
151  */
152 static int
153 aout_are_u()
154 {
155 	struct exec *exec;
156 
157 	/* LINTED */
158 	exec = (struct exec *)fmap->fm_maddr;
159 	if (fmap->fm_fsize < sizeof (exec) || (exec->a_machtype != M_SPARC) ||
160 	    (N_BADMAG(*exec))) {
161 		return (0);
162 	}
163 	return (1);
164 }
165 
166 /*
167  * Return the entry point the A_OUT executable. This is always zero.
168  */
169 static ulong_t
170 aout_entry_pt()
171 {
172 	return (0);
173 }
174 
175 /*
176  * Unmap a given A_OUT shared object from the address space.
177  */
178 static void
179 aout_unmap_so(Rt_map *lmp)
180 {
181 	Mmap	*immap = MMAPS(lmp);
182 
183 	(void) munmap(immap->m_vaddr, immap->m_msize);
184 }
185 
186 /*
187  * Dummy versioning interface - real functionality is only applicable to elf.
188  */
189 static int
190 aout_verify_vers()
191 {
192 	return (1);
193 }
194 
195 /*
196  * Search through the dynamic section for DT_NEEDED entries and perform one
197  * of two functions.  If only the first argument is specified then load the
198  * defined shared object, otherwise add the link map representing the
199  * defined link map the the dlopen list.
200  */
201 static int
202 aout_needed(Lm_list *lml, Aliste lmco, Rt_map *clmp, int *in_nfavl)
203 {
204 	void	*need;
205 
206 	for (need = &TEXTBASE(clmp)[AOUTDYN(clmp)->v2->ld_need];
207 	    need != &TEXTBASE(clmp)[0];
208 	    need = &TEXTBASE(clmp)[((Lnk_obj *)(need))->lo_next]) {
209 		Rt_map	*nlmp;
210 		char	*name;
211 		Pnode	*pnp;
212 
213 		name = &TEXTBASE(clmp)[((Lnk_obj *)(need))->lo_name];
214 
215 		if (((Lnk_obj *)(need))->lo_library) {
216 			/*
217 			 * If lo_library field is not NULL then this needed
218 			 * library was linked in using the "-l" option.
219 			 * Thus we need to rebuild the library name before
220 			 * trying to load it.
221 			 */
222 			Pnode	*dir, *dirlist = (Pnode *)0;
223 			char	*file;
224 			size_t	len;
225 
226 			/*
227 			 * Allocate name length plus 20 for full library name.
228 			 * lib.so.. = 7 + (2 * short) + NULL = 7 + 12 + 1 = 20
229 			 */
230 			len = strlen(name) + 20;
231 			if ((file = malloc(len)) == 0)
232 				return (0);
233 			(void) snprintf(file, len, MSG_ORIG(MSG_FMT_4XLIB),
234 			    name, ((Lnk_obj *)(need))->lo_major,
235 			    ((Lnk_obj *)(need))->lo_minor);
236 
237 			DBG_CALL(Dbg_libs_find(lml, file));
238 
239 			/*
240 			 * We need to determine what filename will match the
241 			 * the filename specified (ie, a libc.so.1.2 may match
242 			 * to a libc.so.1.3).  It's the real pathname that is
243 			 * recorded in the link maps.  If we are presently
244 			 * being traced, skip this pathname generation so
245 			 * that we fall through into load_so() to print the
246 			 * appropriate diagnostics.  I don't like this at all.
247 			 */
248 			if (lml->lm_flags & LML_FLG_TRC_ENABLE)
249 				name = file;
250 			else {
251 				char	*path = (char *)0;
252 
253 				for (dir = get_next_dir(&dirlist, clmp, 0); dir;
254 				    dir = get_next_dir(&dirlist, clmp, 0)) {
255 					if (dir->p_name == 0)
256 						continue;
257 
258 					if (path =
259 					    aout_get_so(dir->p_name, file))
260 						break;
261 				}
262 				if (!path) {
263 					eprintf(lml, ERR_FATAL,
264 					    MSG_INTL(MSG_SYS_OPEN), file,
265 					    strerror(ENOENT));
266 					return (0);
267 				}
268 				name = path;
269 			}
270 			if ((pnp = expand_paths(clmp, name, 0, 0)) == 0)
271 				return (0);
272 		} else {
273 			/*
274 			 * If the library is specified as a pathname, see if
275 			 * it must be fixed to specify the current working
276 			 * directory (ie. libc.so.1.2 -> ./libc.so.1.2).
277 			 */
278 			if ((pnp = aout_fix_name(name, clmp)) == 0)
279 				return (0);
280 		}
281 
282 		DBG_CALL(Dbg_file_needed(clmp, name));
283 
284 		nlmp = load_one(lml, lmco, pnp, clmp, MODE(clmp), 0, 0,
285 		    in_nfavl);
286 		remove_pnode(pnp);
287 		if (((nlmp == 0) || (bind_one(clmp, nlmp, BND_NEEDED) == 0)) &&
288 		    ((lml->lm_flags & LML_FLG_TRC_ENABLE) == 0))
289 			return (0);
290 	}
291 
292 	return (1);
293 }
294 
295 static Sym *
296 aout_symconvert(struct nlist *sp)
297 {
298 	static Sym	sym;
299 
300 	sym.st_value = sp->n_value;
301 	sym.st_size = 0;
302 	sym.st_info = 0;
303 	sym.st_other = 0;
304 	switch (sp->n_type) {
305 		case N_EXT + N_ABS:
306 			sym.st_shndx = SHN_ABS;
307 			break;
308 		case N_COMM:
309 			sym.st_shndx = SHN_COMMON;
310 			break;
311 		case N_EXT + N_UNDF:
312 			sym.st_shndx = SHN_UNDEF;
313 			break;
314 		default:
315 			sym.st_shndx = 0;
316 			break;
317 	}
318 	return (&sym);
319 }
320 
321 /*
322  * Process a.out format commons.
323  */
324 static struct nlist *
325 aout_find_com(struct nlist *sp, const char *name)
326 {
327 	static struct rtc_symb	*rtcp = 0;
328 	struct rtc_symb		*rs, * trs;
329 	const char		*sl;
330 	char			*cp;
331 
332 	/*
333 	 * See if common is already allocated.
334 	 */
335 	trs = rtcp;
336 	while (trs) {
337 		sl = name;
338 		cp = trs->rtc_sp->n_un.n_name;
339 		while (*sl == *cp++)
340 			if (*sl++ == '\0')
341 				return (trs->rtc_sp);
342 		trs = trs->rtc_next;
343 	}
344 
345 	/*
346 	 * If we got here, common is not already allocated so allocate it.
347 	 */
348 	if ((rs = malloc(sizeof (struct rtc_symb))) == 0)
349 		return (0);
350 	if ((rs->rtc_sp = malloc(sizeof (struct nlist))) == 0)
351 		return (0);
352 	trs = rtcp;
353 	rtcp = rs;
354 	rs->rtc_next = trs;
355 	*(rs->rtc_sp) = *sp;
356 	if ((rs->rtc_sp->n_un.n_name = malloc(strlen(name) + 1)) == 0)
357 		return (0);
358 	(void) strcpy(rs->rtc_sp->n_un.n_name, name);
359 	rs->rtc_sp->n_type = N_COMM;
360 	if ((rs->rtc_sp->n_value = (long)calloc(rs->rtc_sp->n_value, 1)) == 0)
361 		return (0);
362 	return (rs->rtc_sp);
363 }
364 
365 /*
366  * Find a.out format symbol in the specified link map.  Unlike the sister
367  * elf routine we re-calculate the symbols hash value for each link map
368  * we're looking at.
369  */
370 static struct nlist *
371 aout_findsb(const char *aname, Rt_map *lmp, int flag)
372 {
373 	const char	*name = aname;
374 	char		*cp;
375 	struct fshash	*p;
376 	int		i;
377 	struct nlist	*sp;
378 	ulong_t		hval = 0;
379 
380 #define	HASHMASK	0x7fffffff
381 #define	RTHS		126
382 
383 	/*
384 	 * The name passed to us is in ELF format, thus it is necessary to
385 	 * map this back to the A_OUT format to compute the hash value (see
386 	 * mapping rules in aout_lookup_sym()).  Basically the symbols are
387 	 * mapped according to whether a leading `.' exists.
388 	 *
389 	 *	elf symbol		a.out symbol
390 	 * i.	   .bar		->	   .bar		(LKUP_LDOT)
391 	 * ii.	   .nuts	->	    nuts
392 	 * iii.	    foo		->	   _foo
393 	 */
394 	if (*name == '.') {
395 		if (!(flag & LKUP_LDOT))
396 			name++;
397 	} else
398 		hval = '_';
399 
400 	while (*name)
401 		hval = (hval << 1) + *name++;
402 	hval = hval & HASHMASK;
403 
404 	i = hval % (AOUTDYN(lmp)->v2->ld_buckets == 0 ? RTHS :
405 	    AOUTDYN(lmp)->v2->ld_buckets);
406 	p = LM2LP(lmp)->lp_hash + i;
407 
408 	if (p->fssymbno != -1)
409 		do {
410 			sp = &LM2LP(lmp)->lp_symtab[p->fssymbno];
411 			cp = &LM2LP(lmp)->lp_symstr[sp->n_un.n_strx];
412 			name = aname;
413 			if (*name == '.') {
414 				if (!(flag & LKUP_LDOT))
415 					name++;
416 			} else {
417 				cp++;
418 			}
419 			while (*name == *cp++) {
420 				if (*name++ == '\0')
421 					return (sp);	/* found */
422 			}
423 			if (p->next == 0)
424 				return (0);		/* not found */
425 			else
426 				continue;
427 		} while ((p = &LM2LP(lmp)->lp_hash[p->next]) != 0);
428 	return (0);
429 }
430 
431 /*
432  * The symbol name we have been asked to look up is in A_OUT format, this
433  * symbol is mapped to the appropriate ELF format which is the standard by
434  * which symbols are passed around ld.so.1.  The symbols are mapped
435  * according to whether a leading `_' or `.' exists.
436  *
437  *	a.out symbol		elf symbol
438  * i.	   _foo		->	    foo
439  * ii.	   .bar		->	   .bar		(LKUP_LDOT)
440  * iii.	    nuts	->	   .nuts
441  */
442 Sym *
443 aout_lookup_sym(Slookup *slp, Rt_map **dlmp, uint_t *binfo, int *in_nfavl)
444 {
445 	char	name[PATH_MAX];
446 	Slookup	sl = *slp;
447 
448 	DBG_CALL(Dbg_syms_lookup_aout(LIST(slp->sl_imap), slp->sl_name));
449 
450 	if (*sl.sl_name == '_')
451 		++sl.sl_name;
452 	else if (*sl.sl_name == '.')
453 		sl.sl_flags |= LKUP_LDOT;
454 	else {
455 		name[0] = '.';
456 		(void) strcpy(&name[1], sl.sl_name);
457 		sl.sl_name = name;
458 	}
459 
460 	/*
461 	 * Call the generic lookup routine to cycle through the specified
462 	 * link maps.
463 	 */
464 	return (lookup_sym(&sl, dlmp, binfo, in_nfavl));
465 }
466 
467 /*
468  * Symbol lookup for an a.out format module.
469  */
470 /* ARGSUSED3 */
471 static Sym *
472 aout_find_sym(Slookup *slp, Rt_map **dlmp, uint_t *binfo, int *in_nfavl)
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     int *in_nfavl)
814 {
815 	Sym	*sym;
816 	char	buffer[PATH_MAX];
817 	Slookup	sl;
818 
819 	buffer[0] = '_';
820 	(void) strcpy(&buffer[1], slp->sl_name);
821 
822 	if ((sym = dlsym_handle(ghp, slp, _lmp, binfo, in_nfavl)) != 0)
823 		return (sym);
824 
825 	/*
826 	 * Symbol not found as supplied.  However, most of our symbols will
827 	 * be in the "C" name space, where the implementation prepends a "_"
828 	 * to the symbol as it emits it.  Therefore, attempt to find the
829 	 * symbol with the "_" prepend.
830 	 */
831 	sl = *slp;
832 	sl.sl_name = (const char *)buffer;
833 
834 	return (dlsym_handle(ghp, &sl, _lmp, binfo, in_nfavl));
835 }
836