xref: /openbsd-src/libexec/ld.so/resolve.c (revision 210cc31ee7e6dd0fb4a22aeade973d93c561e538)
1*210cc31eSderaadt /*	$OpenBSD: resolve.c,v 1.102 2024/01/22 02:08:31 deraadt Exp $ */
24d11faf9Srahnds 
34d11faf9Srahnds /*
44d11faf9Srahnds  * Copyright (c) 1998 Per Fogelstrom, Opsycon AB
54d11faf9Srahnds  *
64d11faf9Srahnds  * Redistribution and use in source and binary forms, with or without
74d11faf9Srahnds  * modification, are permitted provided that the following conditions
84d11faf9Srahnds  * are met:
94d11faf9Srahnds  * 1. Redistributions of source code must retain the above copyright
104d11faf9Srahnds  *    notice, this list of conditions and the following disclaimer.
114d11faf9Srahnds  * 2. Redistributions in binary form must reproduce the above copyright
124d11faf9Srahnds  *    notice, this list of conditions and the following disclaimer in the
134d11faf9Srahnds  *    documentation and/or other materials provided with the distribution.
144d11faf9Srahnds  *
154d11faf9Srahnds  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
164d11faf9Srahnds  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
174d11faf9Srahnds  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
184d11faf9Srahnds  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
194d11faf9Srahnds  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
204d11faf9Srahnds  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
214d11faf9Srahnds  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
224d11faf9Srahnds  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
234d11faf9Srahnds  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
244d11faf9Srahnds  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
254d11faf9Srahnds  * SUCH DAMAGE.
264d11faf9Srahnds  *
274d11faf9Srahnds  */
284d11faf9Srahnds 
294d11faf9Srahnds #define _DYN_LOADER
304d11faf9Srahnds 
314d11faf9Srahnds #include <sys/types.h>
324a066defSderaadt #include <sys/mman.h>
334a066defSderaadt #include <sys/syscall.h>
344d11faf9Srahnds 
35337bd349Skurt #include <limits.h>
364d11faf9Srahnds #include <link.h>
37b722ba42Sguenther 
38b722ba42Sguenther #include "util.h"
39c8dfd7a0Skurt #include "path.h"
404be7d39eSrahnds #include "resolve.h"
414a066defSderaadt #include "syscall.h"
424d11faf9Srahnds 
43337bd349Skurt /* substitution types */
44337bd349Skurt typedef enum {
45337bd349Skurt 	SUBST_UNKNOWN, SUBST_ORIGIN, SUBST_OSNAME, SUBST_OSREL, SUBST_PLATFORM
46337bd349Skurt } SUBST_TYPES;
47337bd349Skurt 
48b5a21baaSguenther struct symlookup {
49b5a21baaSguenther 	const char		*sl_name;
50143e5accSguenther 	struct sym_res		sl_out;
51143e5accSguenther 	struct sym_res		sl_weak_out;
52b5a21baaSguenther 	unsigned long		sl_elf_hash;
53ac51d06cSguenther 	uint32_t		sl_gnu_hash;
54b5a21baaSguenther 	int			sl_flags;
55b5a21baaSguenther };
56b5a21baaSguenther 
574d11faf9Srahnds elf_object_t *_dl_objects;
58bae526eeSguenther int object_count;
59bae526eeSguenther static elf_object_t *_dl_last_object;
600acae5e5Sdrahn elf_object_t *_dl_loading_object;
614d11faf9Srahnds 
6270be5820Sdrahn void
_dl_handle_nodelete(elf_object_t * object)63296fbf9fSsemarie _dl_handle_nodelete(elf_object_t *object)
6470be5820Sdrahn {
652f744062Sguenther 	/*
662f744062Sguenther 	 * If a .so is marked nodelete, then the entire load group that it's
672f744062Sguenther 	 * in needs to be kept around forever, so add a reference there.
682f744062Sguenther 	 * XXX It would be better if we tracked inter-object dependencies
692f744062Sguenther 	 * from relocations and didn't leave dangling pointers when a load
702f744062Sguenther 	 * group was partially unloaded.  That would render this unnecessary.
712f744062Sguenther 	 */
720fdecfd0Sguenther 	if (object->obj_flags & DF_1_NODELETE &&
732f744062Sguenther 	    (object->load_object->status & STAT_NODELETE) == 0) {
740fdecfd0Sguenther 		DL_DEB(("objname %s is nodelete\n", object->load_name));
752f744062Sguenther 		object->load_object->opencount++;
762f744062Sguenther 		object->load_object->status |= STAT_NODELETE;
770fdecfd0Sguenther 	}
78296fbf9fSsemarie }
79296fbf9fSsemarie 
80296fbf9fSsemarie /*
81296fbf9fSsemarie  * Add a new dynamic object to the object list.
82296fbf9fSsemarie  */
83296fbf9fSsemarie void
_dl_add_object(elf_object_t * object)84296fbf9fSsemarie _dl_add_object(elf_object_t *object)
85296fbf9fSsemarie {
86296fbf9fSsemarie 	_dl_handle_nodelete(object);
8770be5820Sdrahn 
8870be5820Sdrahn 	/*
8970be5820Sdrahn 	 * if this is a new object, prev will be NULL
9070be5820Sdrahn 	 * != NULL if an object already in the list
9170be5820Sdrahn 	 * prev == NULL for the first item in the list, but that will
9270be5820Sdrahn 	 * be the executable.
9370be5820Sdrahn 	 */
9470be5820Sdrahn 	if (object->prev != NULL)
9570be5820Sdrahn 		return;
9670be5820Sdrahn 
9770be5820Sdrahn 	if (_dl_objects == NULL) {			/* First object ? */
9870be5820Sdrahn 		_dl_last_object = _dl_objects = object;
99bae526eeSguenther 		object_count = 2;			/* count ld.so early */
10070be5820Sdrahn 	} else {
10170be5820Sdrahn 		_dl_last_object->next = object;
10270be5820Sdrahn 		object->prev = _dl_last_object;
10370be5820Sdrahn 		_dl_last_object = object;
104bae526eeSguenther 		if (object->obj_type != OBJTYPE_LDR)	/* see above */
105bae526eeSguenther 			object_count++;
10670be5820Sdrahn 	}
10770be5820Sdrahn }
10870be5820Sdrahn 
10970be5820Sdrahn /*
110337bd349Skurt  * Identify substitution sequence name.
111337bd349Skurt  */
112337bd349Skurt static int
_dl_subst_name(const char * name,size_t siz)113337bd349Skurt _dl_subst_name(const char *name, size_t siz) {
114337bd349Skurt 	switch (siz) {
115337bd349Skurt 	case 5:
116337bd349Skurt 		if (_dl_strncmp(name, "OSREL", 5) == 0)
117337bd349Skurt 			return SUBST_OSREL;
118337bd349Skurt 		break;
119337bd349Skurt 	case 6:
120337bd349Skurt 		if (_dl_strncmp(name, "ORIGIN", 6) == 0)
121337bd349Skurt 			return SUBST_ORIGIN;
122337bd349Skurt 		if (_dl_strncmp(name, "OSNAME", 6) == 0)
123337bd349Skurt 			return SUBST_OSNAME;
124337bd349Skurt 		break;
125337bd349Skurt 	case 8:
126337bd349Skurt 		if (_dl_strncmp(name, "PLATFORM", 8) == 0)
127337bd349Skurt 			return SUBST_PLATFORM;
128337bd349Skurt 		break;
129337bd349Skurt 	}
130337bd349Skurt 
131337bd349Skurt 	return (SUBST_UNKNOWN);
132337bd349Skurt }
133337bd349Skurt 
134337bd349Skurt /*
135337bd349Skurt  * Perform $ORIGIN substitutions on path
136337bd349Skurt  */
137337bd349Skurt static void
_dl_origin_subst_path(elf_object_t * object,const char * origin_path,char ** path)138337bd349Skurt _dl_origin_subst_path(elf_object_t *object, const char *origin_path,
139337bd349Skurt     char **path)
140337bd349Skurt {
141337bd349Skurt 	char tmp_path[PATH_MAX];
142337bd349Skurt 	char *new_path, *tp;
143337bd349Skurt 	const char *pp, *name, *value;
144337bd349Skurt 	static struct utsname uts;
145337bd349Skurt 	size_t value_len;
146337bd349Skurt 	int skip_brace;
147337bd349Skurt 
148337bd349Skurt 	if (uts.sysname[0] == '\0') {
149337bd349Skurt 		if (_dl_uname(&uts) != 0)
150337bd349Skurt 			return;
151337bd349Skurt 	}
152337bd349Skurt 
153337bd349Skurt 	tp = tmp_path;
154337bd349Skurt 	pp = *path;
155337bd349Skurt 
156337bd349Skurt 	while (*pp != '\0' && (tp - tmp_path) < sizeof(tmp_path)) {
157337bd349Skurt 
158337bd349Skurt 		/* copy over chars up to but not including $ */
159337bd349Skurt 		while (*pp != '\0' && *pp != '$' &&
160337bd349Skurt 		    (tp - tmp_path) < sizeof(tmp_path))
161337bd349Skurt 			*tp++ = *pp++;
162337bd349Skurt 
163337bd349Skurt 		/* substitution sequence detected */
164337bd349Skurt 		if (*pp == '$' && (tp - tmp_path) < sizeof(tmp_path)) {
165337bd349Skurt 			pp++;
166337bd349Skurt 
167337bd349Skurt 			if ((skip_brace = (*pp == '{')))
168337bd349Skurt 				pp++;
169337bd349Skurt 
170337bd349Skurt 			/* skip over name */
171337bd349Skurt 			name = pp;
1724207a9b6Sderaadt 			while (_dl_isalnum((unsigned char)*pp) || *pp == '_')
173337bd349Skurt 				pp++;
174337bd349Skurt 
175337bd349Skurt 			switch (_dl_subst_name(name, pp - name)) {
176337bd349Skurt 			case SUBST_ORIGIN:
177337bd349Skurt 				value = origin_path;
178337bd349Skurt 				break;
179337bd349Skurt 			case SUBST_OSNAME:
180337bd349Skurt 				value = uts.sysname;
181337bd349Skurt 				break;
182337bd349Skurt 			case SUBST_OSREL:
183337bd349Skurt 				value = uts.release;
184337bd349Skurt 				break;
185337bd349Skurt 			case SUBST_PLATFORM:
186337bd349Skurt 				value = uts.machine;
187337bd349Skurt 				break;
188337bd349Skurt 			default:
189337bd349Skurt 				value = "";
190337bd349Skurt 			}
191337bd349Skurt 
192337bd349Skurt 			value_len = _dl_strlen(value);
193337bd349Skurt 			if (value_len >= sizeof(tmp_path) - (tp - tmp_path))
194337bd349Skurt 				return;
195337bd349Skurt 
196337bd349Skurt 			_dl_bcopy(value, tp, value_len);
197337bd349Skurt 			tp += value_len;
198337bd349Skurt 
199337bd349Skurt 			if (skip_brace && *pp == '}')
200337bd349Skurt 				pp++;
201337bd349Skurt 		}
202337bd349Skurt 	}
203337bd349Skurt 
204337bd349Skurt 	/* no substitution made if result exceeds sizeof(tmp_path) */
205337bd349Skurt 	if (tp - tmp_path >= sizeof(tmp_path))
206337bd349Skurt 		return;
207337bd349Skurt 
208337bd349Skurt 	/* NULL terminate tmp_path */
209337bd349Skurt 	*tp = '\0';
210337bd349Skurt 
211337bd349Skurt 	if (_dl_strcmp(tmp_path, *path) == 0)
212337bd349Skurt 		return;
213337bd349Skurt 
214337bd349Skurt 	new_path = _dl_strdup(tmp_path);
215337bd349Skurt 	if (new_path == NULL)
216337bd349Skurt 		return;
217337bd349Skurt 
218337bd349Skurt 	DL_DEB(("orig_path %s\n", *path));
219337bd349Skurt 	DL_DEB(("new_path  %s\n", new_path));
220337bd349Skurt 
221337bd349Skurt 	_dl_free(*path);
222337bd349Skurt 	*path = new_path;
223337bd349Skurt }
224337bd349Skurt 
225337bd349Skurt /*
226337bd349Skurt  * Determine origin_path from object load_name. The origin_path argument
227337bd349Skurt  * must refer to a buffer capable of storing at least PATH_MAX characters.
228337bd349Skurt  * Returns 0 on success.
229337bd349Skurt  */
230337bd349Skurt static int
_dl_origin_path(elf_object_t * object,char * origin_path)231337bd349Skurt _dl_origin_path(elf_object_t *object, char *origin_path)
232337bd349Skurt {
233c51b9268Sgnezdo 	const char *dirname_path;
234337bd349Skurt 
235c51b9268Sgnezdo 	/* syscall in ld.so returns 0/-errno, where libc returns char* */
236c51b9268Sgnezdo 	if (_dl___realpath(object->load_name, origin_path) < 0)
237c51b9268Sgnezdo 		return -1;
238c51b9268Sgnezdo 
239c51b9268Sgnezdo 	dirname_path = _dl_dirname(origin_path);
240337bd349Skurt 	if (dirname_path == NULL)
241337bd349Skurt 		return -1;
242337bd349Skurt 
243c51b9268Sgnezdo 	_dl_strlcpy(origin_path, dirname_path, PATH_MAX);
244337bd349Skurt 
245337bd349Skurt 	return 0;
246337bd349Skurt }
247337bd349Skurt 
248337bd349Skurt /*
24982c4222eSguenther  * Perform $ORIGIN substitutions on runpath and rpath
250337bd349Skurt  */
251337bd349Skurt static void
_dl_origin_subst(elf_object_t * object)252337bd349Skurt _dl_origin_subst(elf_object_t *object)
253337bd349Skurt {
254337bd349Skurt 	char origin_path[PATH_MAX];
255337bd349Skurt 	char **pp;
256337bd349Skurt 
257337bd349Skurt 	if (_dl_origin_path(object, origin_path) != 0)
258337bd349Skurt 		return;
259337bd349Skurt 
26082c4222eSguenther 	/* perform path substitutions on each segment of runpath and rpath */
261439893b0Sguenther 	if (object->runpath != NULL) {
262439893b0Sguenther 		for (pp = object->runpath; *pp != NULL; pp++)
26382c4222eSguenther 			_dl_origin_subst_path(object, origin_path, pp);
26482c4222eSguenther 	}
265439893b0Sguenther 	if (object->rpath != NULL) {
266439893b0Sguenther 		for (pp = object->rpath; *pp != NULL; pp++)
267337bd349Skurt 			_dl_origin_subst_path(object, origin_path, pp);
268337bd349Skurt 	}
269337bd349Skurt }
270337bd349Skurt 
271337bd349Skurt /*
27270be5820Sdrahn  * Initialize a new dynamic object.
2734d11faf9Srahnds  */
2744d11faf9Srahnds elf_object_t *
_dl_finalize_object(const char * objname,Elf_Dyn * dynp,Elf_Phdr * phdrp,int phdrc,const int objtype,const long lbase,const long obase)2759f6c3316Skurt _dl_finalize_object(const char *objname, Elf_Dyn *dynp, Elf_Phdr *phdrp,
2769f6c3316Skurt     int phdrc, const int objtype, const long lbase, const long obase)
2774d11faf9Srahnds {
2784d11faf9Srahnds 	elf_object_t *object;
279ac51d06cSguenther 	Elf_Addr gnu_hash = 0;
28086fa57a2Skettenis 
281d198ddd1Sjasper 	DL_DEB(("objname [%s], dynp %p, objtype %x lbase %lx, obase %lx\n",
282d198ddd1Sjasper 	    objname, dynp, objtype, lbase, obase));
283d198ddd1Sjasper 
284c827e20bSotto 	object = _dl_calloc(1, sizeof(elf_object_t));
28567b06ea7Sotto 	if (object == NULL)
2863b50b772Sguenther 		_dl_oom();
28770be5820Sdrahn 	object->prev = object->next = NULL;
2884d11faf9Srahnds 
2894d11faf9Srahnds 	object->load_dyn = dynp;
2904d11faf9Srahnds 	while (dynp->d_tag != DT_NULL) {
291fb2271a5Sderaadt 		if (dynp->d_tag < DT_NUM)
2924d11faf9Srahnds 			object->Dyn.info[dynp->d_tag] = dynp->d_un.d_val;
293fb2271a5Sderaadt 		else if (dynp->d_tag >= DT_LOPROC &&
294cb964ca6Skettenis 		    dynp->d_tag < DT_LOPROC + DT_PROCNUM)
295fb2271a5Sderaadt 			object->Dyn.info[dynp->d_tag + DT_NUM - DT_LOPROC] =
296fb2271a5Sderaadt 			    dynp->d_un.d_val;
2974d11faf9Srahnds 		if (dynp->d_tag == DT_TEXTREL)
2984d11faf9Srahnds 			object->dyn.textrel = 1;
2994d11faf9Srahnds 		if (dynp->d_tag == DT_SYMBOLIC)
3004d11faf9Srahnds 			object->dyn.symbolic = 1;
3014d11faf9Srahnds 		if (dynp->d_tag == DT_BIND_NOW)
3020fdecfd0Sguenther 			object->obj_flags |= DF_1_NOW;
3030fdecfd0Sguenther 		if (dynp->d_tag == DT_FLAGS_1)
3040fdecfd0Sguenther 			object->obj_flags |= dynp->d_un.d_val;
30582c4222eSguenther 		if (dynp->d_tag == DT_FLAGS) {
30682c4222eSguenther 			object->dyn.flags |= dynp->d_un.d_val;
30782c4222eSguenther 			if (dynp->d_un.d_val & DF_SYMBOLIC)
30882c4222eSguenther 				object->dyn.symbolic = 1;
30991659d32Skettenis 			if (dynp->d_un.d_val & DF_TEXTREL)
31091659d32Skettenis 				object->dyn.textrel = 1;
31182c4222eSguenther 			if (dynp->d_un.d_val & DF_ORIGIN)
31282c4222eSguenther 				object->obj_flags |= DF_1_ORIGIN;
31382c4222eSguenther 			if (dynp->d_un.d_val & DF_BIND_NOW)
31482c4222eSguenther 				object->obj_flags |= DF_1_NOW;
31582c4222eSguenther 		}
31688098a4dSguenther 		if (dynp->d_tag == DT_RELACOUNT)
31788098a4dSguenther 			object->relacount = dynp->d_un.d_val;
31888098a4dSguenther 		if (dynp->d_tag == DT_RELCOUNT)
31988098a4dSguenther 			object->relcount = dynp->d_un.d_val;
320ac51d06cSguenther 		if (dynp->d_tag == DT_GNU_HASH)
321ac51d06cSguenther 			gnu_hash = dynp->d_un.d_val;
3224d11faf9Srahnds 		dynp++;
3234d11faf9Srahnds 	}
3240fdecfd0Sguenther 	DL_DEB((" flags %s = 0x%x\n", objname, object->obj_flags));
3252880af04Skettenis 	object->obj_type = objtype;
3262880af04Skettenis 
3272880af04Skettenis 	if (_dl_loading_object == NULL) {
3282880af04Skettenis 		/*
3292880af04Skettenis 		 * no loading object, object is the loading object,
3302880af04Skettenis 		 * as it is either executable, or dlopened()
3312880af04Skettenis 		 */
3322880af04Skettenis 		_dl_loading_object = object;
3332880af04Skettenis 	}
3342880af04Skettenis 
3352880af04Skettenis 	if ((object->obj_flags & DF_1_NOOPEN) != 0 &&
3362880af04Skettenis 	    _dl_loading_object->obj_type == OBJTYPE_DLO &&
33710200827Sguenther 	    !_dl_traceld) {
3382880af04Skettenis 		_dl_free(object);
3392880af04Skettenis 		_dl_errno = DL_CANT_LOAD_OBJ;
3402880af04Skettenis 		return(NULL);
3412880af04Skettenis 	}
3424d11faf9Srahnds 
3434d11faf9Srahnds 	/*
3444d11faf9Srahnds 	 *  Now relocate all pointer to dynamic info, but only
3455d5c76edSjufi 	 *  the ones which have pointer values.
3464d11faf9Srahnds 	 */
3474d11faf9Srahnds 	if (object->Dyn.info[DT_PLTGOT])
348ce11e090Skurt 		object->Dyn.info[DT_PLTGOT] += obase;
3494d11faf9Srahnds 	if (object->Dyn.info[DT_STRTAB])
350ce11e090Skurt 		object->Dyn.info[DT_STRTAB] += obase;
3514d11faf9Srahnds 	if (object->Dyn.info[DT_SYMTAB])
352ce11e090Skurt 		object->Dyn.info[DT_SYMTAB] += obase;
3534d11faf9Srahnds 	if (object->Dyn.info[DT_RELA])
354ce11e090Skurt 		object->Dyn.info[DT_RELA] += obase;
3554d11faf9Srahnds 	if (object->Dyn.info[DT_SONAME])
3560af06aafSkurt 		object->Dyn.info[DT_SONAME] += object->Dyn.info[DT_STRTAB];
3574d11faf9Srahnds 	if (object->Dyn.info[DT_RPATH])
3584be7d39eSrahnds 		object->Dyn.info[DT_RPATH] += object->Dyn.info[DT_STRTAB];
359d8ad95d2Sguenther 	if (object->Dyn.info[DT_RUNPATH])
360d8ad95d2Sguenther 		object->Dyn.info[DT_RUNPATH] += object->Dyn.info[DT_STRTAB];
3614d11faf9Srahnds 	if (object->Dyn.info[DT_REL])
362ce11e090Skurt 		object->Dyn.info[DT_REL] += obase;
3634d11faf9Srahnds 	if (object->Dyn.info[DT_INIT])
364ce11e090Skurt 		object->Dyn.info[DT_INIT] += obase;
3654d11faf9Srahnds 	if (object->Dyn.info[DT_FINI])
366ce11e090Skurt 		object->Dyn.info[DT_FINI] += obase;
3674be7d39eSrahnds 	if (object->Dyn.info[DT_JMPREL])
368ce11e090Skurt 		object->Dyn.info[DT_JMPREL] += obase;
36986fa57a2Skettenis 	if (object->Dyn.info[DT_INIT_ARRAY])
37086fa57a2Skettenis 		object->Dyn.info[DT_INIT_ARRAY] += obase;
37186fa57a2Skettenis 	if (object->Dyn.info[DT_FINI_ARRAY])
37286fa57a2Skettenis 		object->Dyn.info[DT_FINI_ARRAY] += obase;
37386fa57a2Skettenis 	if (object->Dyn.info[DT_PREINIT_ARRAY])
37486fa57a2Skettenis 		object->Dyn.info[DT_PREINIT_ARRAY] += obase;
375b3331980Sguenther 	if (object->Dyn.info[DT_RELR])
376b3331980Sguenther 		object->Dyn.info[DT_RELR] += obase;
3774d11faf9Srahnds 
378ac51d06cSguenther 	if (gnu_hash) {
3799d9b0c10Sderaadt 		Elf_Word *hashtab = (Elf_Word *)(gnu_hash + obase);
3809d9b0c10Sderaadt 		Elf_Word nbuckets = hashtab[0];
3819d9b0c10Sderaadt 		Elf_Word nmaskwords = hashtab[2];
38282cac0f6Sart 
383ac51d06cSguenther 		/* validity check */
384ac51d06cSguenther 		if (nbuckets > 0 && (nmaskwords & (nmaskwords - 1)) == 0) {
3859d9b0c10Sderaadt 			Elf_Word symndx = hashtab[1];
386ac51d06cSguenther 			int bloom_size32 = (ELFSIZE / 32) * nmaskwords;
387ac51d06cSguenther 
388ac51d06cSguenther 			object->nbuckets = nbuckets;
389ac51d06cSguenther 			object->symndx_gnu = symndx;
390ac51d06cSguenther 			object->mask_bm_gnu = nmaskwords - 1;
391ac51d06cSguenther 			object->shift2_gnu = hashtab[3];
392ac51d06cSguenther 			object->bloom_gnu = (Elf_Addr *)(hashtab + 4);
393ac51d06cSguenther 			object->buckets_gnu = hashtab + 4 + bloom_size32;
394ac51d06cSguenther 			object->chains_gnu = object->buckets_gnu + nbuckets
395ac51d06cSguenther 			    - symndx;
396ac51d06cSguenther 
397ac51d06cSguenther 			/*
398ac51d06cSguenther 			 * If the ELF hash is present, get the total symbol
399ac51d06cSguenther 			 * count ("nchains") from there.  Otherwise, count
400ac51d06cSguenther 			 * the entries in the GNU hash chain.
401ac51d06cSguenther 			 */
402ac51d06cSguenther 			if (object->Dyn.info[DT_HASH] == 0) {
4039d9b0c10Sderaadt 				Elf_Word n;
404ac51d06cSguenther 
405ac51d06cSguenther 				for (n = 0; n < nbuckets; n++) {
406ac51d06cSguenther 					Elf_Word bkt = object->buckets_gnu[n];
4079d9b0c10Sderaadt 					const Elf_Word *hashval;
408ac51d06cSguenther 					if (bkt == 0)
409ac51d06cSguenther 						continue;
410ac51d06cSguenther 					hashval = &object->chains_gnu[bkt];
411ac51d06cSguenther 					do {
412ac51d06cSguenther 						symndx++;
413ac51d06cSguenther 					} while ((*hashval++ & 1U) == 0);
414ac51d06cSguenther 				}
415ac51d06cSguenther 				object->nchains = symndx;
416ac51d06cSguenther 			}
417ac51d06cSguenther 			object->status |= STAT_GNU_HASH;
418ac51d06cSguenther 		}
419ac51d06cSguenther 	}
420ac51d06cSguenther 	if (object->Dyn.info[DT_HASH] != 0) {
4214e986f76Sguenther 		Elf_Hash_Word *hashtab =
4224e986f76Sguenther 		    (Elf_Hash_Word *)(object->Dyn.info[DT_HASH] + obase);
423ac51d06cSguenther 
42482cac0f6Sart 		object->nchains = hashtab[1];
425ac51d06cSguenther 		if (object->nbuckets == 0) {
426ac51d06cSguenther 			object->nbuckets = hashtab[0];
427ac51d06cSguenther 			object->buckets_elf = hashtab + 2;
428ac51d06cSguenther 			object->chains_elf = object->buckets_elf +
429ac51d06cSguenther 			    object->nbuckets;
430ac51d06cSguenther 		}
4314d11faf9Srahnds 	}
4324d11faf9Srahnds 
4339f6c3316Skurt 	object->phdrp = phdrp;
4349f6c3316Skurt 	object->phdrc = phdrc;
435ce11e090Skurt 	object->load_base = lbase;
436ce11e090Skurt 	object->obj_base = obase;
43741c230b7Sdrahn 	object->load_name = _dl_strdup(objname);
43867b06ea7Sotto 	if (object->load_name == NULL)
4393b50b772Sguenther 		_dl_oom();
4400acae5e5Sdrahn 	object->load_object = _dl_loading_object;
4419652c184Smatthew 	if (object->load_object == object)
4429652c184Smatthew 		DL_DEB(("head %s\n", object->load_name));
4430acae5e5Sdrahn 	DL_DEB(("obj %s has %s as head\n", object->load_name,
4440acae5e5Sdrahn 	    _dl_loading_object->load_name));
4458f55e5f1Skurt 	object->refcount = 0;
44650cabf59Skurt 	object->opencount = 0;	/* # dlopen() & exe */
44750cabf59Skurt 	object->grprefcount = 0;
4487afb1d1dSkjell 	/* default dev, inode for dlopen-able objects. */
4497afb1d1dSkjell 	object->dev = 0;
4507afb1d1dSkjell 	object->inode = 0;
451b6decd50Sguenther 	object->grpsym_gen = 0;
45250cabf59Skurt 	TAILQ_INIT(&object->grpref_list);
4537afb1d1dSkjell 
45482c4222eSguenther 	if (object->dyn.runpath)
45582c4222eSguenther 		object->runpath = _dl_split_path(object->dyn.runpath);
45682c4222eSguenther 	/*
45782c4222eSguenther 	 * DT_RPATH is ignored if DT_RUNPATH is present...except in
45882c4222eSguenther 	 * the exe, whose DT_RPATH is a fallback for libs that don't
45982c4222eSguenther 	 * use DT_RUNPATH
46082c4222eSguenther 	 */
46182c4222eSguenther 	if (object->dyn.rpath && (object->runpath == NULL ||
46282c4222eSguenther 	    objtype == OBJTYPE_EXE))
463c8dfd7a0Skurt 		object->rpath = _dl_split_path(object->dyn.rpath);
464337bd349Skurt 	if ((object->obj_flags & DF_1_ORIGIN) && _dl_trust)
465337bd349Skurt 		_dl_origin_subst(object);
466c8dfd7a0Skurt 
467ae398163Smiod 	_dl_trace_object_setup(object);
468ae398163Smiod 
4694d11faf9Srahnds 	return (object);
4704d11faf9Srahnds }
4714d11faf9Srahnds 
4722f86c0efSderaadt static void
_dl_tailq_free(struct dep_node * n)47350cabf59Skurt _dl_tailq_free(struct dep_node *n)
47450cabf59Skurt {
47550cabf59Skurt 	struct dep_node *next;
47650cabf59Skurt 
47750cabf59Skurt 	while (n != NULL) {
47850cabf59Skurt 		next = TAILQ_NEXT(n, next_sib);
47950cabf59Skurt 		_dl_free(n);
48050cabf59Skurt 		n = next;
48150cabf59Skurt 	}
48250cabf59Skurt }
48350cabf59Skurt 
484bfc90735Sguenther static elf_object_t *free_objects;
4858a1e31c9Sdrahn 
4868a1e31c9Sdrahn void
_dl_cleanup_objects()4878a1e31c9Sdrahn _dl_cleanup_objects()
4888a1e31c9Sdrahn {
4898a1e31c9Sdrahn 	elf_object_t *nobj, *head;
49050cabf59Skurt 	struct dep_node *n, *next;
4912c5b63afSdrahn 
49250cabf59Skurt 	n = TAILQ_FIRST(&_dlopened_child_list);
49350cabf59Skurt 	while (n != NULL) {
49450cabf59Skurt 		next = TAILQ_NEXT(n, next_sib);
495ca7a62b5Skurt 		if (OBJECT_DLREF_CNT(n->data) == 0) {
4962c5b63afSdrahn 			TAILQ_REMOVE(&_dlopened_child_list, n, next_sib);
4972c5b63afSdrahn 			_dl_free(n);
4982c5b63afSdrahn 		}
49950cabf59Skurt 		n = next;
5002c5b63afSdrahn 	}
5012c5b63afSdrahn 
5028a1e31c9Sdrahn 	head = free_objects;
5038a1e31c9Sdrahn 	free_objects = NULL;
5048a1e31c9Sdrahn 	while (head != NULL) {
50550cabf59Skurt 		_dl_free(head->load_name);
5060af06aafSkurt 		_dl_free((char *)head->sod.sod_name);
50782c4222eSguenther 		_dl_free_path(head->runpath);
508c8dfd7a0Skurt 		_dl_free_path(head->rpath);
509bae526eeSguenther 		_dl_free(head->grpsym_vec.vec);
510d937a926Sguenther 		_dl_free(head->child_vec.vec);
51150cabf59Skurt 		_dl_tailq_free(TAILQ_FIRST(&head->grpref_list));
5128a1e31c9Sdrahn 		nobj = head->next;
5138a1e31c9Sdrahn 		_dl_free(head);
5148a1e31c9Sdrahn 		head = nobj;
5158a1e31c9Sdrahn 	}
5168a1e31c9Sdrahn }
5178a1e31c9Sdrahn 
5184d11faf9Srahnds void
_dl_remove_object(elf_object_t * object)5194d11faf9Srahnds _dl_remove_object(elf_object_t *object)
5204d11faf9Srahnds {
5214d11faf9Srahnds 	object->prev->next = object->next;
52239b7d201Sderaadt 	if (object->next)
5234d11faf9Srahnds 		object->next->prev = object->prev;
52439b7d201Sderaadt 
52539b7d201Sderaadt 	if (_dl_last_object == object)
526a526b250Sdrahn 		_dl_last_object = object->prev;
527bae526eeSguenther 	object_count--;
52839b7d201Sderaadt 
5298a1e31c9Sdrahn 	object->next = free_objects;
53050cabf59Skurt 	free_objects = object;
5314d11faf9Srahnds }
5324d11faf9Srahnds 
5332f86c0efSderaadt static int
matched_symbol(elf_object_t * obj,const Elf_Sym * sym,struct symlookup * sl)53449fb1b57Sguenther matched_symbol(elf_object_t *obj, const Elf_Sym *sym, struct symlookup *sl)
5352f86c0efSderaadt {
53649fb1b57Sguenther 	switch (ELF_ST_TYPE(sym->st_info)) {
53749fb1b57Sguenther 	case STT_FUNC:
53849fb1b57Sguenther 		/*
53949fb1b57Sguenther 		 * Allow this symbol if we are referring to a function which
54049fb1b57Sguenther 		 * has a value, even if section is UNDEF.  This allows &func
54149fb1b57Sguenther 		 * to refer to PLT as per the ELF spec.  If flags has SYM_PLT
54249fb1b57Sguenther 		 * set, we must have actual symbol, so this symbol is skipped.
5432f86c0efSderaadt 		 */
54449fb1b57Sguenther 		if ((sl->sl_flags & SYM_PLT) && sym->st_shndx == SHN_UNDEF)
54549fb1b57Sguenther 			return 0;
54649fb1b57Sguenther 		if (sym->st_value == 0)
54749fb1b57Sguenther 			return 0;
54849fb1b57Sguenther 		break;
54949fb1b57Sguenther 	case STT_NOTYPE:
55049fb1b57Sguenther 	case STT_OBJECT:
55149fb1b57Sguenther 		if (sym->st_value == 0)
55249fb1b57Sguenther 			return 0;
55349fb1b57Sguenther #if 0
55449fb1b57Sguenther 		/* FALLTHROUGH */
55549fb1b57Sguenther 	case STT_TLS:
55649fb1b57Sguenther #endif
55749fb1b57Sguenther 		if (sym->st_shndx == SHN_UNDEF)
55849fb1b57Sguenther 			return 0;
55949fb1b57Sguenther 		break;
56049fb1b57Sguenther 	default:
56149fb1b57Sguenther 		return 0;
5622f86c0efSderaadt 	}
5632f86c0efSderaadt 
564143e5accSguenther 	if (sym != sl->sl_out.sym &&
56549fb1b57Sguenther 	    _dl_strcmp(sl->sl_name, obj->dyn.strtab + sym->st_name))
56649fb1b57Sguenther 		return 0;
56749fb1b57Sguenther 
5682f86c0efSderaadt 	if (ELF_ST_BIND(sym->st_info) == STB_GLOBAL) {
569143e5accSguenther 		sl->sl_out.sym = sym;
570143e5accSguenther 		sl->sl_out.obj = obj;
5712f86c0efSderaadt 		return 1;
5722f86c0efSderaadt 	} else if (ELF_ST_BIND(sym->st_info) == STB_WEAK) {
573143e5accSguenther 		if (sl->sl_weak_out.sym == NULL) {
574143e5accSguenther 			sl->sl_weak_out.sym = sym;
575143e5accSguenther 			sl->sl_weak_out.obj = obj;
5762f86c0efSderaadt 		}
57749fb1b57Sguenther 		/* done with this object, but need to check other objects */
57849fb1b57Sguenther 		return -1;
5792f86c0efSderaadt 	}
58049fb1b57Sguenther 	return 0;
58149fb1b57Sguenther }
58249fb1b57Sguenther 
58349fb1b57Sguenther static int
_dl_find_symbol_obj(elf_object_t * obj,struct symlookup * sl)58449fb1b57Sguenther _dl_find_symbol_obj(elf_object_t *obj, struct symlookup *sl)
58549fb1b57Sguenther {
58649fb1b57Sguenther 	const Elf_Sym	*symt = obj->dyn.symtab;
58749fb1b57Sguenther 
588ac51d06cSguenther 	if (obj->status & STAT_GNU_HASH) {
589ac51d06cSguenther 		uint32_t hash = sl->sl_gnu_hash;
590ac51d06cSguenther 		Elf_Addr bloom_word;
591ac51d06cSguenther 		unsigned int h1;
592ac51d06cSguenther 		unsigned int h2;
5939d9b0c10Sderaadt 		Elf_Word bucket;
5949d9b0c10Sderaadt 		const Elf_Word *hashval;
595ac51d06cSguenther 
596ac51d06cSguenther 		/* pick right bitmask word from Bloom filter array */
597ac51d06cSguenther 		bloom_word = obj->bloom_gnu[(hash / ELFSIZE) &
598ac51d06cSguenther 		    obj->mask_bm_gnu];
599ac51d06cSguenther 
600ac51d06cSguenther 		/* calculate modulus ELFSIZE of gnu hash and its derivative */
601ac51d06cSguenther 		h1 = hash & (ELFSIZE - 1);
602ac51d06cSguenther 		h2 = (hash >> obj->shift2_gnu) & (ELFSIZE - 1);
603ac51d06cSguenther 
604ac51d06cSguenther 		/* Filter out the "definitely not in set" queries */
605ac51d06cSguenther 		if (((bloom_word >> h1) & (bloom_word >> h2) & 1) == 0)
606ac51d06cSguenther 			return 0;
607ac51d06cSguenther 
608ac51d06cSguenther 		/* Locate hash chain and corresponding value element */
609ac51d06cSguenther 		bucket = obj->buckets_gnu[hash % obj->nbuckets];
610ac51d06cSguenther 		if (bucket == 0)
611ac51d06cSguenther 			return 0;
612ac51d06cSguenther 		hashval = &obj->chains_gnu[bucket];
613ac51d06cSguenther 		do {
614ac51d06cSguenther 			if (((*hashval ^ hash) >> 1) == 0) {
615ac51d06cSguenther 				const Elf_Sym *sym = symt +
616ac51d06cSguenther 				    (hashval - obj->chains_gnu);
617ac51d06cSguenther 
618ac51d06cSguenther 				int r = matched_symbol(obj, sym, sl);
619ac51d06cSguenther 				if (r)
620ac51d06cSguenther 					return r > 0;
621ac51d06cSguenther 			}
622ac51d06cSguenther 		} while ((*hashval++ & 1U) == 0);
623ac51d06cSguenther 	} else {
624ac51d06cSguenther 		Elf_Word si;
625ac51d06cSguenther 
626ac51d06cSguenther 		for (si = obj->buckets_elf[sl->sl_elf_hash % obj->nbuckets];
627ac51d06cSguenther 		    si != STN_UNDEF; si = obj->chains_elf[si]) {
62849fb1b57Sguenther 			const Elf_Sym *sym = symt + si;
62949fb1b57Sguenther 
63049fb1b57Sguenther 			int r = matched_symbol(obj, sym, sl);
63149fb1b57Sguenther 			if (r)
63249fb1b57Sguenther 				return r > 0;
6332f86c0efSderaadt 		}
634ac51d06cSguenther 	}
6352f86c0efSderaadt 	return 0;
6362f86c0efSderaadt }
6372f86c0efSderaadt 
638143e5accSguenther struct sym_res
_dl_find_symbol(const char * name,int flags,const Elf_Sym * ref_sym,elf_object_t * req_obj)639143e5accSguenther _dl_find_symbol(const char *name, int flags, const Elf_Sym *ref_sym,
640143e5accSguenther     elf_object_t *req_obj)
6414d11faf9Srahnds {
642ac51d06cSguenther 	const unsigned char *p;
643ac51d06cSguenther 	unsigned char c;
644b5a21baaSguenther 	struct symlookup sl = {
645b5a21baaSguenther 		.sl_name = name,
646143e5accSguenther 		.sl_out = { .sym = NULL },
647143e5accSguenther 		.sl_weak_out = { .sym = NULL },
648b5a21baaSguenther 		.sl_elf_hash = 0,
649ac51d06cSguenther 		.sl_gnu_hash = 5381,
650b5a21baaSguenther 		.sl_flags = flags,
651b5a21baaSguenther 	};
6524d11faf9Srahnds 
653ac51d06cSguenther 	/* Calculate both hashes in one pass */
654ac51d06cSguenther 	for (p = (const unsigned char *)name; (c = *p) != '\0'; p++) {
655ac51d06cSguenther 		sl.sl_elf_hash = (sl.sl_elf_hash << 4) + c;
656d82bde86Smillert 		sl.sl_elf_hash ^= (sl.sl_elf_hash >> 24) & 0xf0;
657ac51d06cSguenther 		sl.sl_gnu_hash = sl.sl_gnu_hash * 33 + c;
6584d11faf9Srahnds 	}
659d82bde86Smillert 	sl.sl_elf_hash &= 0x0fffffff;
6604d11faf9Srahnds 
66150f3e86fSdrahn 	if (req_obj->dyn.symbolic)
662b5a21baaSguenther 		if (_dl_find_symbol_obj(req_obj, &sl))
66350f3e86fSdrahn 			goto found;
66450f3e86fSdrahn 
66525205068Sguenther 	if (flags & SYM_DLSYM) {
666bae526eeSguenther 		struct object_vector vec;
667bae526eeSguenther 		int i;
668bae526eeSguenther 
669b5a21baaSguenther 		if (_dl_find_symbol_obj(req_obj, &sl))
670b5a21baaSguenther 			goto found;
6710acae5e5Sdrahn 
672b5a21baaSguenther 		/* weak definition in the specified object is good enough */
673143e5accSguenther 		if (sl.sl_weak_out.sym != NULL)
674b5a21baaSguenther 			goto found;
675b5a21baaSguenther 
676b5a21baaSguenther 		/* search dlopened obj and all children */
677bae526eeSguenther 		vec = req_obj->load_object->grpsym_vec;
678bae526eeSguenther 		for (i = 0; i < vec.len; i++) {
679bae526eeSguenther 			if (vec.vec[i] == req_obj)
680bae526eeSguenther 				continue;		/* already searched */
681bae526eeSguenther 			if (_dl_find_symbol_obj(vec.vec[i], &sl))
682b5a21baaSguenther 				goto found;
6830acae5e5Sdrahn 		}
68491de9d58Ssthen 	} else {
685bae526eeSguenther 		struct dep_node *n;
686bae526eeSguenther 		struct object_vector vec;
687bae526eeSguenther 		int i, skip = 0;
6880acae5e5Sdrahn 
6896fa405c3Sdrahn 		if ((flags & SYM_SEARCH_SELF) || (flags & SYM_SEARCH_NEXT))
6906fa405c3Sdrahn 			skip = 1;
6910acae5e5Sdrahn 
6920acae5e5Sdrahn 		/*
6930acae5e5Sdrahn 		 * search dlopened objects: global or req_obj == dlopened_obj
694bae526eeSguenther 		 * and its children
6950acae5e5Sdrahn 		 */
6960acae5e5Sdrahn 		TAILQ_FOREACH(n, &_dlopened_child_list, next_sib) {
6970fdecfd0Sguenther 			if (((n->data->obj_flags & DF_1_GLOBAL) == 0) &&
6980acae5e5Sdrahn 			    (n->data != req_obj->load_object))
6990acae5e5Sdrahn 				continue;
7000acae5e5Sdrahn 
701bae526eeSguenther 			vec = n->data->grpsym_vec;
702bae526eeSguenther 			for (i = 0; i < vec.len; i++) {
7036fa405c3Sdrahn 				if (skip == 1) {
704bae526eeSguenther 					if (vec.vec[i] == req_obj) {
7056fa405c3Sdrahn 						skip = 0;
7066fa405c3Sdrahn 						if (flags & SYM_SEARCH_NEXT)
7076fa405c3Sdrahn 							continue;
7086fa405c3Sdrahn 					} else
7096fa405c3Sdrahn 						continue;
7106fa405c3Sdrahn 				}
7110acae5e5Sdrahn 				if ((flags & SYM_SEARCH_OTHER) &&
712bae526eeSguenther 				    (vec.vec[i] == req_obj))
7130acae5e5Sdrahn 					continue;
714bae526eeSguenther 				if (_dl_find_symbol_obj(vec.vec[i], &sl))
71597ecf04aSkurt 					goto found;
7160acae5e5Sdrahn 			}
7170acae5e5Sdrahn 		}
7180acae5e5Sdrahn 	}
71950f3e86fSdrahn 
72050f3e86fSdrahn found:
721143e5accSguenther 	if (sl.sl_out.sym == NULL) {
722143e5accSguenther 		if (sl.sl_weak_out.sym != NULL)
723143e5accSguenther 			sl.sl_out = sl.sl_weak_out;
724143e5accSguenther 		else {
72506462af4Sdrahn 			if ((ref_sym == NULL ||
72606462af4Sdrahn 			    (ELF_ST_BIND(ref_sym->st_info) != STB_WEAK)) &&
72706462af4Sdrahn 			    (flags & SYM_WARNNOTFOUND))
72850f3e86fSdrahn 				_dl_printf("%s:%s: undefined symbol '%s'\n",
729702424caSguenther 				    __progname, req_obj->load_name, name);
730143e5accSguenther 			return (struct sym_res){ NULL, NULL };
731143e5accSguenther 		}
73250f3e86fSdrahn 	}
73350f3e86fSdrahn 
7346718d15cSdrahn 	if (ref_sym != NULL && ref_sym->st_size != 0 &&
735143e5accSguenther 	    (ref_sym->st_size != sl.sl_out.sym->st_size) &&
736143e5accSguenther 	    (ELF_ST_TYPE(sl.sl_out.sym->st_info) != STT_FUNC)) {
73750f3e86fSdrahn 		_dl_printf("%s:%s: %s : WARNING: "
73850f3e86fSdrahn 		    "symbol(%s) size mismatch, relink your program\n",
739143e5accSguenther 		    __progname, req_obj->load_name, sl.sl_out.obj->load_name,
740b5a21baaSguenther 		    name);
74150f3e86fSdrahn 	}
74250f3e86fSdrahn 
743143e5accSguenther 	return sl.sl_out;
74450f3e86fSdrahn }
74550f3e86fSdrahn 
74676ff5b71Sotto void
_dl_debug_state(void)74776ff5b71Sotto _dl_debug_state(void)
74876ff5b71Sotto {
74976ff5b71Sotto 	/* Debugger stub */
75076ff5b71Sotto }
7514a066defSderaadt 
7524a066defSderaadt /*
7534a066defSderaadt  * Search for DT_SONAME, and check if this is libc
7544a066defSderaadt  */
7554a066defSderaadt int
_dl_islibc(Elf_Dyn * _dynp,Elf_Addr loff)7564a066defSderaadt _dl_islibc(Elf_Dyn *_dynp, Elf_Addr loff)
7574a066defSderaadt {
7584a066defSderaadt 	Elf_Dyn *d, *dynp = (Elf_Dyn *)((unsigned long)_dynp + loff);
7594a066defSderaadt 	long base = 0;
7604a066defSderaadt 
7614a066defSderaadt 	for (d = dynp; d->d_tag != DT_NULL; d++)
7624a066defSderaadt 		if (d->d_tag == DT_STRTAB) {
7634a066defSderaadt 			base = d->d_un.d_ptr + loff;
7644a066defSderaadt 			break;
7654a066defSderaadt 		}
7664a066defSderaadt 	if (base == 0)
7674a066defSderaadt 		return 0;
7684a066defSderaadt 	for (d = dynp; d->d_tag != DT_NULL; d++)
7694a066defSderaadt 		if (d->d_tag == DT_SONAME) {
7704a066defSderaadt 			if (_dl_strncmp((char *)(base + d->d_un.d_ptr),
7714a066defSderaadt 			    "libc.so.", 8) == 0)
7724a066defSderaadt 				return 1;
7734a066defSderaadt 			break;
7744a066defSderaadt 		}
7754a066defSderaadt 	return 0;
7764a066defSderaadt }
7774a066defSderaadt 
7784a066defSderaadt void
_dl_pin(int file,Elf_Phdr * phdp,void * base,size_t len,void * exec_base,size_t exec_size)7794a066defSderaadt _dl_pin(int file, Elf_Phdr *phdp, void *base, size_t len,
7804a066defSderaadt     void *exec_base, size_t exec_size)
7814a066defSderaadt {
7824a066defSderaadt 	struct pinsyscalls {
7834a066defSderaadt 		u_int offset;
7844a066defSderaadt 		u_int sysno;
7854a066defSderaadt 	} *syscalls;
7864a066defSderaadt 	int npins = 0, nsyscalls, i;
7874a066defSderaadt 	u_int *pins = NULL;
7884a066defSderaadt 	vaddr_t offset;
7894a066defSderaadt 
7904a066defSderaadt 	if (phdp->p_filesz > SYS_MAXSYSCALL * 2 * sizeof(*syscalls) ||
7914a066defSderaadt 	    phdp->p_filesz % sizeof(*syscalls) != 0 ||
7924a066defSderaadt 	    phdp->p_offset & 0x3)
7934a066defSderaadt 		return;
7944a066defSderaadt 	syscalls = _dl_mmap(NULL, phdp->p_filesz, PROT_READ,
7954a066defSderaadt 	    MAP_PRIVATE|MAP_FILE, file, phdp->p_offset);
7964a066defSderaadt 	if (syscalls == MAP_FAILED)
7974a066defSderaadt 		return;
7984a066defSderaadt 
7994a066defSderaadt 	/* Validate, and calculate pintable size */
8004a066defSderaadt 	nsyscalls = phdp->p_filesz / sizeof(*syscalls);
8014a066defSderaadt 	for (i = 0; i < nsyscalls; i++) {
8024a066defSderaadt 		if (syscalls[i].sysno < 0 ||
8034a066defSderaadt 		    syscalls[i].sysno >= SYS_MAXSYSCALL ||
8044a066defSderaadt 		    syscalls[i].offset >= len)
8054a066defSderaadt 			goto bad;
8064a066defSderaadt 		npins = MAXIMUM(npins, syscalls[i].sysno);
8074a066defSderaadt 	}
8084a066defSderaadt 	npins++;
8094a066defSderaadt 
8104a066defSderaadt 	/*
8114a066defSderaadt 	 * Fill pintable: 0 = invalid, -1 = accept, else offset
8124a066defSderaadt 	 * from base, rebase to text_start while at it
8134a066defSderaadt 	 */
8144a066defSderaadt 	pins = _dl_calloc(npins, sizeof(u_int));
8154a066defSderaadt 	offset = exec_base - base;
8164a066defSderaadt 	for (i = 0; i < nsyscalls; i++) {
8174a066defSderaadt 		if (pins[syscalls[i].sysno])
8184a066defSderaadt 			pins[syscalls[i].sysno] = (u_int)-1; /* duplicated */
8194a066defSderaadt 		else
8204a066defSderaadt 			pins[syscalls[i].sysno] = syscalls[i].offset - offset;
8214a066defSderaadt 	}
8224a066defSderaadt 	base += offset;
8234a066defSderaadt 	len = len - offset;
8244a066defSderaadt bad:
8254a066defSderaadt 	_dl_munmap(syscalls, phdp->p_filesz);
8264a066defSderaadt 	if (pins)
8274a066defSderaadt 		_dl_pinsyscalls(base, len, pins, npins);
8284a066defSderaadt 	_dl_free(pins);
8294a066defSderaadt }
830