rtld.c revision 1.142 1 /* $NetBSD: rtld.c,v 1.142 2011/03/26 21:40:37 joerg Exp $ */
2
3 /*
4 * Copyright 1996 John D. Polstra.
5 * Copyright 1996 Matt Thomas <matt (at) 3am-software.com>
6 * Copyright 2002 Charles M. Hannum <root (at) ihack.net>
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by John Polstra.
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 /*
36 * Dynamic linker for ELF.
37 *
38 * John Polstra <jdp (at) polstra.com>.
39 */
40
41 #include <sys/cdefs.h>
42 #ifndef lint
43 __RCSID("$NetBSD: rtld.c,v 1.142 2011/03/26 21:40:37 joerg Exp $");
44 #endif /* not lint */
45
46 #include <sys/param.h>
47 #include <sys/atomic.h>
48 #include <sys/mman.h>
49 #include <err.h>
50 #include <errno.h>
51 #include <fcntl.h>
52 #include <lwp.h>
53 #include <stdarg.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <unistd.h>
58 #include <dirent.h>
59
60 #include <ctype.h>
61
62 #include <dlfcn.h>
63 #include "debug.h"
64 #include "rtld.h"
65
66 #if !defined(lint)
67 #include "sysident.h"
68 #endif
69
70 /*
71 * Function declarations.
72 */
73 static void _rtld_init(caddr_t, caddr_t, const char *);
74 static void _rtld_exit(void);
75
76 Elf_Addr _rtld(Elf_Addr *, Elf_Addr);
77
78
79 /*
80 * Data declarations.
81 */
82 static char *error_message; /* Message for dlopen(), or NULL */
83
84 struct r_debug _rtld_debug; /* for GDB; */
85 bool _rtld_trust; /* False for setuid and setgid programs */
86 Obj_Entry *_rtld_objlist; /* Head of linked list of shared objects */
87 Obj_Entry **_rtld_objtail; /* Link field of last object in list */
88 Obj_Entry *_rtld_objmain; /* The main program shared object */
89 Obj_Entry _rtld_objself; /* The dynamic linker shared object */
90 u_int _rtld_objcount; /* Number of objects in _rtld_objlist */
91 u_int _rtld_objloads; /* Number of objects loaded in _rtld_objlist */
92 const char _rtld_path[] = _PATH_RTLD;
93
94 /* Initialize a fake symbol for resolving undefined weak references. */
95 Elf_Sym _rtld_sym_zero = {
96 .st_info = ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE),
97 .st_shndx = SHN_ABS,
98 };
99 size_t _rtld_pagesz; /* Page size, as provided by kernel */
100
101 Search_Path *_rtld_default_paths;
102 Search_Path *_rtld_paths;
103
104 Library_Xform *_rtld_xforms;
105
106 /*
107 * Global declarations normally provided by crt0.
108 */
109 char *__progname;
110 char **environ;
111
112 static volatile bool _rtld_mutex_may_recurse;
113
114 #if defined(RTLD_DEBUG)
115 #ifndef __sh__
116 extern Elf_Addr _GLOBAL_OFFSET_TABLE_[];
117 #else /* 32-bit SuperH */
118 register Elf_Addr *_GLOBAL_OFFSET_TABLE_ asm("r12");
119 #endif
120 #endif /* RTLD_DEBUG */
121 extern Elf_Dyn _DYNAMIC;
122
123 static void _rtld_call_fini_functions(int);
124 static void _rtld_call_init_functions(void);
125 static void _rtld_initlist_visit(Objlist *, Obj_Entry *, int);
126 static void _rtld_initlist_tsort(Objlist *, int);
127 static Obj_Entry *_rtld_dlcheck(void *);
128 static void _rtld_init_dag(Obj_Entry *);
129 static void _rtld_init_dag1(Obj_Entry *, Obj_Entry *);
130 static void _rtld_objlist_remove(Objlist *, Obj_Entry *);
131 static void _rtld_objlist_clear(Objlist *);
132 static void _rtld_unload_object(Obj_Entry *, bool);
133 static void _rtld_unref_dag(Obj_Entry *);
134 static Obj_Entry *_rtld_obj_from_addr(const void *);
135
136 static void
137 _rtld_call_fini_functions(int force)
138 {
139 Objlist_Entry *elm;
140 Objlist finilist;
141 Obj_Entry *obj;
142
143 dbg(("_rtld_call_fini_functions(%d)", force));
144
145 SIMPLEQ_INIT(&finilist);
146 _rtld_initlist_tsort(&finilist, 1);
147
148 /* First pass: objects _not_ marked with DF_1_INITFIRST. */
149 SIMPLEQ_FOREACH(elm, &finilist, link) {
150 obj = elm->obj;
151 if (obj->refcount > 0 && !force) {
152 continue;
153 }
154 if (obj->fini == NULL || obj->fini_called || obj->z_initfirst) {
155 continue;
156 }
157 dbg (("calling fini function %s at %p", obj->path,
158 (void *)obj->fini));
159 obj->fini_called = 1;
160 /* XXXlocking: exit point */
161 _rtld_mutex_may_recurse = true;
162 (*obj->fini)();
163 _rtld_mutex_may_recurse = false;
164 }
165
166 /* Second pass: objects marked with DF_1_INITFIRST. */
167 SIMPLEQ_FOREACH(elm, &finilist, link) {
168 obj = elm->obj;
169 if (obj->refcount > 0 && !force) {
170 continue;
171 }
172 if (obj->fini == NULL || obj->fini_called) {
173 continue;
174 }
175 dbg (("calling fini function %s at %p (DF_1_INITFIRST)",
176 obj->path, (void *)obj->fini));
177 obj->fini_called = 1;
178 /* XXXlocking: exit point */
179 _rtld_mutex_may_recurse = true;
180 (*obj->fini)();
181 _rtld_mutex_may_recurse = false;
182 }
183
184 _rtld_objlist_clear(&finilist);
185 }
186
187 static void
188 _rtld_call_init_functions()
189 {
190 Objlist_Entry *elm;
191 Objlist initlist;
192 Obj_Entry *obj;
193
194 dbg(("_rtld_call_init_functions()"));
195 SIMPLEQ_INIT(&initlist);
196 _rtld_initlist_tsort(&initlist, 0);
197
198 /* First pass: objects marked with DF_1_INITFIRST. */
199 SIMPLEQ_FOREACH(elm, &initlist, link) {
200 obj = elm->obj;
201 if (obj->init == NULL || obj->init_called || !obj->z_initfirst) {
202 continue;
203 }
204 dbg (("calling init function %s at %p (DF_1_INITFIRST)",
205 obj->path, (void *)obj->init));
206 obj->init_called = 1;
207 /* XXXlocking: exit point */
208 _rtld_mutex_may_recurse = true;
209 (*obj->init)();
210 _rtld_mutex_may_recurse = false;
211 }
212
213 /* Second pass: all other objects. */
214 SIMPLEQ_FOREACH(elm, &initlist, link) {
215 obj = elm->obj;
216 if (obj->init == NULL || obj->init_called) {
217 continue;
218 }
219 dbg (("calling init function %s at %p", obj->path,
220 (void *)obj->init));
221 obj->init_called = 1;
222 /* XXXlocking: exit point */
223 _rtld_mutex_may_recurse = true;
224 (*obj->init)();
225 _rtld_mutex_may_recurse = false;
226 }
227
228 _rtld_objlist_clear(&initlist);
229 }
230
231 /*
232 * Initialize the dynamic linker. The argument is the address at which
233 * the dynamic linker has been mapped into memory. The primary task of
234 * this function is to create an Obj_Entry for the dynamic linker and
235 * to resolve the PLT relocation for platforms that need it (those that
236 * define __HAVE_FUNCTION_DESCRIPTORS
237 */
238 static void
239 _rtld_init(caddr_t mapbase, caddr_t relocbase, const char *execname)
240 {
241
242 /* Conjure up an Obj_Entry structure for the dynamic linker. */
243 _rtld_objself.path = __UNCONST(_rtld_path);
244 _rtld_objself.pathlen = sizeof(_rtld_path)-1;
245 _rtld_objself.rtld = true;
246 _rtld_objself.mapbase = mapbase;
247 _rtld_objself.relocbase = relocbase;
248 _rtld_objself.dynamic = (Elf_Dyn *) &_DYNAMIC;
249 _rtld_objself.strtab = "_rtld_sym_zero";
250
251 /*
252 * Set value to -relocbase so that
253 *
254 * _rtld_objself.relocbase + _rtld_sym_zero.st_value == 0
255 *
256 * This allows unresolved references to weak symbols to be computed
257 * to a value of 0.
258 */
259 _rtld_sym_zero.st_value = -(uintptr_t)relocbase;
260
261 _rtld_digest_dynamic(_rtld_path, &_rtld_objself);
262 assert(!_rtld_objself.needed);
263 #if !defined(__hppa__)
264 assert(!_rtld_objself.pltrel && !_rtld_objself.pltrela);
265 #else
266 _rtld_relocate_plt_objects(&_rtld_objself);
267 #endif
268 #if !defined(__mips__) && !defined(__hppa__)
269 assert(!_rtld_objself.pltgot);
270 #endif
271 #if !defined(__arm__) && !defined(__mips__) && !defined(__sh__)
272 /* ARM, MIPS and SH{3,5} have a bogus DT_TEXTREL. */
273 assert(!_rtld_objself.textrel);
274 #endif
275
276 _rtld_add_paths(execname, &_rtld_default_paths,
277 RTLD_DEFAULT_LIBRARY_PATH);
278
279 #ifdef RTLD_ARCH_SUBDIR
280 _rtld_add_paths(execname, &_rtld_default_paths,
281 RTLD_DEFAULT_LIBRARY_PATH "/" RTLD_ARCH_SUBDIR);
282 #endif
283
284 /*
285 * Set up the _rtld_objlist pointer, so that rtld symbols can be found.
286 */
287 _rtld_objlist = &_rtld_objself;
288
289 /* Make the object list empty again. */
290 _rtld_objlist = NULL;
291 _rtld_objtail = &_rtld_objlist;
292 _rtld_objcount = 0;
293
294 _rtld_debug.r_brk = _rtld_debug_state;
295 _rtld_debug.r_state = RT_CONSISTENT;
296 }
297
298 /*
299 * Cleanup procedure. It will be called (by the atexit() mechanism) just
300 * before the process exits.
301 */
302 static void
303 _rtld_exit(void)
304 {
305 dbg(("rtld_exit()"));
306
307 _rtld_call_fini_functions(1);
308 }
309
310 /*
311 * Main entry point for dynamic linking. The argument is the stack
312 * pointer. The stack is expected to be laid out as described in the
313 * SVR4 ABI specification, Intel 386 Processor Supplement. Specifically,
314 * the stack pointer points to a word containing ARGC. Following that
315 * in the stack is a null-terminated sequence of pointers to argument
316 * strings. Then comes a null-terminated sequence of pointers to
317 * environment strings. Finally, there is a sequence of "auxiliary
318 * vector" entries.
319 *
320 * This function returns the entry point for the main program, the dynamic
321 * linker's exit procedure in sp[0], and a pointer to the main object in
322 * sp[1].
323 */
324 Elf_Addr
325 _rtld(Elf_Addr *sp, Elf_Addr relocbase)
326 {
327 const AuxInfo *pAUX_base, *pAUX_entry, *pAUX_execfd, *pAUX_phdr,
328 *pAUX_phent, *pAUX_phnum, *pAUX_euid, *pAUX_egid,
329 *pAUX_ruid, *pAUX_rgid;
330 const AuxInfo *pAUX_pagesz;
331 char **env, **oenvp;
332 const AuxInfo *aux;
333 const AuxInfo *auxp;
334 #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
335 Obj_Entry *obj;
336 #endif
337 Elf_Addr *const osp = sp;
338 bool bind_now = 0;
339 const char *ld_bind_now, *ld_preload, *ld_library_path;
340 const char **argv;
341 const char *execname;
342 long argc;
343 const char **real___progname;
344 const Obj_Entry **real___mainprog_obj;
345 char ***real_environ;
346 #ifdef DEBUG
347 const char *ld_debug;
348 #endif
349 #ifdef RTLD_DEBUG
350 int i = 0;
351 #endif
352
353 /*
354 * On entry, the dynamic linker itself has not been relocated yet.
355 * Be very careful not to reference any global data until after
356 * _rtld_init has returned. It is OK to reference file-scope statics
357 * and string constants, and to call static and global functions.
358 */
359 /* Find the auxiliary vector on the stack. */
360 /* first Elf_Word reserved to address of exit routine */
361 #if defined(RTLD_DEBUG)
362 debug = 1;
363 dbg(("sp = %p, argc = %ld, argv = %p <%s> relocbase %p", sp,
364 (long)sp[2], &sp[3], (char *) sp[3], (void *)relocbase));
365 dbg(("got is at %p, dynamic is at %p", _GLOBAL_OFFSET_TABLE_,
366 &_DYNAMIC));
367 dbg(("_ctype_ is %p", _ctype_));
368 #endif
369
370 sp += 2; /* skip over return argument space */
371 argv = (const char **) &sp[1];
372 argc = *(long *)sp;
373 sp += 2 + argc; /* Skip over argc, arguments, and NULL
374 * terminator */
375 env = (char **) sp;
376 while (*sp++ != 0) { /* Skip over environment, and NULL terminator */
377 #if defined(RTLD_DEBUG)
378 dbg(("env[%d] = %p %s", i++, (void *)sp[-1], (char *)sp[-1]));
379 #endif
380 }
381 aux = (const AuxInfo *) sp;
382
383 pAUX_base = pAUX_entry = pAUX_execfd = NULL;
384 pAUX_phdr = pAUX_phent = pAUX_phnum = NULL;
385 pAUX_euid = pAUX_ruid = pAUX_egid = pAUX_rgid = NULL;
386 pAUX_pagesz = NULL;
387
388 execname = NULL;
389
390 /* Digest the auxiliary vector. */
391 for (auxp = aux; auxp->a_type != AT_NULL; ++auxp) {
392 switch (auxp->a_type) {
393 case AT_BASE:
394 pAUX_base = auxp;
395 break;
396 case AT_ENTRY:
397 pAUX_entry = auxp;
398 break;
399 case AT_EXECFD:
400 pAUX_execfd = auxp;
401 break;
402 case AT_PHDR:
403 pAUX_phdr = auxp;
404 break;
405 case AT_PHENT:
406 pAUX_phent = auxp;
407 break;
408 case AT_PHNUM:
409 pAUX_phnum = auxp;
410 break;
411 #ifdef AT_EUID
412 case AT_EUID:
413 pAUX_euid = auxp;
414 break;
415 case AT_RUID:
416 pAUX_ruid = auxp;
417 break;
418 case AT_EGID:
419 pAUX_egid = auxp;
420 break;
421 case AT_RGID:
422 pAUX_rgid = auxp;
423 break;
424 #endif
425 #ifdef AT_SUN_EXECNAME
426 case AT_SUN_EXECNAME:
427 execname = (const char *)(const void *)auxp->a_v;
428 break;
429 #endif
430 case AT_PAGESZ:
431 pAUX_pagesz = auxp;
432 break;
433 }
434 }
435
436 /* Initialize and relocate ourselves. */
437 if (pAUX_base == NULL) {
438 _rtld_error("Bad pAUX_base");
439 _rtld_die();
440 }
441 assert(pAUX_pagesz != NULL);
442 _rtld_pagesz = (int)pAUX_pagesz->a_v;
443 _rtld_init((caddr_t)pAUX_base->a_v, (caddr_t)relocbase, execname);
444
445 __progname = _rtld_objself.path;
446 environ = env;
447
448 _rtld_trust = ((pAUX_euid ? (uid_t)pAUX_euid->a_v : geteuid()) ==
449 (pAUX_ruid ? (uid_t)pAUX_ruid->a_v : getuid())) &&
450 ((pAUX_egid ? (gid_t)pAUX_egid->a_v : getegid()) ==
451 (pAUX_rgid ? (gid_t)pAUX_rgid->a_v : getgid()));
452
453 #ifdef DEBUG
454 ld_debug = NULL;
455 #endif
456 ld_bind_now = NULL;
457 ld_library_path = NULL;
458 ld_preload = NULL;
459 /*
460 * Inline avoid using normal getenv/unsetenv here as the libc
461 * code is quite a bit more complicated.
462 */
463 for (oenvp = env; *env != NULL; ++env) {
464 static const char bind_var[] = "LD_BIND_NOW=";
465 static const char debug_var[] = "LD_DEBUG=";
466 static const char path_var[] = "LD_LIBRARY_PATH=";
467 static const char preload_var[] = "LD_PRELOAD=";
468 #define LEN(x) (sizeof(x) - 1)
469
470 if ((*env)[0] != 'L' || (*env)[1] != 'D') {
471 /*
472 * Special case to skip most entries without
473 * the more expensive calls to strncmp.
474 */
475 *oenvp++ = *env;
476 } else if (strncmp(*env, debug_var, LEN(debug_var)) == 0) {
477 if (_rtld_trust) {
478 #ifdef DEBUG
479 ld_debug = *env + LEN(debug_var);
480 #endif
481 *oenvp++ = *env;
482 }
483 } else if (strncmp(*env, bind_var, LEN(bind_var)) == 0) {
484 ld_bind_now = *env + LEN(bind_var);
485 } else if (strncmp(*env, path_var, LEN(path_var)) == 0) {
486 if (_rtld_trust) {
487 ld_library_path = *env + LEN(path_var);
488 *oenvp++ = *env;
489 }
490 } else if (strncmp(*env, preload_var, LEN(preload_var)) == 0) {
491 if (_rtld_trust) {
492 ld_preload = *env + LEN(preload_var);
493 *oenvp++ = *env;
494 }
495 } else {
496 *oenvp++ = *env;
497 }
498 #undef LEN
499 }
500 *oenvp++ = NULL;
501
502 if (ld_bind_now != NULL && *ld_bind_now != '\0')
503 bind_now = true;
504 if (_rtld_trust) {
505 #ifdef DEBUG
506 #ifdef RTLD_DEBUG
507 debug = 0;
508 #endif
509 if (ld_debug != NULL && *ld_debug != '\0')
510 debug = 1;
511 #endif
512 _rtld_add_paths(execname, &_rtld_paths, ld_library_path);
513 } else {
514 execname = NULL;
515 }
516 _rtld_process_hints(execname, &_rtld_paths, &_rtld_xforms,
517 _PATH_LD_HINTS);
518 dbg(("dynamic linker is initialized, mapbase=%p, relocbase=%p",
519 _rtld_objself.mapbase, _rtld_objself.relocbase));
520
521 /*
522 * Load the main program, or process its program header if it is
523 * already loaded.
524 */
525 if (pAUX_execfd != NULL) { /* Load the main program. */
526 int fd = pAUX_execfd->a_v;
527 const char *obj_name = argv[0] ? argv[0] : "main program";
528 dbg(("loading main program"));
529 _rtld_objmain = _rtld_map_object(obj_name, fd, NULL);
530 close(fd);
531 if (_rtld_objmain == NULL)
532 _rtld_die();
533 } else { /* Main program already loaded. */
534 const Elf_Phdr *phdr;
535 int phnum;
536 caddr_t entry;
537
538 dbg(("processing main program's program header"));
539 assert(pAUX_phdr != NULL);
540 phdr = (const Elf_Phdr *) pAUX_phdr->a_v;
541 assert(pAUX_phnum != NULL);
542 phnum = pAUX_phnum->a_v;
543 assert(pAUX_phent != NULL);
544 assert(pAUX_phent->a_v == sizeof(Elf_Phdr));
545 assert(pAUX_entry != NULL);
546 entry = (caddr_t) pAUX_entry->a_v;
547 _rtld_objmain = _rtld_digest_phdr(phdr, phnum, entry);
548 _rtld_objmain->path = xstrdup(argv[0] ? argv[0] :
549 "main program");
550 _rtld_objmain->pathlen = strlen(_rtld_objmain->path);
551 }
552
553 _rtld_objmain->mainprog = true;
554
555 /*
556 * Get the actual dynamic linker pathname from the executable if
557 * possible. (It should always be possible.) That ensures that
558 * gdb will find the right dynamic linker even if a non-standard
559 * one is being used.
560 */
561 if (_rtld_objmain->interp != NULL &&
562 strcmp(_rtld_objmain->interp, _rtld_objself.path) != 0)
563 _rtld_objself.path = xstrdup(_rtld_objmain->interp);
564 dbg(("actual dynamic linker is %s", _rtld_objself.path));
565
566 _rtld_digest_dynamic(execname, _rtld_objmain);
567
568 /* Link the main program into the list of objects. */
569 *_rtld_objtail = _rtld_objmain;
570 _rtld_objtail = &_rtld_objmain->next;
571 _rtld_objcount++;
572 _rtld_objloads++;
573
574 _rtld_linkmap_add(_rtld_objmain);
575 _rtld_linkmap_add(&_rtld_objself);
576
577 ++_rtld_objmain->refcount;
578 _rtld_objmain->mainref = 1;
579 _rtld_objlist_push_tail(&_rtld_list_main, _rtld_objmain);
580
581 if (ld_preload) {
582 /*
583 * Pre-load user-specified objects after the main program
584 * but before any shared object dependencies.
585 */
586 dbg(("preloading objects"));
587 if (_rtld_preload(ld_preload) == -1)
588 _rtld_die();
589 }
590
591 dbg(("loading needed objects"));
592 if (_rtld_load_needed_objects(_rtld_objmain, _RTLD_MAIN) == -1)
593 _rtld_die();
594
595 #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
596 dbg(("initializing initial Thread Local Storage"));
597 /*
598 * All initial objects get the TLS space from the static block.
599 */
600 for (obj = _rtld_objlist; obj != NULL; obj = obj->next)
601 _rtld_tls_offset_allocate(obj);
602 _rtld_tls_initial_allocation();
603 #endif
604
605 dbg(("relocating objects"));
606 if (_rtld_relocate_objects(_rtld_objmain, bind_now) == -1)
607 _rtld_die();
608
609 dbg(("doing copy relocations"));
610 if (_rtld_do_copy_relocations(_rtld_objmain) == -1)
611 _rtld_die();
612
613 /*
614 * Set the __progname, environ and, __mainprog_obj before
615 * calling anything that might use them.
616 */
617 real___progname = _rtld_objmain_sym("__progname");
618 if (real___progname) {
619 if (argv[0] != NULL) {
620 if ((*real___progname = strrchr(argv[0], '/')) == NULL)
621 (*real___progname) = argv[0];
622 else
623 (*real___progname)++;
624 } else {
625 (*real___progname) = NULL;
626 }
627 }
628 real_environ = _rtld_objmain_sym("environ");
629 if (real_environ)
630 *real_environ = environ;
631 /*
632 * Set __mainprog_obj for old binaries.
633 */
634 real___mainprog_obj = _rtld_objmain_sym("__mainprog_obj");
635 if (real___mainprog_obj)
636 *real___mainprog_obj = _rtld_objmain;
637
638 _rtld_exclusive_enter();
639
640 dbg(("calling _init functions"));
641 _rtld_call_init_functions();
642
643 dbg(("control at program entry point = %p, obj = %p, exit = %p",
644 _rtld_objmain->entry, _rtld_objmain, _rtld_exit));
645
646 _rtld_exclusive_exit();
647
648 /*
649 * Return with the entry point and the exit procedure in at the top
650 * of stack.
651 */
652
653 _rtld_debug_state(); /* say hello to gdb! */
654
655 ((void **) osp)[0] = _rtld_exit;
656 ((void **) osp)[1] = _rtld_objmain;
657 return (Elf_Addr) _rtld_objmain->entry;
658 }
659
660 void
661 _rtld_die(void)
662 {
663 const char *msg = dlerror();
664
665 if (msg == NULL)
666 msg = "Fatal error";
667 xerrx(1, "%s", msg);
668 }
669
670 static Obj_Entry *
671 _rtld_dlcheck(void *handle)
672 {
673 Obj_Entry *obj;
674
675 for (obj = _rtld_objlist; obj != NULL; obj = obj->next)
676 if (obj == (Obj_Entry *) handle)
677 break;
678
679 if (obj == NULL || obj->dl_refcount == 0) {
680 xwarnx("Invalid shared object handle %p", handle);
681 return NULL;
682 }
683 return obj;
684 }
685
686 static void
687 _rtld_initlist_visit(Objlist* list, Obj_Entry *obj, int rev)
688 {
689 Needed_Entry* elm;
690
691 /* dbg(("_rtld_initlist_visit(%s)", obj->path)); */
692
693 if (obj->init_done)
694 return;
695 obj->init_done = 1;
696
697 for (elm = obj->needed; elm != NULL; elm = elm->next) {
698 if (elm->obj != NULL) {
699 _rtld_initlist_visit(list, elm->obj, rev);
700 }
701 }
702
703 if (rev) {
704 _rtld_objlist_push_head(list, obj);
705 } else {
706 _rtld_objlist_push_tail(list, obj);
707 }
708 }
709
710 static void
711 _rtld_initlist_tsort(Objlist* list, int rev)
712 {
713 dbg(("_rtld_initlist_tsort"));
714
715 Obj_Entry* obj;
716
717 for (obj = _rtld_objlist->next; obj; obj = obj->next) {
718 obj->init_done = 0;
719 }
720
721 for (obj = _rtld_objlist->next; obj; obj = obj->next) {
722 _rtld_initlist_visit(list, obj, rev);
723 }
724 }
725
726 static void
727 _rtld_init_dag(Obj_Entry *root)
728 {
729
730 _rtld_init_dag1(root, root);
731 }
732
733 static void
734 _rtld_init_dag1(Obj_Entry *root, Obj_Entry *obj)
735 {
736 const Needed_Entry *needed;
737
738 if (!obj->mainref) {
739 if (_rtld_objlist_find(&obj->dldags, root))
740 return;
741 dbg(("add %p (%s) to %p (%s) DAG", obj, obj->path, root,
742 root->path));
743 _rtld_objlist_push_tail(&obj->dldags, root);
744 _rtld_objlist_push_tail(&root->dagmembers, obj);
745 }
746 for (needed = obj->needed; needed != NULL; needed = needed->next)
747 if (needed->obj != NULL)
748 _rtld_init_dag1(root, needed->obj);
749 }
750
751 /*
752 * Note, this is called only for objects loaded by dlopen().
753 */
754 static void
755 _rtld_unload_object(Obj_Entry *root, bool do_fini_funcs)
756 {
757
758 _rtld_unref_dag(root);
759 if (root->refcount == 0) { /* We are finished with some objects. */
760 Obj_Entry *obj;
761 Obj_Entry **linkp;
762 Objlist_Entry *elm;
763
764 /* Finalize objects that are about to be unmapped. */
765 if (do_fini_funcs)
766 _rtld_call_fini_functions(0);
767
768 /* Remove the DAG from all objects' DAG lists. */
769 SIMPLEQ_FOREACH(elm, &root->dagmembers, link)
770 _rtld_objlist_remove(&elm->obj->dldags, root);
771
772 /* Remove the DAG from the RTLD_GLOBAL list. */
773 if (root->globalref) {
774 root->globalref = 0;
775 _rtld_objlist_remove(&_rtld_list_global, root);
776 }
777
778 /* Unmap all objects that are no longer referenced. */
779 linkp = &_rtld_objlist->next;
780 while ((obj = *linkp) != NULL) {
781 if (obj->refcount == 0) {
782 dbg(("unloading \"%s\"", obj->path));
783 if (obj->ehdr != MAP_FAILED)
784 munmap(obj->ehdr, _rtld_pagesz);
785 munmap(obj->mapbase, obj->mapsize);
786 _rtld_objlist_remove(&_rtld_list_global, obj);
787 _rtld_linkmap_delete(obj);
788 *linkp = obj->next;
789 _rtld_objcount--;
790 _rtld_obj_free(obj);
791 } else
792 linkp = &obj->next;
793 }
794 _rtld_objtail = linkp;
795 }
796 }
797
798 void
799 _rtld_ref_dag(Obj_Entry *root)
800 {
801 const Needed_Entry *needed;
802
803 assert(root);
804
805 ++root->refcount;
806
807 dbg(("incremented reference on \"%s\" (%d)", root->path,
808 root->refcount));
809 for (needed = root->needed; needed != NULL;
810 needed = needed->next) {
811 if (needed->obj != NULL)
812 _rtld_ref_dag(needed->obj);
813 }
814 }
815
816 static void
817 _rtld_unref_dag(Obj_Entry *root)
818 {
819
820 assert(root);
821 assert(root->refcount != 0);
822
823 --root->refcount;
824 dbg(("decremented reference on \"%s\" (%d)", root->path,
825 root->refcount));
826
827 if (root->refcount == 0) {
828 const Needed_Entry *needed;
829
830 for (needed = root->needed; needed != NULL;
831 needed = needed->next) {
832 if (needed->obj != NULL)
833 _rtld_unref_dag(needed->obj);
834 }
835 }
836 }
837
838 __strong_alias(__dlclose,dlclose)
839 int
840 dlclose(void *handle)
841 {
842 Obj_Entry *root = _rtld_dlcheck(handle);
843
844 if (root == NULL)
845 return -1;
846
847 _rtld_debug.r_state = RT_DELETE;
848 _rtld_debug_state();
849
850 --root->dl_refcount;
851 _rtld_unload_object(root, true);
852
853 _rtld_debug.r_state = RT_CONSISTENT;
854 _rtld_debug_state();
855
856 return 0;
857 }
858
859 __strong_alias(__dlerror,dlerror)
860 char *
861 dlerror(void)
862 {
863 char *msg = error_message;
864
865 error_message = NULL;
866 return msg;
867 }
868
869 __strong_alias(__dlopen,dlopen)
870 void *
871 dlopen(const char *name, int mode)
872 {
873 Obj_Entry **old_obj_tail = _rtld_objtail;
874 Obj_Entry *obj = NULL;
875 int flags = _RTLD_DLOPEN;
876 bool nodelete;
877 bool now;
878
879 _rtld_exclusive_enter();
880
881 flags |= (mode & RTLD_GLOBAL) ? _RTLD_GLOBAL : 0;
882 flags |= (mode & RTLD_NOLOAD) ? _RTLD_NOLOAD : 0;
883
884 nodelete = (mode & RTLD_NODELETE) ? true : false;
885 now = ((mode & RTLD_MODEMASK) == RTLD_NOW) ? true : false;
886
887 _rtld_debug.r_state = RT_ADD;
888 _rtld_debug_state();
889
890 if (name == NULL) {
891 obj = _rtld_objmain;
892 obj->refcount++;
893 } else
894 obj = _rtld_load_library(name, _rtld_objmain, flags);
895
896
897 if (obj != NULL) {
898 ++obj->dl_refcount;
899 if (*old_obj_tail != NULL) { /* We loaded something new. */
900 assert(*old_obj_tail == obj);
901
902 if (_rtld_load_needed_objects(obj, flags) == -1 ||
903 (_rtld_init_dag(obj),
904 _rtld_relocate_objects(obj,
905 (now || obj->z_now))) == -1) {
906 _rtld_unload_object(obj, false);
907 obj->dl_refcount--;
908 obj = NULL;
909 } else {
910 _rtld_call_init_functions();
911 }
912 }
913 if (obj != NULL) {
914 if ((nodelete || obj->z_nodelete) && !obj->ref_nodel) {
915 dbg(("dlopen obj %s nodelete", obj->path));
916 _rtld_ref_dag(obj);
917 obj->z_nodelete = obj->ref_nodel = true;
918 }
919 }
920 }
921 _rtld_debug.r_state = RT_CONSISTENT;
922 _rtld_debug_state();
923
924 _rtld_exclusive_exit();
925
926 return obj;
927 }
928
929 /*
930 * Find a symbol in the main program.
931 */
932 void *
933 _rtld_objmain_sym(const char *name)
934 {
935 unsigned long hash;
936 const Elf_Sym *def;
937 const Obj_Entry *obj;
938 DoneList donelist;
939
940 hash = _rtld_elf_hash(name);
941 obj = _rtld_objmain;
942 _rtld_donelist_init(&donelist);
943
944 def = _rtld_symlook_list(name, hash, &_rtld_list_main, &obj, false,
945 &donelist);
946
947 if (def != NULL)
948 return obj->relocbase + def->st_value;
949 return NULL;
950 }
951
952 #ifdef __powerpc__
953 static void *
954 hackish_return_address(void)
955 {
956 return __builtin_return_address(1);
957 }
958 #endif
959
960 #ifdef __HAVE_FUNCTION_DESCRIPTORS
961 #define lookup_mutex_enter() _rtld_exclusive_enter()
962 #define lookup_mutex_exit() _rtld_exclusive_exit()
963 #else
964 #define lookup_mutex_enter() _rtld_shared_enter()
965 #define lookup_mutex_exit() _rtld_shared_exit()
966 #endif
967
968 __strong_alias(__dlsym,dlsym)
969 void *
970 dlsym(void *handle, const char *name)
971 {
972 const Obj_Entry *obj;
973 unsigned long hash;
974 const Elf_Sym *def;
975 const Obj_Entry *defobj;
976 void *retaddr;
977 DoneList donelist;
978
979 lookup_mutex_enter();
980
981 hash = _rtld_elf_hash(name);
982 def = NULL;
983 defobj = NULL;
984
985 switch ((intptr_t)handle) {
986 case (intptr_t)NULL:
987 case (intptr_t)RTLD_NEXT:
988 case (intptr_t)RTLD_DEFAULT:
989 case (intptr_t)RTLD_SELF:
990 #ifdef __powerpc__
991 retaddr = hackish_return_address();
992 #else
993 retaddr = __builtin_return_address(0);
994 #endif
995 if ((obj = _rtld_obj_from_addr(retaddr)) == NULL) {
996 _rtld_error("Cannot determine caller's shared object");
997 lookup_mutex_exit();
998 return NULL;
999 }
1000
1001 switch ((intptr_t)handle) {
1002 case (intptr_t)NULL: /* Just the caller's shared object. */
1003 def = _rtld_symlook_obj(name, hash, obj, false);
1004 defobj = obj;
1005 break;
1006
1007 case (intptr_t)RTLD_NEXT: /* Objects after callers */
1008 obj = obj->next;
1009 /*FALLTHROUGH*/
1010
1011 case (intptr_t)RTLD_SELF: /* Caller included */
1012 for (; obj; obj = obj->next) {
1013 if ((def = _rtld_symlook_obj(name, hash, obj,
1014 false)) != NULL) {
1015 defobj = obj;
1016 break;
1017 }
1018 }
1019 break;
1020
1021 case (intptr_t)RTLD_DEFAULT:
1022 def = _rtld_symlook_default(name, hash, obj, &defobj,
1023 false);
1024 break;
1025
1026 default:
1027 abort();
1028 }
1029 break;
1030
1031 default:
1032 if ((obj = _rtld_dlcheck(handle)) == NULL) {
1033 lookup_mutex_exit();
1034 return NULL;
1035 }
1036
1037 _rtld_donelist_init(&donelist);
1038
1039 if (obj->mainprog) {
1040 /* Search main program and all libraries loaded by it */
1041 def = _rtld_symlook_list(name, hash, &_rtld_list_main,
1042 &defobj, false, &donelist);
1043 } else {
1044 Needed_Entry fake;
1045 DoneList depth;
1046
1047 /* Search the object and all the libraries loaded by it. */
1048 fake.next = NULL;
1049 fake.obj = __UNCONST(obj);
1050 fake.name = 0;
1051
1052 _rtld_donelist_init(&depth);
1053 def = _rtld_symlook_needed(name, hash, &fake, &defobj,
1054 false, &donelist, &depth);
1055 }
1056
1057 break;
1058 }
1059
1060 if (def != NULL) {
1061 void *p;
1062 #ifdef __HAVE_FUNCTION_DESCRIPTORS
1063 if (ELF_ST_TYPE(def->st_info) == STT_FUNC) {
1064 p = (void *)_rtld_function_descriptor_alloc(defobj,
1065 def, 0);
1066 lookup_mutex_exit();
1067 return p;
1068 }
1069 #endif /* __HAVE_FUNCTION_DESCRIPTORS */
1070 p = defobj->relocbase + def->st_value;
1071 lookup_mutex_exit();
1072 return p;
1073 }
1074
1075 _rtld_error("Undefined symbol \"%s\"", name);
1076 lookup_mutex_exit();
1077 return NULL;
1078 }
1079
1080 __strong_alias(__dladdr,dladdr)
1081 int
1082 dladdr(const void *addr, Dl_info *info)
1083 {
1084 const Obj_Entry *obj;
1085 const Elf_Sym *def, *best_def;
1086 void *symbol_addr;
1087 unsigned long symoffset;
1088
1089 lookup_mutex_enter();
1090
1091 #ifdef __HAVE_FUNCTION_DESCRIPTORS
1092 addr = _rtld_function_descriptor_function(addr);
1093 #endif /* __HAVE_FUNCTION_DESCRIPTORS */
1094
1095 obj = _rtld_obj_from_addr(addr);
1096 if (obj == NULL) {
1097 _rtld_error("No shared object contains address");
1098 lookup_mutex_enter();
1099 return 0;
1100 }
1101 info->dli_fname = obj->path;
1102 info->dli_fbase = obj->mapbase;
1103 info->dli_saddr = (void *)0;
1104 info->dli_sname = NULL;
1105
1106 /*
1107 * Walk the symbol list looking for the symbol whose address is
1108 * closest to the address sent in.
1109 */
1110 best_def = NULL;
1111 for (symoffset = 0; symoffset < obj->nchains; symoffset++) {
1112 def = obj->symtab + symoffset;
1113
1114 /*
1115 * For skip the symbol if st_shndx is either SHN_UNDEF or
1116 * SHN_COMMON.
1117 */
1118 if (def->st_shndx == SHN_UNDEF || def->st_shndx == SHN_COMMON)
1119 continue;
1120
1121 /*
1122 * If the symbol is greater than the specified address, or if it
1123 * is further away from addr than the current nearest symbol,
1124 * then reject it.
1125 */
1126 symbol_addr = obj->relocbase + def->st_value;
1127 if (symbol_addr > addr || symbol_addr < info->dli_saddr)
1128 continue;
1129
1130 /* Update our idea of the nearest symbol. */
1131 info->dli_sname = obj->strtab + def->st_name;
1132 info->dli_saddr = symbol_addr;
1133 best_def = def;
1134
1135 /* Exact match? */
1136 if (info->dli_saddr == addr)
1137 break;
1138 }
1139
1140 #ifdef __HAVE_FUNCTION_DESCRIPTORS
1141 if (best_def != NULL && ELF_ST_TYPE(best_def->st_info) == STT_FUNC)
1142 info->dli_saddr = (void *)_rtld_function_descriptor_alloc(obj,
1143 best_def, 0);
1144 #endif /* __HAVE_FUNCTION_DESCRIPTORS */
1145
1146 lookup_mutex_exit();
1147 return 1;
1148 }
1149
1150 __strong_alias(__dlinfo,dlinfo)
1151 int
1152 dlinfo(void *handle, int req, void *v)
1153 {
1154 const Obj_Entry *obj;
1155 void *retaddr;
1156
1157 _rtld_shared_enter();
1158
1159 if (handle == RTLD_SELF) {
1160 #ifdef __powerpc__
1161 retaddr = hackish_return_address();
1162 #else
1163 retaddr = __builtin_return_address(0);
1164 #endif
1165 if ((obj = _rtld_obj_from_addr(retaddr)) == NULL) {
1166 _rtld_error("Cannot determine caller's shared object");
1167 _rtld_shared_exit();
1168 return -1;
1169 }
1170 } else {
1171 if ((obj = _rtld_dlcheck(handle)) == NULL) {
1172 _rtld_error("Invalid handle");
1173 _rtld_shared_exit();
1174 return -1;
1175 }
1176 }
1177
1178 switch (req) {
1179 case RTLD_DI_LINKMAP:
1180 {
1181 const struct link_map **map = v;
1182
1183 *map = &obj->linkmap;
1184 break;
1185 }
1186
1187 default:
1188 _rtld_error("Invalid request");
1189 _rtld_shared_exit();
1190 return -1;
1191 }
1192
1193 _rtld_shared_exit();
1194 return 0;
1195 }
1196
1197 __strong_alias(__dl_iterate_phdr,dl_iterate_phdr);
1198 int
1199 dl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *), void *param)
1200 {
1201 struct dl_phdr_info phdr_info;
1202 const Obj_Entry *obj;
1203 int error = 0;
1204
1205 _rtld_shared_enter();
1206
1207 for (obj = _rtld_objlist; obj != NULL; obj = obj->next) {
1208 phdr_info.dlpi_addr = (Elf_Addr)obj->relocbase;
1209 phdr_info.dlpi_name = STAILQ_FIRST(&obj->names) ?
1210 STAILQ_FIRST(&obj->names)->name : obj->path;
1211 phdr_info.dlpi_phdr = obj->phdr;
1212 phdr_info.dlpi_phnum = obj->phsize / sizeof(obj->phdr[0]);
1213 #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
1214 phdr_info.dlpi_tls_modid = obj->tlsindex;
1215 phdr_info.dlpi_tls_data = obj->tlsinit;
1216 #else
1217 phdr_info.dlpi_tls_modid = 0;
1218 phdr_info.dlpi_tls_data = 0;
1219 #endif
1220 phdr_info.dlpi_adds = _rtld_objloads;
1221 phdr_info.dlpi_subs = _rtld_objloads - _rtld_objcount;
1222
1223 /* XXXlocking: exit point */
1224 error = callback(&phdr_info, sizeof(phdr_info), param);
1225 if (error)
1226 break;
1227 }
1228
1229 _rtld_shared_exit();
1230 return error;
1231 }
1232
1233 /*
1234 * Error reporting function. Use it like printf. If formats the message
1235 * into a buffer, and sets things up so that the next call to dlerror()
1236 * will return the message.
1237 */
1238 void
1239 _rtld_error(const char *fmt,...)
1240 {
1241 static char buf[512];
1242 va_list ap;
1243
1244 va_start(ap, fmt);
1245 xvsnprintf(buf, sizeof buf, fmt, ap);
1246 error_message = buf;
1247 va_end(ap);
1248 }
1249
1250 void
1251 _rtld_debug_state(void)
1252 {
1253
1254 /* do nothing */
1255 }
1256
1257 void
1258 _rtld_linkmap_add(Obj_Entry *obj)
1259 {
1260 struct link_map *l = &obj->linkmap;
1261 struct link_map *prev;
1262
1263 obj->linkmap.l_name = obj->path;
1264 obj->linkmap.l_addr = obj->relocbase;
1265 obj->linkmap.l_ld = obj->dynamic;
1266 #ifdef __mips__
1267 /* XXX This field is not standard and will be removed eventually. */
1268 obj->linkmap.l_offs = obj->relocbase;
1269 #endif
1270
1271 if (_rtld_debug.r_map == NULL) {
1272 _rtld_debug.r_map = l;
1273 return;
1274 }
1275
1276 /*
1277 * Scan to the end of the list, but not past the entry for the
1278 * dynamic linker, which we want to keep at the very end.
1279 */
1280 for (prev = _rtld_debug.r_map;
1281 prev->l_next != NULL && prev->l_next != &_rtld_objself.linkmap;
1282 prev = prev->l_next);
1283
1284 l->l_prev = prev;
1285 l->l_next = prev->l_next;
1286 if (l->l_next != NULL)
1287 l->l_next->l_prev = l;
1288 prev->l_next = l;
1289 }
1290
1291 void
1292 _rtld_linkmap_delete(Obj_Entry *obj)
1293 {
1294 struct link_map *l = &obj->linkmap;
1295
1296 if (l->l_prev == NULL) {
1297 if ((_rtld_debug.r_map = l->l_next) != NULL)
1298 l->l_next->l_prev = NULL;
1299 return;
1300 }
1301 if ((l->l_prev->l_next = l->l_next) != NULL)
1302 l->l_next->l_prev = l->l_prev;
1303 }
1304
1305 static Obj_Entry *
1306 _rtld_obj_from_addr(const void *addr)
1307 {
1308 Obj_Entry *obj;
1309
1310 for (obj = _rtld_objlist; obj != NULL; obj = obj->next) {
1311 if (addr < (void *) obj->mapbase)
1312 continue;
1313 if (addr < (void *) (obj->mapbase + obj->mapsize))
1314 return obj;
1315 }
1316 return NULL;
1317 }
1318
1319 static void
1320 _rtld_objlist_clear(Objlist *list)
1321 {
1322 while (!SIMPLEQ_EMPTY(list)) {
1323 Objlist_Entry* elm = SIMPLEQ_FIRST(list);
1324 SIMPLEQ_REMOVE_HEAD(list, link);
1325 xfree(elm);
1326 }
1327 }
1328
1329 static void
1330 _rtld_objlist_remove(Objlist *list, Obj_Entry *obj)
1331 {
1332 Objlist_Entry *elm;
1333
1334 if ((elm = _rtld_objlist_find(list, obj)) != NULL) {
1335 SIMPLEQ_REMOVE(list, elm, Struct_Objlist_Entry, link);
1336 xfree(elm);
1337 }
1338 }
1339
1340 #define RTLD_EXCLUSIVE_MASK 0x80000000U
1341 static volatile unsigned int _rtld_mutex;
1342 static volatile unsigned int _rtld_waiter_exclusive;
1343 static volatile unsigned int _rtld_waiter_shared;
1344
1345 void
1346 _rtld_shared_enter(void)
1347 {
1348 unsigned int cur;
1349 lwpid_t waiter, self = 0;
1350
1351 membar_enter();
1352
1353 for (;;) {
1354 cur = _rtld_mutex;
1355 /*
1356 * First check if we are currently not exclusively locked.
1357 */
1358 if ((cur & RTLD_EXCLUSIVE_MASK) == 0) {
1359 /* Yes, so increment use counter */
1360 if (atomic_cas_uint(&_rtld_mutex, cur, cur + 1) != cur)
1361 continue;
1362 return;
1363 }
1364 /*
1365 * Someone has an exclusive lock. Puts us on the waiter list.
1366 */
1367 if (!self)
1368 self = _lwp_self();
1369 if (cur == (self | RTLD_EXCLUSIVE_MASK)) {
1370 if (_rtld_mutex_may_recurse)
1371 return;
1372 _rtld_error("dead lock detected");
1373 _rtld_die();
1374 }
1375 waiter = atomic_swap_uint(&_rtld_waiter_shared, self);
1376 /*
1377 * Check for race against _rtld_exclusive_exit before sleeping.
1378 */
1379 if ((_rtld_mutex & RTLD_EXCLUSIVE_MASK) ||
1380 _rtld_waiter_exclusive)
1381 _lwp_park(NULL, -1, __UNVOLATILE(&_rtld_mutex), NULL);
1382 /* Try to remove us from the waiter list. */
1383 atomic_cas_uint(&_rtld_waiter_shared, self, 0);
1384 if (waiter)
1385 _lwp_unpark(waiter, __UNVOLATILE(&_rtld_mutex));
1386 }
1387 }
1388
1389 void
1390 _rtld_shared_exit(void)
1391 {
1392 lwpid_t waiter;
1393
1394 /*
1395 * Shared lock taken after an exclusive lock.
1396 * Just assume this is a partial recursion.
1397 */
1398 if (_rtld_mutex & RTLD_EXCLUSIVE_MASK)
1399 return;
1400
1401 /*
1402 * Wakeup LWPs waiting for an exclusive lock if this is the last
1403 * LWP on the shared lock.
1404 */
1405 if (atomic_dec_uint_nv(&_rtld_mutex))
1406 return;
1407 if ((waiter = _rtld_waiter_exclusive) != 0)
1408 _lwp_unpark(waiter, __UNVOLATILE(&_rtld_mutex));
1409
1410 membar_exit();
1411 }
1412
1413 void
1414 _rtld_exclusive_enter(void)
1415 {
1416 lwpid_t waiter, self = _lwp_self();
1417 unsigned int locked_value = (unsigned int)self | RTLD_EXCLUSIVE_MASK;
1418 unsigned int cur;
1419
1420 membar_enter();
1421
1422 for (;;) {
1423 if (atomic_cas_uint(&_rtld_mutex, 0, locked_value) == 0)
1424 break;
1425 waiter = atomic_swap_uint(&_rtld_waiter_exclusive, self);
1426 cur = _rtld_mutex;
1427 if (cur == locked_value) {
1428 _rtld_error("dead lock detected");
1429 _rtld_die();
1430 }
1431 if (cur)
1432 _lwp_park(NULL, -1, __UNVOLATILE(&_rtld_mutex), NULL);
1433 atomic_cas_uint(&_rtld_waiter_exclusive, self, 0);
1434 if (waiter)
1435 _lwp_unpark(waiter, __UNVOLATILE(&_rtld_mutex));
1436 }
1437 }
1438
1439 void
1440 _rtld_exclusive_exit(void)
1441 {
1442 lwpid_t waiter;
1443
1444 _rtld_mutex = 0;
1445 if ((waiter = _rtld_waiter_exclusive) != 0)
1446 _lwp_unpark(waiter, __UNVOLATILE(&_rtld_mutex));
1447
1448 if ((waiter = _rtld_waiter_shared) != 0)
1449 _lwp_unpark(waiter, __UNVOLATILE(&_rtld_mutex));
1450
1451 membar_exit();
1452 }
1453