1 1.221 riastrad /* $NetBSD: rtld.c,v 1.221 2025/05/02 23:04:31 riastradh Exp $ */ 2 1.1 cgd 3 1.1 cgd /* 4 1.1 cgd * Copyright 1996 John D. Polstra. 5 1.1 cgd * Copyright 1996 Matt Thomas <matt (at) 3am-software.com> 6 1.87 mycroft * Copyright 2002 Charles M. Hannum <root (at) ihack.net> 7 1.1 cgd * All rights reserved. 8 1.1 cgd * 9 1.1 cgd * Redistribution and use in source and binary forms, with or without 10 1.1 cgd * modification, are permitted provided that the following conditions 11 1.1 cgd * are met: 12 1.1 cgd * 1. Redistributions of source code must retain the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer. 14 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 cgd * notice, this list of conditions and the following disclaimer in the 16 1.1 cgd * documentation and/or other materials provided with the distribution. 17 1.1 cgd * 3. All advertising materials mentioning features or use of this software 18 1.1 cgd * must display the following acknowledgement: 19 1.1 cgd * This product includes software developed by John Polstra. 20 1.1 cgd * 4. The name of the author may not be used to endorse or promote products 21 1.1 cgd * derived from this software without specific prior written permission. 22 1.1 cgd * 23 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 1.1 cgd * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 1.1 cgd * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 1.1 cgd * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 1.1 cgd * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28 1.1 cgd * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 1.1 cgd * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 1.1 cgd * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 1.1 cgd * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 32 1.1 cgd * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 1.1 cgd */ 34 1.1 cgd 35 1.1 cgd /* 36 1.1 cgd * Dynamic linker for ELF. 37 1.1 cgd * 38 1.1 cgd * John Polstra <jdp (at) polstra.com>. 39 1.1 cgd */ 40 1.1 cgd 41 1.107 skrll #include <sys/cdefs.h> 42 1.107 skrll #ifndef lint 43 1.221 riastrad __RCSID("$NetBSD: rtld.c,v 1.221 2025/05/02 23:04:31 riastradh Exp $"); 44 1.107 skrll #endif /* not lint */ 45 1.107 skrll 46 1.141 joerg #include <sys/param.h> 47 1.141 joerg #include <sys/atomic.h> 48 1.141 joerg #include <sys/mman.h> 49 1.1 cgd #include <err.h> 50 1.1 cgd #include <errno.h> 51 1.1 cgd #include <fcntl.h> 52 1.141 joerg #include <lwp.h> 53 1.1 cgd #include <stdarg.h> 54 1.1 cgd #include <stdio.h> 55 1.1 cgd #include <stdlib.h> 56 1.1 cgd #include <string.h> 57 1.1 cgd #include <unistd.h> 58 1.1 cgd #include <dirent.h> 59 1.1 cgd 60 1.1 cgd #include <ctype.h> 61 1.1 cgd 62 1.2 cgd #include <dlfcn.h> 63 1.215 riastrad 64 1.1 cgd #include "debug.h" 65 1.215 riastrad #include "hash.h" 66 1.1 cgd #include "rtld.h" 67 1.3 cgd 68 1.20 kleink #if !defined(lint) 69 1.3 cgd #include "sysident.h" 70 1.20 kleink #endif 71 1.1 cgd 72 1.1 cgd /* 73 1.216 martin * Hidden function from common/lib/libc/atomic - nop on machines 74 1.216 martin * with enough atomic ops. Need to explicitly call it early. 75 1.216 martin * libc has the same symbol and will initialize itself, but not our copy. 76 1.216 martin */ 77 1.216 martin void __libc_atomic_init(void); 78 1.216 martin 79 1.216 martin /* 80 1.1 cgd * Function declarations. 81 1.1 cgd */ 82 1.113 christos static void _rtld_init(caddr_t, caddr_t, const char *); 83 1.98 skrll static void _rtld_exit(void); 84 1.15 christos 85 1.98 skrll Elf_Addr _rtld(Elf_Addr *, Elf_Addr); 86 1.15 christos 87 1.1 cgd 88 1.1 cgd /* 89 1.1 cgd * Data declarations. 90 1.1 cgd */ 91 1.15 christos static char *error_message; /* Message for dlopen(), or NULL */ 92 1.1 cgd 93 1.206 kamil struct r_debug _rtld_debug; /* The SVR4 interface for the debugger */ 94 1.15 christos bool _rtld_trust; /* False for setuid and setgid programs */ 95 1.15 christos Obj_Entry *_rtld_objlist; /* Head of linked list of shared objects */ 96 1.15 christos Obj_Entry **_rtld_objtail; /* Link field of last object in list */ 97 1.15 christos Obj_Entry *_rtld_objmain; /* The main program shared object */ 98 1.15 christos Obj_Entry _rtld_objself; /* The dynamic linker shared object */ 99 1.131 skrll u_int _rtld_objcount; /* Number of objects in _rtld_objlist */ 100 1.131 skrll u_int _rtld_objloads; /* Number of objects loaded in _rtld_objlist */ 101 1.147 joerg u_int _rtld_objgen; /* Generation count for _rtld_objlist */ 102 1.120 matt const char _rtld_path[] = _PATH_RTLD; 103 1.120 matt 104 1.120 matt /* Initialize a fake symbol for resolving undefined weak references. */ 105 1.120 matt Elf_Sym _rtld_sym_zero = { 106 1.120 matt .st_info = ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE), 107 1.120 matt .st_shndx = SHN_ABS, 108 1.120 matt }; 109 1.126 skrll size_t _rtld_pagesz; /* Page size, as provided by kernel */ 110 1.25 mycroft 111 1.22 kleink Search_Path *_rtld_default_paths; 112 1.15 christos Search_Path *_rtld_paths; 113 1.28 christos 114 1.28 christos Library_Xform *_rtld_xforms; 115 1.156 joerg static void *auxinfo; 116 1.28 christos 117 1.1 cgd /* 118 1.1 cgd * Global declarations normally provided by crt0. 119 1.1 cgd */ 120 1.15 christos char *__progname; 121 1.15 christos char **environ; 122 1.1 cgd 123 1.141 joerg static volatile bool _rtld_mutex_may_recurse; 124 1.141 joerg 125 1.108 uwe #if defined(RTLD_DEBUG) 126 1.112 scw #ifndef __sh__ 127 1.9 tv extern Elf_Addr _GLOBAL_OFFSET_TABLE_[]; 128 1.108 uwe #else /* 32-bit SuperH */ 129 1.108 uwe register Elf_Addr *_GLOBAL_OFFSET_TABLE_ asm("r12"); 130 1.108 uwe #endif 131 1.108 uwe #endif /* RTLD_DEBUG */ 132 1.15 christos extern Elf_Dyn _DYNAMIC; 133 1.8 tv 134 1.148 joerg static void _rtld_call_fini_functions(sigset_t *, int); 135 1.148 joerg static void _rtld_call_init_functions(sigset_t *); 136 1.117 ad static void _rtld_initlist_visit(Objlist *, Obj_Entry *, int); 137 1.117 ad static void _rtld_initlist_tsort(Objlist *, int); 138 1.98 skrll static Obj_Entry *_rtld_dlcheck(void *); 139 1.98 skrll static void _rtld_init_dag(Obj_Entry *); 140 1.98 skrll static void _rtld_init_dag1(Obj_Entry *, Obj_Entry *); 141 1.98 skrll static void _rtld_objlist_remove(Objlist *, Obj_Entry *); 142 1.117 ad static void _rtld_objlist_clear(Objlist *); 143 1.148 joerg static void _rtld_unload_object(sigset_t *, Obj_Entry *, bool); 144 1.98 skrll static void _rtld_unref_dag(Obj_Entry *); 145 1.98 skrll static Obj_Entry *_rtld_obj_from_addr(const void *); 146 1.198 kamil static void _rtld_fill_dl_phdr_info(const Obj_Entry *, struct dl_phdr_info *); 147 1.15 christos 148 1.158 matt static inline void 149 1.210 skrll _rtld_call_initfini_function(fptr_t func, sigset_t *mask) 150 1.158 matt { 151 1.158 matt _rtld_exclusive_exit(mask); 152 1.210 skrll (*func)(); 153 1.158 matt _rtld_exclusive_enter(mask); 154 1.158 matt } 155 1.158 matt 156 1.158 matt static void 157 1.158 matt _rtld_call_fini_function(Obj_Entry *obj, sigset_t *mask, u_int cur_objgen) 158 1.158 matt { 159 1.210 skrll if (obj->fini_arraysz == 0 && (obj->fini == NULL || obj->fini_called)) 160 1.174 joerg return; 161 1.174 joerg 162 1.210 skrll if (obj->fini != NULL && !obj->fini_called) { 163 1.158 matt dbg (("calling fini function %s at %p%s", obj->path, 164 1.158 matt (void *)obj->fini, 165 1.158 matt obj->z_initfirst ? " (DF_1_INITFIRST)" : "")); 166 1.165 skrll obj->fini_called = 1; 167 1.210 skrll _rtld_call_initfini_function(obj->fini, mask); 168 1.158 matt } 169 1.158 matt #ifdef HAVE_INITFINI_ARRAY 170 1.158 matt /* 171 1.158 matt * Now process the fini_array if it exists. Simply go from 172 1.158 matt * start to end. We need to make restartable so just advance 173 1.158 matt * the array pointer and decrement the size each time through 174 1.158 matt * the loop. 175 1.158 matt */ 176 1.158 matt while (obj->fini_arraysz > 0 && _rtld_objgen == cur_objgen) { 177 1.210 skrll fptr_t fini = *obj->fini_array++; 178 1.158 matt obj->fini_arraysz--; 179 1.158 matt dbg (("calling fini array function %s at %p%s", obj->path, 180 1.158 matt (void *)fini, 181 1.158 matt obj->z_initfirst ? " (DF_1_INITFIRST)" : "")); 182 1.210 skrll _rtld_call_initfini_function(fini, mask); 183 1.158 matt } 184 1.158 matt #endif /* HAVE_INITFINI_ARRAY */ 185 1.158 matt } 186 1.158 matt 187 1.1 cgd static void 188 1.148 joerg _rtld_call_fini_functions(sigset_t *mask, int force) 189 1.1 cgd { 190 1.117 ad Objlist_Entry *elm; 191 1.117 ad Objlist finilist; 192 1.147 joerg u_int cur_objgen; 193 1.1 cgd 194 1.117 ad dbg(("_rtld_call_fini_functions(%d)", force)); 195 1.117 ad 196 1.147 joerg restart: 197 1.147 joerg cur_objgen = ++_rtld_objgen; 198 1.117 ad SIMPLEQ_INIT(&finilist); 199 1.117 ad _rtld_initlist_tsort(&finilist, 1); 200 1.117 ad 201 1.117 ad /* First pass: objects _not_ marked with DF_1_INITFIRST. */ 202 1.117 ad SIMPLEQ_FOREACH(elm, &finilist, link) { 203 1.158 matt Obj_Entry * const obj = elm->obj; 204 1.158 matt if (!obj->z_initfirst) { 205 1.158 matt if (obj->refcount > 0 && !force) { 206 1.158 matt continue; 207 1.158 matt } 208 1.158 matt /* 209 1.158 matt * XXX This can race against a concurrent dlclose(). 210 1.158 matt * XXX In that case, the object could be unmapped before 211 1.158 matt * XXX the fini() call or the fini_array has completed. 212 1.158 matt */ 213 1.158 matt _rtld_call_fini_function(obj, mask, cur_objgen); 214 1.158 matt if (_rtld_objgen != cur_objgen) { 215 1.158 matt dbg(("restarting fini iteration")); 216 1.158 matt _rtld_objlist_clear(&finilist); 217 1.158 matt goto restart; 218 1.117 ad } 219 1.147 joerg } 220 1.117 ad } 221 1.117 ad 222 1.117 ad /* Second pass: objects marked with DF_1_INITFIRST. */ 223 1.117 ad SIMPLEQ_FOREACH(elm, &finilist, link) { 224 1.158 matt Obj_Entry * const obj = elm->obj; 225 1.117 ad if (obj->refcount > 0 && !force) { 226 1.117 ad continue; 227 1.117 ad } 228 1.147 joerg /* XXX See above for the race condition here */ 229 1.158 matt _rtld_call_fini_function(obj, mask, cur_objgen); 230 1.147 joerg if (_rtld_objgen != cur_objgen) { 231 1.147 joerg dbg(("restarting fini iteration")); 232 1.147 joerg _rtld_objlist_clear(&finilist); 233 1.147 joerg goto restart; 234 1.147 joerg } 235 1.117 ad } 236 1.117 ad 237 1.117 ad _rtld_objlist_clear(&finilist); 238 1.1 cgd } 239 1.1 cgd 240 1.1 cgd static void 241 1.158 matt _rtld_call_init_function(Obj_Entry *obj, sigset_t *mask, u_int cur_objgen) 242 1.158 matt { 243 1.210 skrll if (obj->init_arraysz == 0 && (obj->init_called || obj->init == NULL)) 244 1.158 matt return; 245 1.174 joerg 246 1.210 skrll if (!obj->init_called && obj->init != NULL) { 247 1.158 matt dbg (("calling init function %s at %p%s", 248 1.158 matt obj->path, (void *)obj->init, 249 1.158 matt obj->z_initfirst ? " (DF_1_INITFIRST)" : "")); 250 1.158 matt obj->init_called = 1; 251 1.210 skrll _rtld_call_initfini_function(obj->init, mask); 252 1.158 matt } 253 1.158 matt 254 1.158 matt #ifdef HAVE_INITFINI_ARRAY 255 1.158 matt /* 256 1.158 matt * Now process the init_array if it exists. Simply go from 257 1.158 matt * start to end. We need to make restartable so just advance 258 1.158 matt * the array pointer and decrement the size each time through 259 1.158 matt * the loop. 260 1.158 matt */ 261 1.158 matt while (obj->init_arraysz > 0 && _rtld_objgen == cur_objgen) { 262 1.210 skrll fptr_t init = *obj->init_array++; 263 1.158 matt obj->init_arraysz--; 264 1.158 matt dbg (("calling init_array function %s at %p%s", 265 1.158 matt obj->path, (void *)init, 266 1.158 matt obj->z_initfirst ? " (DF_1_INITFIRST)" : "")); 267 1.210 skrll _rtld_call_initfini_function(init, mask); 268 1.158 matt } 269 1.158 matt #endif /* HAVE_INITFINI_ARRAY */ 270 1.158 matt } 271 1.158 matt 272 1.188 joerg static bool 273 1.188 joerg _rtld_call_ifunc_functions(sigset_t *mask, Obj_Entry *obj, u_int cur_objgen) 274 1.188 joerg { 275 1.188 joerg if (obj->ifunc_remaining 276 1.192 joerg #if defined(IFUNC_NONPLT) 277 1.188 joerg || obj->ifunc_remaining_nonplt 278 1.188 joerg #endif 279 1.188 joerg ) { 280 1.188 joerg _rtld_call_ifunc(obj, mask, cur_objgen); 281 1.188 joerg if (_rtld_objgen != cur_objgen) { 282 1.188 joerg return true; 283 1.188 joerg } 284 1.188 joerg } 285 1.188 joerg return false; 286 1.188 joerg } 287 1.188 joerg 288 1.158 matt static void 289 1.148 joerg _rtld_call_init_functions(sigset_t *mask) 290 1.1 cgd { 291 1.117 ad Objlist_Entry *elm; 292 1.117 ad Objlist initlist; 293 1.147 joerg u_int cur_objgen; 294 1.94 simonb 295 1.117 ad dbg(("_rtld_call_init_functions()")); 296 1.147 joerg 297 1.147 joerg restart: 298 1.147 joerg cur_objgen = ++_rtld_objgen; 299 1.117 ad SIMPLEQ_INIT(&initlist); 300 1.117 ad _rtld_initlist_tsort(&initlist, 0); 301 1.117 ad 302 1.186 joerg /* First pass: objects with IRELATIVE relocations. */ 303 1.186 joerg SIMPLEQ_FOREACH(elm, &initlist, link) { 304 1.188 joerg if (_rtld_call_ifunc_functions(mask, elm->obj, cur_objgen)) { 305 1.188 joerg dbg(("restarting init iteration")); 306 1.188 joerg _rtld_objlist_clear(&initlist); 307 1.188 joerg goto restart; 308 1.186 joerg } 309 1.186 joerg } 310 1.188 joerg /* 311 1.188 joerg * XXX: For historic reasons, init/fini of the main object are called 312 1.188 joerg * from crt0. Don't introduce that mistake for ifunc, so look at 313 1.188 joerg * the head of _rtld_objlist that _rtld_initlist_tsort skipped. 314 1.188 joerg */ 315 1.188 joerg if (_rtld_call_ifunc_functions(mask, _rtld_objlist, cur_objgen)) { 316 1.188 joerg dbg(("restarting init iteration")); 317 1.188 joerg _rtld_objlist_clear(&initlist); 318 1.188 joerg goto restart; 319 1.188 joerg } 320 1.186 joerg 321 1.186 joerg /* Second pass: objects marked with DF_1_INITFIRST. */ 322 1.117 ad SIMPLEQ_FOREACH(elm, &initlist, link) { 323 1.158 matt Obj_Entry * const obj = elm->obj; 324 1.158 matt if (obj->z_initfirst) { 325 1.158 matt _rtld_call_init_function(obj, mask, cur_objgen); 326 1.158 matt if (_rtld_objgen != cur_objgen) { 327 1.158 matt dbg(("restarting init iteration")); 328 1.158 matt _rtld_objlist_clear(&initlist); 329 1.158 matt goto restart; 330 1.158 matt } 331 1.147 joerg } 332 1.117 ad } 333 1.117 ad 334 1.186 joerg /* Third pass: all other objects. */ 335 1.117 ad SIMPLEQ_FOREACH(elm, &initlist, link) { 336 1.158 matt _rtld_call_init_function(elm->obj, mask, cur_objgen); 337 1.147 joerg if (_rtld_objgen != cur_objgen) { 338 1.147 joerg dbg(("restarting init iteration")); 339 1.147 joerg _rtld_objlist_clear(&initlist); 340 1.147 joerg goto restart; 341 1.147 joerg } 342 1.14 pk } 343 1.117 ad 344 1.117 ad _rtld_objlist_clear(&initlist); 345 1.1 cgd } 346 1.14 pk 347 1.1 cgd /* 348 1.1 cgd * Initialize the dynamic linker. The argument is the address at which 349 1.1 cgd * the dynamic linker has been mapped into memory. The primary task of 350 1.105 skrll * this function is to create an Obj_Entry for the dynamic linker and 351 1.105 skrll * to resolve the PLT relocation for platforms that need it (those that 352 1.105 skrll * define __HAVE_FUNCTION_DESCRIPTORS 353 1.1 cgd */ 354 1.1 cgd static void 355 1.114 christos _rtld_init(caddr_t mapbase, caddr_t relocbase, const char *execname) 356 1.1 cgd { 357 1.198 kamil const Elf_Ehdr *ehdr; 358 1.94 simonb 359 1.14 pk /* Conjure up an Obj_Entry structure for the dynamic linker. */ 360 1.120 matt _rtld_objself.path = __UNCONST(_rtld_path); 361 1.120 matt _rtld_objself.pathlen = sizeof(_rtld_path)-1; 362 1.80 mycroft _rtld_objself.rtld = true; 363 1.80 mycroft _rtld_objself.mapbase = mapbase; 364 1.80 mycroft _rtld_objself.relocbase = relocbase; 365 1.80 mycroft _rtld_objself.dynamic = (Elf_Dyn *) &_DYNAMIC; 366 1.119 christos _rtld_objself.strtab = "_rtld_sym_zero"; 367 1.1 cgd 368 1.120 matt /* 369 1.128 skrll * Set value to -relocbase so that 370 1.128 skrll * 371 1.128 skrll * _rtld_objself.relocbase + _rtld_sym_zero.st_value == 0 372 1.128 skrll * 373 1.120 matt * This allows unresolved references to weak symbols to be computed 374 1.128 skrll * to a value of 0. 375 1.120 matt */ 376 1.120 matt _rtld_sym_zero.st_value = -(uintptr_t)relocbase; 377 1.120 matt 378 1.113 christos _rtld_digest_dynamic(_rtld_path, &_rtld_objself); 379 1.104 skrll assert(!_rtld_objself.needed); 380 1.105 skrll #if !defined(__hppa__) 381 1.103 skrll assert(!_rtld_objself.pltrel && !_rtld_objself.pltrela); 382 1.105 skrll #else 383 1.105 skrll _rtld_relocate_plt_objects(&_rtld_objself); 384 1.105 skrll #endif 385 1.105 skrll #if !defined(__mips__) && !defined(__hppa__) 386 1.104 skrll assert(!_rtld_objself.pltgot); 387 1.103 skrll #endif 388 1.97 skrll #if !defined(__arm__) && !defined(__mips__) && !defined(__sh__) 389 1.97 skrll /* ARM, MIPS and SH{3,5} have a bogus DT_TEXTREL. */ 390 1.103 skrll assert(!_rtld_objself.textrel); 391 1.80 mycroft #endif 392 1.13 christos 393 1.114 christos _rtld_add_paths(execname, &_rtld_default_paths, 394 1.114 christos RTLD_DEFAULT_LIBRARY_PATH); 395 1.13 christos 396 1.123 mrg #ifdef RTLD_ARCH_SUBDIR 397 1.123 mrg _rtld_add_paths(execname, &_rtld_default_paths, 398 1.123 mrg RTLD_DEFAULT_LIBRARY_PATH "/" RTLD_ARCH_SUBDIR); 399 1.123 mrg #endif 400 1.123 mrg 401 1.169 skrll /* Make the object list empty. */ 402 1.14 pk _rtld_objlist = NULL; 403 1.14 pk _rtld_objtail = &_rtld_objlist; 404 1.129 roy _rtld_objcount = 0; 405 1.1 cgd 406 1.206 kamil _rtld_debug.r_version = R_DEBUG_VERSION; 407 1.14 pk _rtld_debug.r_brk = _rtld_debug_state; 408 1.14 pk _rtld_debug.r_state = RT_CONSISTENT; 409 1.207 kamil _rtld_debug.r_ldbase = _rtld_objself.relocbase; 410 1.198 kamil 411 1.198 kamil ehdr = (Elf_Ehdr *)mapbase; 412 1.198 kamil _rtld_objself.phdr = (Elf_Phdr *)((char *)mapbase + ehdr->e_phoff); 413 1.198 kamil _rtld_objself.phsize = ehdr->e_phnum * sizeof(_rtld_objself.phdr[0]); 414 1.216 martin 415 1.216 martin __libc_atomic_init(); 416 1.1 cgd } 417 1.14 pk 418 1.1 cgd /* 419 1.1 cgd * Cleanup procedure. It will be called (by the atexit() mechanism) just 420 1.1 cgd * before the process exits. 421 1.1 cgd */ 422 1.1 cgd static void 423 1.98 skrll _rtld_exit(void) 424 1.1 cgd { 425 1.148 joerg sigset_t mask; 426 1.148 joerg 427 1.15 christos dbg(("rtld_exit()")); 428 1.1 cgd 429 1.148 joerg _rtld_exclusive_enter(&mask); 430 1.145 joerg 431 1.148 joerg _rtld_call_fini_functions(&mask, 1); 432 1.145 joerg 433 1.148 joerg _rtld_exclusive_exit(&mask); 434 1.1 cgd } 435 1.14 pk 436 1.156 joerg __dso_public void * 437 1.156 joerg _dlauxinfo(void) 438 1.156 joerg { 439 1.156 joerg return auxinfo; 440 1.156 joerg } 441 1.156 joerg 442 1.1 cgd /* 443 1.1 cgd * Main entry point for dynamic linking. The argument is the stack 444 1.1 cgd * pointer. The stack is expected to be laid out as described in the 445 1.1 cgd * SVR4 ABI specification, Intel 386 Processor Supplement. Specifically, 446 1.1 cgd * the stack pointer points to a word containing ARGC. Following that 447 1.1 cgd * in the stack is a null-terminated sequence of pointers to argument 448 1.1 cgd * strings. Then comes a null-terminated sequence of pointers to 449 1.1 cgd * environment strings. Finally, there is a sequence of "auxiliary 450 1.1 cgd * vector" entries. 451 1.1 cgd * 452 1.17 kleink * This function returns the entry point for the main program, the dynamic 453 1.17 kleink * linker's exit procedure in sp[0], and a pointer to the main object in 454 1.17 kleink * sp[1]. 455 1.1 cgd */ 456 1.1 cgd Elf_Addr 457 1.98 skrll _rtld(Elf_Addr *sp, Elf_Addr relocbase) 458 1.1 cgd { 459 1.15 christos const AuxInfo *pAUX_base, *pAUX_entry, *pAUX_execfd, *pAUX_phdr, 460 1.53 christos *pAUX_phent, *pAUX_phnum, *pAUX_euid, *pAUX_egid, 461 1.53 christos *pAUX_ruid, *pAUX_rgid; 462 1.18 ws const AuxInfo *pAUX_pagesz; 463 1.134 joerg char **env, **oenvp; 464 1.15 christos const AuxInfo *auxp; 465 1.139 joerg Obj_Entry *obj; 466 1.39 mycroft Elf_Addr *const osp = sp; 467 1.15 christos bool bind_now = 0; 468 1.134 joerg const char *ld_bind_now, *ld_preload, *ld_library_path; 469 1.15 christos const char **argv; 470 1.218 christos const char *execname, *objmain_name; 471 1.40 mycroft long argc; 472 1.31 erh const char **real___progname; 473 1.34 christos const Obj_Entry **real___mainprog_obj; 474 1.31 erh char ***real_environ; 475 1.148 joerg sigset_t mask; 476 1.134 joerg #ifdef DEBUG 477 1.138 pooka const char *ld_debug; 478 1.138 pooka #endif 479 1.138 pooka #ifdef RTLD_DEBUG 480 1.117 ad int i = 0; 481 1.12 christos #endif 482 1.1 cgd 483 1.15 christos /* 484 1.15 christos * On entry, the dynamic linker itself has not been relocated yet. 485 1.15 christos * Be very careful not to reference any global data until after 486 1.15 christos * _rtld_init has returned. It is OK to reference file-scope statics 487 1.15 christos * and string constants, and to call static and global functions. 488 1.15 christos */ 489 1.15 christos /* Find the auxiliary vector on the stack. */ 490 1.15 christos /* first Elf_Word reserved to address of exit routine */ 491 1.60 mycroft #if defined(RTLD_DEBUG) 492 1.75 mycroft debug = 1; 493 1.88 fvdl dbg(("sp = %p, argc = %ld, argv = %p <%s> relocbase %p", sp, 494 1.88 fvdl (long)sp[2], &sp[3], (char *) sp[3], (void *)relocbase)); 495 1.164 skrll #ifndef __x86_64__ 496 1.75 mycroft dbg(("got is at %p, dynamic is at %p", _GLOBAL_OFFSET_TABLE_, 497 1.75 mycroft &_DYNAMIC)); 498 1.152 christos #endif 499 1.162 matt #endif 500 1.1 cgd 501 1.15 christos sp += 2; /* skip over return argument space */ 502 1.15 christos argv = (const char **) &sp[1]; 503 1.40 mycroft argc = *(long *)sp; 504 1.39 mycroft sp += 2 + argc; /* Skip over argc, arguments, and NULL 505 1.15 christos * terminator */ 506 1.15 christos env = (char **) sp; 507 1.15 christos while (*sp++ != 0) { /* Skip over environment, and NULL terminator */ 508 1.60 mycroft #if defined(RTLD_DEBUG) 509 1.71 junyoung dbg(("env[%d] = %p %s", i++, (void *)sp[-1], (char *)sp[-1])); 510 1.1 cgd #endif 511 1.15 christos } 512 1.156 joerg auxinfo = (AuxInfo *) sp; 513 1.1 cgd 514 1.15 christos pAUX_base = pAUX_entry = pAUX_execfd = NULL; 515 1.15 christos pAUX_phdr = pAUX_phent = pAUX_phnum = NULL; 516 1.53 christos pAUX_euid = pAUX_ruid = pAUX_egid = pAUX_rgid = NULL; 517 1.18 ws pAUX_pagesz = NULL; 518 1.44 pk 519 1.114 christos execname = NULL; 520 1.114 christos 521 1.69 mycroft /* Digest the auxiliary vector. */ 522 1.156 joerg for (auxp = auxinfo; auxp->a_type != AT_NULL; ++auxp) { 523 1.24 kleink switch (auxp->a_type) { 524 1.24 kleink case AT_BASE: 525 1.15 christos pAUX_base = auxp; 526 1.15 christos break; 527 1.24 kleink case AT_ENTRY: 528 1.15 christos pAUX_entry = auxp; 529 1.15 christos break; 530 1.24 kleink case AT_EXECFD: 531 1.15 christos pAUX_execfd = auxp; 532 1.15 christos break; 533 1.24 kleink case AT_PHDR: 534 1.15 christos pAUX_phdr = auxp; 535 1.15 christos break; 536 1.24 kleink case AT_PHENT: 537 1.15 christos pAUX_phent = auxp; 538 1.15 christos break; 539 1.24 kleink case AT_PHNUM: 540 1.15 christos pAUX_phnum = auxp; 541 1.15 christos break; 542 1.54 mycroft #ifdef AT_EUID 543 1.53 christos case AT_EUID: 544 1.53 christos pAUX_euid = auxp; 545 1.53 christos break; 546 1.53 christos case AT_RUID: 547 1.53 christos pAUX_ruid = auxp; 548 1.53 christos break; 549 1.53 christos case AT_EGID: 550 1.53 christos pAUX_egid = auxp; 551 1.53 christos break; 552 1.53 christos case AT_RGID: 553 1.53 christos pAUX_rgid = auxp; 554 1.53 christos break; 555 1.54 mycroft #endif 556 1.114 christos #ifdef AT_SUN_EXECNAME 557 1.114 christos case AT_SUN_EXECNAME: 558 1.114 christos execname = (const char *)(const void *)auxp->a_v; 559 1.114 christos break; 560 1.114 christos #endif 561 1.24 kleink case AT_PAGESZ: 562 1.18 ws pAUX_pagesz = auxp; 563 1.18 ws break; 564 1.15 christos } 565 1.15 christos } 566 1.18 ws 567 1.69 mycroft /* Initialize and relocate ourselves. */ 568 1.90 junyoung if (pAUX_base == NULL) { 569 1.90 junyoung _rtld_error("Bad pAUX_base"); 570 1.90 junyoung _rtld_die(); 571 1.90 junyoung } 572 1.69 mycroft assert(pAUX_pagesz != NULL); 573 1.24 kleink _rtld_pagesz = (int)pAUX_pagesz->a_v; 574 1.114 christos _rtld_init((caddr_t)pAUX_base->a_v, (caddr_t)relocbase, execname); 575 1.1 cgd 576 1.15 christos __progname = _rtld_objself.path; 577 1.15 christos environ = env; 578 1.1 cgd 579 1.53 christos _rtld_trust = ((pAUX_euid ? (uid_t)pAUX_euid->a_v : geteuid()) == 580 1.53 christos (pAUX_ruid ? (uid_t)pAUX_ruid->a_v : getuid())) && 581 1.53 christos ((pAUX_egid ? (gid_t)pAUX_egid->a_v : getegid()) == 582 1.53 christos (pAUX_rgid ? (gid_t)pAUX_rgid->a_v : getgid())); 583 1.1 cgd 584 1.134 joerg #ifdef DEBUG 585 1.134 joerg ld_debug = NULL; 586 1.134 joerg #endif 587 1.134 joerg ld_bind_now = NULL; 588 1.134 joerg ld_library_path = NULL; 589 1.134 joerg ld_preload = NULL; 590 1.134 joerg /* 591 1.134 joerg * Inline avoid using normal getenv/unsetenv here as the libc 592 1.134 joerg * code is quite a bit more complicated. 593 1.134 joerg */ 594 1.134 joerg for (oenvp = env; *env != NULL; ++env) { 595 1.134 joerg static const char bind_var[] = "LD_BIND_NOW="; 596 1.134 joerg static const char debug_var[] = "LD_DEBUG="; 597 1.134 joerg static const char path_var[] = "LD_LIBRARY_PATH="; 598 1.134 joerg static const char preload_var[] = "LD_PRELOAD="; 599 1.134 joerg #define LEN(x) (sizeof(x) - 1) 600 1.134 joerg 601 1.134 joerg if ((*env)[0] != 'L' || (*env)[1] != 'D') { 602 1.134 joerg /* 603 1.134 joerg * Special case to skip most entries without 604 1.134 joerg * the more expensive calls to strncmp. 605 1.134 joerg */ 606 1.134 joerg *oenvp++ = *env; 607 1.134 joerg } else if (strncmp(*env, debug_var, LEN(debug_var)) == 0) { 608 1.134 joerg if (_rtld_trust) { 609 1.134 joerg #ifdef DEBUG 610 1.134 joerg ld_debug = *env + LEN(debug_var); 611 1.134 joerg #endif 612 1.134 joerg *oenvp++ = *env; 613 1.134 joerg } 614 1.134 joerg } else if (strncmp(*env, bind_var, LEN(bind_var)) == 0) { 615 1.173 joerg if (_rtld_trust) { 616 1.173 joerg ld_bind_now = *env + LEN(bind_var); 617 1.173 joerg *oenvp++ = *env; 618 1.173 joerg } 619 1.134 joerg } else if (strncmp(*env, path_var, LEN(path_var)) == 0) { 620 1.134 joerg if (_rtld_trust) { 621 1.134 joerg ld_library_path = *env + LEN(path_var); 622 1.134 joerg *oenvp++ = *env; 623 1.134 joerg } 624 1.134 joerg } else if (strncmp(*env, preload_var, LEN(preload_var)) == 0) { 625 1.134 joerg if (_rtld_trust) { 626 1.134 joerg ld_preload = *env + LEN(preload_var); 627 1.134 joerg *oenvp++ = *env; 628 1.134 joerg } 629 1.134 joerg } else { 630 1.134 joerg *oenvp++ = *env; 631 1.134 joerg } 632 1.134 joerg #undef LEN 633 1.134 joerg } 634 1.134 joerg *oenvp++ = NULL; 635 1.134 joerg 636 1.218 christos /* 637 1.218 christos * Set the main name. Prefer the name passed by the kernel first, 638 1.218 christos * then the argument vector, and fall back to "main program" 639 1.218 christos * This way the name will be an absolute path if available. 640 1.218 christos */ 641 1.218 christos objmain_name = execname ? execname : 642 1.218 christos (argv[0] ? argv[0] : "main program"); 643 1.218 christos 644 1.15 christos if (ld_bind_now != NULL && *ld_bind_now != '\0') 645 1.15 christos bind_now = true; 646 1.15 christos if (_rtld_trust) { 647 1.6 mhitch #ifdef DEBUG 648 1.75 mycroft #ifdef RTLD_DEBUG 649 1.75 mycroft debug = 0; 650 1.75 mycroft #endif 651 1.15 christos if (ld_debug != NULL && *ld_debug != '\0') 652 1.15 christos debug = 1; 653 1.15 christos #endif 654 1.134 joerg _rtld_add_paths(execname, &_rtld_paths, ld_library_path); 655 1.111 christos } else { 656 1.218 christos // Prevent $ORIGIN expansion 657 1.115 christos execname = NULL; 658 1.15 christos } 659 1.114 christos _rtld_process_hints(execname, &_rtld_paths, &_rtld_xforms, 660 1.113 christos _PATH_LD_HINTS); 661 1.66 junyoung dbg(("dynamic linker is initialized, mapbase=%p, relocbase=%p", 662 1.58 mycroft _rtld_objself.mapbase, _rtld_objself.relocbase)); 663 1.15 christos 664 1.15 christos /* 665 1.15 christos * Load the main program, or process its program header if it is 666 1.15 christos * already loaded. 667 1.15 christos */ 668 1.15 christos if (pAUX_execfd != NULL) { /* Load the main program. */ 669 1.24 kleink int fd = pAUX_execfd->a_v; 670 1.15 christos dbg(("loading main program")); 671 1.218 christos _rtld_objmain = _rtld_map_object(objmain_name, fd, NULL); 672 1.15 christos close(fd); 673 1.15 christos if (_rtld_objmain == NULL) 674 1.15 christos _rtld_die(); 675 1.15 christos } else { /* Main program already loaded. */ 676 1.15 christos const Elf_Phdr *phdr; 677 1.15 christos int phnum; 678 1.15 christos caddr_t entry; 679 1.15 christos 680 1.15 christos dbg(("processing main program's program header")); 681 1.15 christos assert(pAUX_phdr != NULL); 682 1.24 kleink phdr = (const Elf_Phdr *) pAUX_phdr->a_v; 683 1.15 christos assert(pAUX_phnum != NULL); 684 1.24 kleink phnum = pAUX_phnum->a_v; 685 1.15 christos assert(pAUX_phent != NULL); 686 1.24 kleink assert(pAUX_phent->a_v == sizeof(Elf_Phdr)); 687 1.15 christos assert(pAUX_entry != NULL); 688 1.24 kleink entry = (caddr_t) pAUX_entry->a_v; 689 1.15 christos _rtld_objmain = _rtld_digest_phdr(phdr, phnum, entry); 690 1.218 christos _rtld_objmain->path = xstrdup(objmain_name); 691 1.89 junyoung _rtld_objmain->pathlen = strlen(_rtld_objmain->path); 692 1.15 christos } 693 1.15 christos 694 1.92 mycroft _rtld_objmain->mainprog = true; 695 1.165 skrll 696 1.25 mycroft /* 697 1.25 mycroft * Get the actual dynamic linker pathname from the executable if 698 1.25 mycroft * possible. (It should always be possible.) That ensures that 699 1.206 kamil * the debugger will find the right dynamic linker even if a 700 1.206 kamil * non-standard one is being used. 701 1.25 mycroft */ 702 1.25 mycroft if (_rtld_objmain->interp != NULL && 703 1.171 skrll strcmp(_rtld_objmain->interp, _rtld_objself.path) != 0) { 704 1.25 mycroft _rtld_objself.path = xstrdup(_rtld_objmain->interp); 705 1.171 skrll _rtld_objself.pathlen = strlen(_rtld_objself.path); 706 1.171 skrll } 707 1.66 junyoung dbg(("actual dynamic linker is %s", _rtld_objself.path)); 708 1.165 skrll 709 1.114 christos _rtld_digest_dynamic(execname, _rtld_objmain); 710 1.15 christos 711 1.84 mycroft /* Link the main program into the list of objects. */ 712 1.84 mycroft *_rtld_objtail = _rtld_objmain; 713 1.84 mycroft _rtld_objtail = &_rtld_objmain->next; 714 1.131 skrll _rtld_objcount++; 715 1.131 skrll _rtld_objloads++; 716 1.84 mycroft 717 1.15 christos _rtld_linkmap_add(_rtld_objmain); 718 1.178 christos _rtld_objself.path = xstrdup(_rtld_objself.path); 719 1.15 christos _rtld_linkmap_add(&_rtld_objself); 720 1.15 christos 721 1.15 christos ++_rtld_objmain->refcount; 722 1.84 mycroft _rtld_objmain->mainref = 1; 723 1.117 ad _rtld_objlist_push_tail(&_rtld_list_main, _rtld_objmain); 724 1.19 kleink 725 1.134 joerg if (ld_preload) { 726 1.111 christos /* 727 1.111 christos * Pre-load user-specified objects after the main program 728 1.111 christos * but before any shared object dependencies. 729 1.111 christos */ 730 1.111 christos dbg(("preloading objects")); 731 1.134 joerg if (_rtld_preload(ld_preload) == -1) 732 1.127 christos _rtld_die(); 733 1.134 joerg } 734 1.15 christos 735 1.15 christos dbg(("loading needed objects")); 736 1.137 skrll if (_rtld_load_needed_objects(_rtld_objmain, _RTLD_MAIN) == -1) 737 1.15 christos _rtld_die(); 738 1.15 christos 739 1.151 nonaka dbg(("checking for required versions")); 740 1.151 nonaka for (obj = _rtld_objlist; obj != NULL; obj = obj->next) { 741 1.151 nonaka if (_rtld_verify_object_versions(obj) == -1) 742 1.151 nonaka _rtld_die(); 743 1.151 nonaka } 744 1.151 nonaka 745 1.139 joerg #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II) 746 1.154 joerg dbg(("initializing initial Thread Local Storage offsets")); 747 1.139 joerg /* 748 1.139 joerg * All initial objects get the TLS space from the static block. 749 1.139 joerg */ 750 1.139 joerg for (obj = _rtld_objlist; obj != NULL; obj = obj->next) 751 1.139 joerg _rtld_tls_offset_allocate(obj); 752 1.139 joerg #endif 753 1.139 joerg 754 1.15 christos dbg(("relocating objects")); 755 1.81 mycroft if (_rtld_relocate_objects(_rtld_objmain, bind_now) == -1) 756 1.15 christos _rtld_die(); 757 1.15 christos 758 1.15 christos dbg(("doing copy relocations")); 759 1.60 mycroft if (_rtld_do_copy_relocations(_rtld_objmain) == -1) 760 1.15 christos _rtld_die(); 761 1.15 christos 762 1.154 joerg #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II) 763 1.154 joerg dbg(("initializing Thread Local Storage for main thread")); 764 1.154 joerg /* 765 1.154 joerg * Set up TLS area for the main thread. 766 1.154 joerg * This has to be done after all relocations are processed, 767 1.154 joerg * since .tdata may contain relocations. 768 1.154 joerg */ 769 1.154 joerg _rtld_tls_initial_allocation(); 770 1.154 joerg #endif 771 1.154 joerg 772 1.31 erh /* 773 1.34 christos * Set the __progname, environ and, __mainprog_obj before 774 1.34 christos * calling anything that might use them. 775 1.31 erh */ 776 1.31 erh real___progname = _rtld_objmain_sym("__progname"); 777 1.31 erh if (real___progname) { 778 1.64 christos if (argv[0] != NULL) { 779 1.64 christos if ((*real___progname = strrchr(argv[0], '/')) == NULL) 780 1.64 christos (*real___progname) = argv[0]; 781 1.64 christos else 782 1.64 christos (*real___progname)++; 783 1.64 christos } else { 784 1.64 christos (*real___progname) = NULL; 785 1.64 christos } 786 1.31 erh } 787 1.31 erh real_environ = _rtld_objmain_sym("environ"); 788 1.31 erh if (real_environ) 789 1.31 erh *real_environ = environ; 790 1.99 skrll /* 791 1.99 skrll * Set __mainprog_obj for old binaries. 792 1.99 skrll */ 793 1.34 christos real___mainprog_obj = _rtld_objmain_sym("__mainprog_obj"); 794 1.34 christos if (real___mainprog_obj) 795 1.34 christos *real___mainprog_obj = _rtld_objmain; 796 1.31 erh 797 1.206 kamil _rtld_debug_state(); /* say hello to the debugger! */ 798 1.184 joerg 799 1.148 joerg _rtld_exclusive_enter(&mask); 800 1.141 joerg 801 1.15 christos dbg(("calling _init functions")); 802 1.148 joerg _rtld_call_init_functions(&mask); 803 1.15 christos 804 1.15 christos dbg(("control at program entry point = %p, obj = %p, exit = %p", 805 1.15 christos _rtld_objmain->entry, _rtld_objmain, _rtld_exit)); 806 1.15 christos 807 1.148 joerg _rtld_exclusive_exit(&mask); 808 1.141 joerg 809 1.219 riastrad #ifdef GNU_RELRO 810 1.219 riastrad /* 811 1.219 riastrad * If the main program is lazily bound (default -- whether or 812 1.219 riastrad * not LD_BINDNOW is set in the calling environment), its RELRO 813 1.219 riastrad * region has already been mapped read-only in 814 1.219 riastrad * _rtld_do_copy_relocations. The ifunc resolutions lie 815 1.219 riastrad * outside this region, so future lazy ifunc resolution is 816 1.219 riastrad * unaffected by the RELRO region's being read-only. 817 1.219 riastrad * 818 1.219 riastrad * If the main program is eagerly bound (i.e., the object has 819 1.219 riastrad * DF_1_NOW set in DT_FLAGS_1, whether or not LD_BIND_NOW is 820 1.219 riastrad * set in the calling environment), we deferred that from 821 1.219 riastrad * _rtld_do_copy_relocations so that the ifunc resolution, we 822 1.219 riastrad * have now resolved all ifuncs in it, so we can commit the 823 1.219 riastrad * RELRO region to be read-only -- and that means ifunc 824 1.219 riastrad * resolutions are read-only too. 825 1.219 riastrad */ 826 1.219 riastrad if (_rtld_objmain->z_now && _rtld_relro(_rtld_objmain, true) == -1) 827 1.220 riastrad _rtld_die(); 828 1.219 riastrad #endif 829 1.219 riastrad 830 1.15 christos /* 831 1.15 christos * Return with the entry point and the exit procedure in at the top 832 1.15 christos * of stack. 833 1.15 christos */ 834 1.15 christos 835 1.15 christos ((void **) osp)[0] = _rtld_exit; 836 1.193 joerg ((void **) osp)[1] = __UNCONST(_rtld_compat_obj); 837 1.15 christos return (Elf_Addr) _rtld_objmain->entry; 838 1.1 cgd } 839 1.1 cgd 840 1.1 cgd void 841 1.98 skrll _rtld_die(void) 842 1.1 cgd { 843 1.99 skrll const char *msg = dlerror(); 844 1.1 cgd 845 1.15 christos if (msg == NULL) 846 1.15 christos msg = "Fatal error"; 847 1.52 soren xerrx(1, "%s", msg); 848 1.1 cgd } 849 1.1 cgd 850 1.1 cgd static Obj_Entry * 851 1.98 skrll _rtld_dlcheck(void *handle) 852 1.1 cgd { 853 1.15 christos Obj_Entry *obj; 854 1.1 cgd 855 1.15 christos for (obj = _rtld_objlist; obj != NULL; obj = obj->next) 856 1.15 christos if (obj == (Obj_Entry *) handle) 857 1.15 christos break; 858 1.15 christos 859 1.15 christos if (obj == NULL || obj->dl_refcount == 0) { 860 1.159 riastrad _rtld_error("Invalid shared object handle %p", handle); 861 1.15 christos return NULL; 862 1.15 christos } 863 1.15 christos return obj; 864 1.1 cgd } 865 1.1 cgd 866 1.1 cgd static void 867 1.117 ad _rtld_initlist_visit(Objlist* list, Obj_Entry *obj, int rev) 868 1.117 ad { 869 1.117 ad Needed_Entry* elm; 870 1.117 ad 871 1.117 ad /* dbg(("_rtld_initlist_visit(%s)", obj->path)); */ 872 1.117 ad 873 1.117 ad if (obj->init_done) 874 1.117 ad return; 875 1.117 ad obj->init_done = 1; 876 1.117 ad 877 1.117 ad for (elm = obj->needed; elm != NULL; elm = elm->next) { 878 1.117 ad if (elm->obj != NULL) { 879 1.117 ad _rtld_initlist_visit(list, elm->obj, rev); 880 1.117 ad } 881 1.117 ad } 882 1.117 ad 883 1.117 ad if (rev) { 884 1.117 ad _rtld_objlist_push_head(list, obj); 885 1.117 ad } else { 886 1.117 ad _rtld_objlist_push_tail(list, obj); 887 1.117 ad } 888 1.117 ad } 889 1.117 ad 890 1.117 ad static void 891 1.117 ad _rtld_initlist_tsort(Objlist* list, int rev) 892 1.117 ad { 893 1.117 ad dbg(("_rtld_initlist_tsort")); 894 1.117 ad 895 1.117 ad Obj_Entry* obj; 896 1.117 ad 897 1.194 christos /* 898 1.194 christos * We don't include objmain here (starting from next) 899 1.194 christos * because csu handles it 900 1.194 christos */ 901 1.117 ad for (obj = _rtld_objlist->next; obj; obj = obj->next) { 902 1.117 ad obj->init_done = 0; 903 1.117 ad } 904 1.117 ad 905 1.117 ad for (obj = _rtld_objlist->next; obj; obj = obj->next) { 906 1.117 ad _rtld_initlist_visit(list, obj, rev); 907 1.117 ad } 908 1.117 ad } 909 1.117 ad 910 1.117 ad static void 911 1.98 skrll _rtld_init_dag(Obj_Entry *root) 912 1.25 mycroft { 913 1.94 simonb 914 1.25 mycroft _rtld_init_dag1(root, root); 915 1.25 mycroft } 916 1.25 mycroft 917 1.25 mycroft static void 918 1.98 skrll _rtld_init_dag1(Obj_Entry *root, Obj_Entry *obj) 919 1.25 mycroft { 920 1.25 mycroft const Needed_Entry *needed; 921 1.25 mycroft 922 1.84 mycroft if (!obj->mainref) { 923 1.84 mycroft if (_rtld_objlist_find(&obj->dldags, root)) 924 1.84 mycroft return; 925 1.133 skrll dbg(("add %p (%s) to %p (%s) DAG", obj, obj->path, root, 926 1.84 mycroft root->path)); 927 1.117 ad _rtld_objlist_push_tail(&obj->dldags, root); 928 1.117 ad _rtld_objlist_push_tail(&root->dagmembers, obj); 929 1.84 mycroft } 930 1.25 mycroft for (needed = obj->needed; needed != NULL; needed = needed->next) 931 1.25 mycroft if (needed->obj != NULL) 932 1.25 mycroft _rtld_init_dag1(root, needed->obj); 933 1.25 mycroft } 934 1.25 mycroft 935 1.25 mycroft /* 936 1.25 mycroft * Note, this is called only for objects loaded by dlopen(). 937 1.25 mycroft */ 938 1.25 mycroft static void 939 1.148 joerg _rtld_unload_object(sigset_t *mask, Obj_Entry *root, bool do_fini_funcs) 940 1.25 mycroft { 941 1.94 simonb 942 1.25 mycroft _rtld_unref_dag(root); 943 1.25 mycroft if (root->refcount == 0) { /* We are finished with some objects. */ 944 1.25 mycroft Obj_Entry *obj; 945 1.25 mycroft Obj_Entry **linkp; 946 1.25 mycroft Objlist_Entry *elm; 947 1.25 mycroft 948 1.25 mycroft /* Finalize objects that are about to be unmapped. */ 949 1.25 mycroft if (do_fini_funcs) 950 1.148 joerg _rtld_call_fini_functions(mask, 0); 951 1.25 mycroft 952 1.25 mycroft /* Remove the DAG from all objects' DAG lists. */ 953 1.50 lukem SIMPLEQ_FOREACH(elm, &root->dagmembers, link) 954 1.25 mycroft _rtld_objlist_remove(&elm->obj->dldags, root); 955 1.25 mycroft 956 1.25 mycroft /* Remove the DAG from the RTLD_GLOBAL list. */ 957 1.84 mycroft if (root->globalref) { 958 1.84 mycroft root->globalref = 0; 959 1.84 mycroft _rtld_objlist_remove(&_rtld_list_global, root); 960 1.84 mycroft } 961 1.25 mycroft 962 1.25 mycroft /* Unmap all objects that are no longer referenced. */ 963 1.25 mycroft linkp = &_rtld_objlist->next; 964 1.25 mycroft while ((obj = *linkp) != NULL) { 965 1.25 mycroft if (obj->refcount == 0) { 966 1.25 mycroft dbg(("unloading \"%s\"", obj->path)); 967 1.118 ad if (obj->ehdr != MAP_FAILED) 968 1.118 ad munmap(obj->ehdr, _rtld_pagesz); 969 1.25 mycroft munmap(obj->mapbase, obj->mapsize); 970 1.45 christos _rtld_objlist_remove(&_rtld_list_global, obj); 971 1.25 mycroft _rtld_linkmap_delete(obj); 972 1.25 mycroft *linkp = obj->next; 973 1.129 roy _rtld_objcount--; 974 1.25 mycroft _rtld_obj_free(obj); 975 1.25 mycroft } else 976 1.25 mycroft linkp = &obj->next; 977 1.25 mycroft } 978 1.25 mycroft _rtld_objtail = linkp; 979 1.25 mycroft } 980 1.25 mycroft } 981 1.25 mycroft 982 1.137 skrll void 983 1.137 skrll _rtld_ref_dag(Obj_Entry *root) 984 1.137 skrll { 985 1.137 skrll const Needed_Entry *needed; 986 1.137 skrll 987 1.137 skrll assert(root); 988 1.137 skrll 989 1.137 skrll ++root->refcount; 990 1.137 skrll 991 1.137 skrll dbg(("incremented reference on \"%s\" (%d)", root->path, 992 1.137 skrll root->refcount)); 993 1.137 skrll for (needed = root->needed; needed != NULL; 994 1.137 skrll needed = needed->next) { 995 1.137 skrll if (needed->obj != NULL) 996 1.137 skrll _rtld_ref_dag(needed->obj); 997 1.137 skrll } 998 1.137 skrll } 999 1.137 skrll 1000 1.25 mycroft static void 1001 1.98 skrll _rtld_unref_dag(Obj_Entry *root) 1002 1.1 cgd { 1003 1.94 simonb 1004 1.33 jdolecek assert(root); 1005 1.15 christos assert(root->refcount != 0); 1006 1.137 skrll 1007 1.15 christos --root->refcount; 1008 1.137 skrll dbg(("decremented reference on \"%s\" (%d)", root->path, 1009 1.137 skrll root->refcount)); 1010 1.137 skrll 1011 1.15 christos if (root->refcount == 0) { 1012 1.15 christos const Needed_Entry *needed; 1013 1.15 christos 1014 1.15 christos for (needed = root->needed; needed != NULL; 1015 1.32 jdolecek needed = needed->next) { 1016 1.32 jdolecek if (needed->obj != NULL) 1017 1.32 jdolecek _rtld_unref_dag(needed->obj); 1018 1.32 jdolecek } 1019 1.15 christos } 1020 1.1 cgd } 1021 1.1 cgd 1022 1.106 thorpej __strong_alias(__dlclose,dlclose) 1023 1.1 cgd int 1024 1.99 skrll dlclose(void *handle) 1025 1.1 cgd { 1026 1.143 joerg Obj_Entry *root; 1027 1.148 joerg sigset_t mask; 1028 1.1 cgd 1029 1.144 joerg dbg(("dlclose of %p", handle)); 1030 1.143 joerg 1031 1.148 joerg _rtld_exclusive_enter(&mask); 1032 1.143 joerg 1033 1.143 joerg root = _rtld_dlcheck(handle); 1034 1.143 joerg 1035 1.143 joerg if (root == NULL) { 1036 1.148 joerg _rtld_exclusive_exit(&mask); 1037 1.15 christos return -1; 1038 1.143 joerg } 1039 1.1 cgd 1040 1.15 christos _rtld_debug.r_state = RT_DELETE; 1041 1.15 christos _rtld_debug_state(); 1042 1.15 christos 1043 1.15 christos --root->dl_refcount; 1044 1.148 joerg _rtld_unload_object(&mask, root, true); 1045 1.15 christos 1046 1.15 christos _rtld_debug.r_state = RT_CONSISTENT; 1047 1.15 christos _rtld_debug_state(); 1048 1.1 cgd 1049 1.148 joerg _rtld_exclusive_exit(&mask); 1050 1.143 joerg 1051 1.15 christos return 0; 1052 1.1 cgd } 1053 1.1 cgd 1054 1.106 thorpej __strong_alias(__dlerror,dlerror) 1055 1.1 cgd char * 1056 1.99 skrll dlerror(void) 1057 1.1 cgd { 1058 1.15 christos char *msg = error_message; 1059 1.94 simonb 1060 1.15 christos error_message = NULL; 1061 1.15 christos return msg; 1062 1.1 cgd } 1063 1.1 cgd 1064 1.106 thorpej __strong_alias(__dlopen,dlopen) 1065 1.1 cgd void * 1066 1.99 skrll dlopen(const char *name, int mode) 1067 1.15 christos { 1068 1.213 riastrad Obj_Entry **old_obj_tail; 1069 1.15 christos Obj_Entry *obj = NULL; 1070 1.137 skrll int flags = _RTLD_DLOPEN; 1071 1.137 skrll bool nodelete; 1072 1.137 skrll bool now; 1073 1.148 joerg sigset_t mask; 1074 1.151 nonaka int result; 1075 1.137 skrll 1076 1.214 riastrad dbg(("dlopen of %s 0x%x", name, mode)); 1077 1.144 joerg 1078 1.148 joerg _rtld_exclusive_enter(&mask); 1079 1.141 joerg 1080 1.213 riastrad old_obj_tail = _rtld_objtail; 1081 1.213 riastrad 1082 1.137 skrll flags |= (mode & RTLD_GLOBAL) ? _RTLD_GLOBAL : 0; 1083 1.137 skrll flags |= (mode & RTLD_NOLOAD) ? _RTLD_NOLOAD : 0; 1084 1.165 skrll 1085 1.137 skrll nodelete = (mode & RTLD_NODELETE) ? true : false; 1086 1.137 skrll now = ((mode & RTLD_MODEMASK) == RTLD_NOW) ? true : false; 1087 1.15 christos 1088 1.15 christos _rtld_debug.r_state = RT_ADD; 1089 1.15 christos _rtld_debug_state(); 1090 1.15 christos 1091 1.15 christos if (name == NULL) { 1092 1.15 christos obj = _rtld_objmain; 1093 1.25 mycroft obj->refcount++; 1094 1.67 mycroft } else 1095 1.137 skrll obj = _rtld_load_library(name, _rtld_objmain, flags); 1096 1.137 skrll 1097 1.1 cgd 1098 1.15 christos if (obj != NULL) { 1099 1.15 christos ++obj->dl_refcount; 1100 1.15 christos if (*old_obj_tail != NULL) { /* We loaded something new. */ 1101 1.15 christos assert(*old_obj_tail == obj); 1102 1.15 christos 1103 1.151 nonaka result = _rtld_load_needed_objects(obj, flags); 1104 1.151 nonaka if (result != -1) { 1105 1.151 nonaka Objlist_Entry *entry; 1106 1.151 nonaka _rtld_init_dag(obj); 1107 1.151 nonaka SIMPLEQ_FOREACH(entry, &obj->dagmembers, link) { 1108 1.151 nonaka result = _rtld_verify_object_versions(entry->obj); 1109 1.151 nonaka if (result == -1) 1110 1.151 nonaka break; 1111 1.151 nonaka } 1112 1.151 nonaka } 1113 1.151 nonaka if (result == -1 || _rtld_relocate_objects(obj, 1114 1.151 nonaka (now || obj->z_now)) == -1) { 1115 1.148 joerg _rtld_unload_object(&mask, obj, false); 1116 1.25 mycroft obj->dl_refcount--; 1117 1.15 christos obj = NULL; 1118 1.117 ad } else { 1119 1.148 joerg _rtld_call_init_functions(&mask); 1120 1.117 ad } 1121 1.15 christos } 1122 1.137 skrll if (obj != NULL) { 1123 1.137 skrll if ((nodelete || obj->z_nodelete) && !obj->ref_nodel) { 1124 1.137 skrll dbg(("dlopen obj %s nodelete", obj->path)); 1125 1.137 skrll _rtld_ref_dag(obj); 1126 1.137 skrll obj->z_nodelete = obj->ref_nodel = true; 1127 1.137 skrll } 1128 1.137 skrll } 1129 1.15 christos } 1130 1.15 christos _rtld_debug.r_state = RT_CONSISTENT; 1131 1.15 christos _rtld_debug_state(); 1132 1.1 cgd 1133 1.214 riastrad dbg(("dlopen of %s 0x%x returned %p%s%s%s", name, mode, obj, 1134 1.214 riastrad obj ? "" : " (", obj ? "" : error_message, obj ? "" : ")")); 1135 1.214 riastrad 1136 1.148 joerg _rtld_exclusive_exit(&mask); 1137 1.141 joerg 1138 1.15 christos return obj; 1139 1.31 erh } 1140 1.31 erh 1141 1.31 erh /* 1142 1.31 erh * Find a symbol in the main program. 1143 1.31 erh */ 1144 1.221 riastrad _Pragma("GCC diagnostic push") /* _rtld_donelist_init: -Wno-stack-protector */ 1145 1.221 riastrad _Pragma("GCC diagnostic ignored \"-Wstack-protector\"") 1146 1.31 erh void * 1147 1.98 skrll _rtld_objmain_sym(const char *name) 1148 1.31 erh { 1149 1.202 kamil Elf_Hash hash; 1150 1.31 erh const Elf_Sym *def; 1151 1.31 erh const Obj_Entry *obj; 1152 1.129 roy DoneList donelist; 1153 1.31 erh 1154 1.202 kamil hash.sysv = _rtld_sysv_hash(name); 1155 1.202 kamil hash.gnu = _rtld_gnu_hash(name); 1156 1.31 erh obj = _rtld_objmain; 1157 1.129 roy _rtld_donelist_init(&donelist); 1158 1.31 erh 1159 1.202 kamil def = _rtld_symlook_list(name, &hash, &_rtld_list_main, &obj, 0, 1160 1.151 nonaka NULL, &donelist); 1161 1.129 roy 1162 1.31 erh if (def != NULL) 1163 1.31 erh return obj->relocbase + def->st_value; 1164 1.136 skrll return NULL; 1165 1.1 cgd } 1166 1.221 riastrad _Pragma("GCC diagnostic pop") 1167 1.1 cgd 1168 1.208 joerg #if defined(__powerpc__) && !defined(__clang__) 1169 1.183 chs static __noinline void * 1170 1.121 macallan hackish_return_address(void) 1171 1.121 macallan { 1172 1.190 jakllsch #if __GNUC_PREREQ__(6,0) 1173 1.189 mrg #pragma GCC diagnostic push 1174 1.189 mrg #pragma GCC diagnostic ignored "-Wframe-address" 1175 1.190 jakllsch #endif 1176 1.121 macallan return __builtin_return_address(1); 1177 1.190 jakllsch #if __GNUC_PREREQ__(6,0) 1178 1.189 mrg #pragma GCC diagnostic pop 1179 1.190 jakllsch #endif 1180 1.121 macallan } 1181 1.121 macallan #endif 1182 1.121 macallan 1183 1.141 joerg #ifdef __HAVE_FUNCTION_DESCRIPTORS 1184 1.148 joerg #define lookup_mutex_enter() _rtld_exclusive_enter(&mask) 1185 1.148 joerg #define lookup_mutex_exit() _rtld_exclusive_exit(&mask) 1186 1.141 joerg #else 1187 1.141 joerg #define lookup_mutex_enter() _rtld_shared_enter() 1188 1.141 joerg #define lookup_mutex_exit() _rtld_shared_exit() 1189 1.141 joerg #endif 1190 1.141 joerg 1191 1.221 riastrad _Pragma("GCC diagnostic push") /* _rtld_donelist_init: -Wno-stack-protector */ 1192 1.221 riastrad _Pragma("GCC diagnostic ignored \"-Wstack-protector\"") 1193 1.151 nonaka static void * 1194 1.155 joerg do_dlsym(void *handle, const char *name, const Ver_Entry *ventry, void *retaddr) 1195 1.15 christos { 1196 1.25 mycroft const Obj_Entry *obj; 1197 1.202 kamil Elf_Hash hash; 1198 1.25 mycroft const Elf_Sym *def; 1199 1.15 christos const Obj_Entry *defobj; 1200 1.148 joerg DoneList donelist; 1201 1.151 nonaka const u_int flags = SYMLOOK_DLSYM | SYMLOOK_IN_PLT; 1202 1.148 joerg #ifdef __HAVE_FUNCTION_DESCRIPTORS 1203 1.148 joerg sigset_t mask; 1204 1.148 joerg #endif 1205 1.141 joerg 1206 1.141 joerg lookup_mutex_enter(); 1207 1.141 joerg 1208 1.202 kamil hash.sysv = _rtld_sysv_hash(name); 1209 1.202 kamil hash.gnu = _rtld_gnu_hash(name); 1210 1.92 mycroft def = NULL; 1211 1.92 mycroft defobj = NULL; 1212 1.165 skrll 1213 1.93 christos switch ((intptr_t)handle) { 1214 1.93 christos case (intptr_t)NULL: 1215 1.93 christos case (intptr_t)RTLD_NEXT: 1216 1.93 christos case (intptr_t)RTLD_DEFAULT: 1217 1.93 christos case (intptr_t)RTLD_SELF: 1218 1.30 christos if ((obj = _rtld_obj_from_addr(retaddr)) == NULL) { 1219 1.30 christos _rtld_error("Cannot determine caller's shared object"); 1220 1.141 joerg lookup_mutex_exit(); 1221 1.30 christos return NULL; 1222 1.30 christos } 1223 1.93 christos 1224 1.93 christos switch ((intptr_t)handle) { 1225 1.93 christos case (intptr_t)NULL: /* Just the caller's shared object. */ 1226 1.202 kamil def = _rtld_symlook_obj(name, &hash, obj, flags, ventry); 1227 1.92 mycroft defobj = obj; 1228 1.93 christos break; 1229 1.93 christos 1230 1.93 christos case (intptr_t)RTLD_NEXT: /* Objects after callers */ 1231 1.93 christos obj = obj->next; 1232 1.93 christos /*FALLTHROUGH*/ 1233 1.93 christos 1234 1.93 christos case (intptr_t)RTLD_SELF: /* Caller included */ 1235 1.93 christos for (; obj; obj = obj->next) { 1236 1.202 kamil if ((def = _rtld_symlook_obj(name, &hash, obj, 1237 1.151 nonaka flags, ventry)) != NULL) { 1238 1.92 mycroft defobj = obj; 1239 1.92 mycroft break; 1240 1.92 mycroft } 1241 1.92 mycroft } 1242 1.179 christos /* 1243 1.180 christos * Search the dynamic linker itself, and possibly 1244 1.180 christos * resolve the symbol from there if it is not defined 1245 1.179 christos * already or weak. This is how the application links 1246 1.181 christos * to dynamic linker services such as dlopen. 1247 1.179 christos */ 1248 1.179 christos if (!def || ELF_ST_BIND(def->st_info) == STB_WEAK) { 1249 1.179 christos const Elf_Sym *symp = _rtld_symlook_obj(name, 1250 1.202 kamil &hash, &_rtld_objself, flags, ventry); 1251 1.181 christos if (symp != NULL) { 1252 1.179 christos def = symp; 1253 1.179 christos defobj = &_rtld_objself; 1254 1.179 christos } 1255 1.179 christos } 1256 1.93 christos break; 1257 1.93 christos 1258 1.93 christos case (intptr_t)RTLD_DEFAULT: 1259 1.202 kamil def = _rtld_symlook_default(name, &hash, obj, &defobj, 1260 1.151 nonaka flags, ventry); 1261 1.93 christos break; 1262 1.93 christos 1263 1.93 christos default: 1264 1.93 christos abort(); 1265 1.92 mycroft } 1266 1.93 christos break; 1267 1.93 christos 1268 1.93 christos default: 1269 1.141 joerg if ((obj = _rtld_dlcheck(handle)) == NULL) { 1270 1.141 joerg lookup_mutex_exit(); 1271 1.30 christos return NULL; 1272 1.141 joerg } 1273 1.141 joerg 1274 1.129 roy _rtld_donelist_init(&donelist); 1275 1.129 roy 1276 1.92 mycroft if (obj->mainprog) { 1277 1.93 christos /* Search main program and all libraries loaded by it */ 1278 1.202 kamil def = _rtld_symlook_list(name, &hash, &_rtld_list_main, 1279 1.151 nonaka &defobj, flags, ventry, &donelist); 1280 1.92 mycroft } else { 1281 1.122 skrll Needed_Entry fake; 1282 1.129 roy DoneList depth; 1283 1.122 skrll 1284 1.122 skrll /* Search the object and all the libraries loaded by it. */ 1285 1.122 skrll fake.next = NULL; 1286 1.124 christos fake.obj = __UNCONST(obj); 1287 1.122 skrll fake.name = 0; 1288 1.129 roy 1289 1.129 roy _rtld_donelist_init(&depth); 1290 1.202 kamil def = _rtld_symlook_needed(name, &hash, &fake, &defobj, 1291 1.151 nonaka flags, ventry, &donelist, &depth); 1292 1.25 mycroft } 1293 1.129 roy 1294 1.93 christos break; 1295 1.30 christos } 1296 1.165 skrll 1297 1.51 fredette if (def != NULL) { 1298 1.141 joerg void *p; 1299 1.174 joerg 1300 1.174 joerg if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { 1301 1.174 joerg #ifdef __HAVE_FUNCTION_DESCRIPTORS 1302 1.174 joerg lookup_mutex_exit(); 1303 1.174 joerg _rtld_shared_enter(); 1304 1.174 joerg #endif 1305 1.174 joerg p = (void *)_rtld_resolve_ifunc(defobj, def); 1306 1.174 joerg _rtld_shared_exit(); 1307 1.174 joerg return p; 1308 1.174 joerg } 1309 1.174 joerg 1310 1.51 fredette #ifdef __HAVE_FUNCTION_DESCRIPTORS 1311 1.141 joerg if (ELF_ST_TYPE(def->st_info) == STT_FUNC) { 1312 1.142 joerg p = (void *)_rtld_function_descriptor_alloc(defobj, 1313 1.142 joerg def, 0); 1314 1.141 joerg lookup_mutex_exit(); 1315 1.141 joerg return p; 1316 1.141 joerg } 1317 1.51 fredette #endif /* __HAVE_FUNCTION_DESCRIPTORS */ 1318 1.141 joerg p = defobj->relocbase + def->st_value; 1319 1.141 joerg lookup_mutex_exit(); 1320 1.141 joerg return p; 1321 1.51 fredette } 1322 1.165 skrll 1323 1.101 mycroft _rtld_error("Undefined symbol \"%s\"", name); 1324 1.141 joerg lookup_mutex_exit(); 1325 1.92 mycroft return NULL; 1326 1.25 mycroft } 1327 1.221 riastrad _Pragma("GCC diagnostic pop") 1328 1.1 cgd 1329 1.151 nonaka __strong_alias(__dlsym,dlsym) 1330 1.151 nonaka void * 1331 1.151 nonaka dlsym(void *handle, const char *name) 1332 1.151 nonaka { 1333 1.155 joerg void *retaddr; 1334 1.151 nonaka 1335 1.151 nonaka dbg(("dlsym of %s in %p", name, handle)); 1336 1.151 nonaka 1337 1.208 joerg #if defined(__powerpc__) && !defined(__clang__) 1338 1.155 joerg retaddr = hackish_return_address(); 1339 1.155 joerg #else 1340 1.155 joerg retaddr = __builtin_return_address(0); 1341 1.155 joerg #endif 1342 1.155 joerg return do_dlsym(handle, name, NULL, retaddr); 1343 1.151 nonaka } 1344 1.151 nonaka 1345 1.151 nonaka __strong_alias(__dlvsym,dlvsym) 1346 1.151 nonaka void * 1347 1.151 nonaka dlvsym(void *handle, const char *name, const char *version) 1348 1.151 nonaka { 1349 1.151 nonaka Ver_Entry *ventry = NULL; 1350 1.151 nonaka Ver_Entry ver_entry; 1351 1.155 joerg void *retaddr; 1352 1.151 nonaka 1353 1.151 nonaka dbg(("dlvsym of %s@%s in %p", name, version ? version : NULL, handle)); 1354 1.151 nonaka 1355 1.151 nonaka if (version != NULL) { 1356 1.151 nonaka ver_entry.name = version; 1357 1.151 nonaka ver_entry.file = NULL; 1358 1.202 kamil ver_entry.hash = _rtld_sysv_hash(version); 1359 1.151 nonaka ver_entry.flags = 0; 1360 1.151 nonaka ventry = &ver_entry; 1361 1.151 nonaka } 1362 1.208 joerg #if defined(__powerpc__) && !defined(__clang__) 1363 1.155 joerg retaddr = hackish_return_address(); 1364 1.155 joerg #else 1365 1.155 joerg retaddr = __builtin_return_address(0); 1366 1.155 joerg #endif 1367 1.155 joerg return do_dlsym(handle, name, ventry, retaddr); 1368 1.151 nonaka } 1369 1.151 nonaka 1370 1.106 thorpej __strong_alias(__dladdr,dladdr) 1371 1.25 mycroft int 1372 1.99 skrll dladdr(const void *addr, Dl_info *info) 1373 1.25 mycroft { 1374 1.25 mycroft const Obj_Entry *obj; 1375 1.51 fredette const Elf_Sym *def, *best_def; 1376 1.25 mycroft void *symbol_addr; 1377 1.25 mycroft unsigned long symoffset; 1378 1.149 joerg #ifdef __HAVE_FUNCTION_DESCRIPTORS 1379 1.149 joerg sigset_t mask; 1380 1.149 joerg #endif 1381 1.141 joerg 1382 1.144 joerg dbg(("dladdr of %p", addr)); 1383 1.144 joerg 1384 1.141 joerg lookup_mutex_enter(); 1385 1.141 joerg 1386 1.51 fredette #ifdef __HAVE_FUNCTION_DESCRIPTORS 1387 1.51 fredette addr = _rtld_function_descriptor_function(addr); 1388 1.51 fredette #endif /* __HAVE_FUNCTION_DESCRIPTORS */ 1389 1.51 fredette 1390 1.25 mycroft obj = _rtld_obj_from_addr(addr); 1391 1.25 mycroft if (obj == NULL) { 1392 1.25 mycroft _rtld_error("No shared object contains address"); 1393 1.176 joerg lookup_mutex_exit(); 1394 1.25 mycroft return 0; 1395 1.25 mycroft } 1396 1.25 mycroft info->dli_fname = obj->path; 1397 1.25 mycroft info->dli_fbase = obj->mapbase; 1398 1.25 mycroft info->dli_saddr = (void *)0; 1399 1.25 mycroft info->dli_sname = NULL; 1400 1.165 skrll 1401 1.15 christos /* 1402 1.25 mycroft * Walk the symbol list looking for the symbol whose address is 1403 1.25 mycroft * closest to the address sent in. 1404 1.25 mycroft */ 1405 1.51 fredette best_def = NULL; 1406 1.25 mycroft for (symoffset = 0; symoffset < obj->nchains; symoffset++) { 1407 1.25 mycroft def = obj->symtab + symoffset; 1408 1.25 mycroft 1409 1.25 mycroft /* 1410 1.25 mycroft * For skip the symbol if st_shndx is either SHN_UNDEF or 1411 1.25 mycroft * SHN_COMMON. 1412 1.25 mycroft */ 1413 1.25 mycroft if (def->st_shndx == SHN_UNDEF || def->st_shndx == SHN_COMMON) 1414 1.25 mycroft continue; 1415 1.25 mycroft 1416 1.25 mycroft /* 1417 1.25 mycroft * If the symbol is greater than the specified address, or if it 1418 1.25 mycroft * is further away from addr than the current nearest symbol, 1419 1.25 mycroft * then reject it. 1420 1.25 mycroft */ 1421 1.25 mycroft symbol_addr = obj->relocbase + def->st_value; 1422 1.25 mycroft if (symbol_addr > addr || symbol_addr < info->dli_saddr) 1423 1.25 mycroft continue; 1424 1.25 mycroft 1425 1.25 mycroft /* Update our idea of the nearest symbol. */ 1426 1.25 mycroft info->dli_sname = obj->strtab + def->st_name; 1427 1.25 mycroft info->dli_saddr = symbol_addr; 1428 1.51 fredette best_def = def; 1429 1.1 cgd 1430 1.170 christos 1431 1.25 mycroft /* Exact match? */ 1432 1.25 mycroft if (info->dli_saddr == addr) 1433 1.25 mycroft break; 1434 1.25 mycroft } 1435 1.51 fredette 1436 1.51 fredette #ifdef __HAVE_FUNCTION_DESCRIPTORS 1437 1.51 fredette if (best_def != NULL && ELF_ST_TYPE(best_def->st_info) == STT_FUNC) 1438 1.165 skrll info->dli_saddr = (void *)_rtld_function_descriptor_alloc(obj, 1439 1.51 fredette best_def, 0); 1440 1.170 christos #else 1441 1.170 christos __USE(best_def); 1442 1.51 fredette #endif /* __HAVE_FUNCTION_DESCRIPTORS */ 1443 1.51 fredette 1444 1.141 joerg lookup_mutex_exit(); 1445 1.25 mycroft return 1; 1446 1.1 cgd } 1447 1.1 cgd 1448 1.125 pooka __strong_alias(__dlinfo,dlinfo) 1449 1.125 pooka int 1450 1.125 pooka dlinfo(void *handle, int req, void *v) 1451 1.125 pooka { 1452 1.125 pooka const Obj_Entry *obj; 1453 1.125 pooka void *retaddr; 1454 1.125 pooka 1455 1.144 joerg dbg(("dlinfo for %p %d", handle, req)); 1456 1.144 joerg 1457 1.141 joerg _rtld_shared_enter(); 1458 1.141 joerg 1459 1.125 pooka if (handle == RTLD_SELF) { 1460 1.208 joerg #if defined(__powerpc__) && !defined(__clang__) 1461 1.125 pooka retaddr = hackish_return_address(); 1462 1.125 pooka #else 1463 1.125 pooka retaddr = __builtin_return_address(0); 1464 1.125 pooka #endif 1465 1.125 pooka if ((obj = _rtld_obj_from_addr(retaddr)) == NULL) { 1466 1.125 pooka _rtld_error("Cannot determine caller's shared object"); 1467 1.141 joerg _rtld_shared_exit(); 1468 1.125 pooka return -1; 1469 1.125 pooka } 1470 1.125 pooka } else { 1471 1.125 pooka if ((obj = _rtld_dlcheck(handle)) == NULL) { 1472 1.141 joerg _rtld_shared_exit(); 1473 1.125 pooka return -1; 1474 1.125 pooka } 1475 1.125 pooka } 1476 1.125 pooka 1477 1.125 pooka switch (req) { 1478 1.125 pooka case RTLD_DI_LINKMAP: 1479 1.125 pooka { 1480 1.125 pooka const struct link_map **map = v; 1481 1.125 pooka 1482 1.125 pooka *map = &obj->linkmap; 1483 1.125 pooka break; 1484 1.125 pooka } 1485 1.125 pooka 1486 1.125 pooka default: 1487 1.125 pooka _rtld_error("Invalid request"); 1488 1.141 joerg _rtld_shared_exit(); 1489 1.125 pooka return -1; 1490 1.125 pooka } 1491 1.125 pooka 1492 1.141 joerg _rtld_shared_exit(); 1493 1.125 pooka return 0; 1494 1.125 pooka } 1495 1.125 pooka 1496 1.198 kamil static void 1497 1.198 kamil _rtld_fill_dl_phdr_info(const Obj_Entry *obj, struct dl_phdr_info *phdr_info) 1498 1.198 kamil { 1499 1.198 kamil 1500 1.198 kamil phdr_info->dlpi_addr = (Elf_Addr)obj->relocbase; 1501 1.198 kamil /* XXX: wrong but not fixing it yet */ 1502 1.198 kamil phdr_info->dlpi_name = obj->path; 1503 1.198 kamil phdr_info->dlpi_phdr = obj->phdr; 1504 1.198 kamil phdr_info->dlpi_phnum = obj->phsize / sizeof(obj->phdr[0]); 1505 1.198 kamil #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II) 1506 1.198 kamil phdr_info->dlpi_tls_modid = obj->tlsindex; 1507 1.198 kamil phdr_info->dlpi_tls_data = obj->tlsinit; 1508 1.198 kamil #else 1509 1.198 kamil phdr_info->dlpi_tls_modid = 0; 1510 1.198 kamil phdr_info->dlpi_tls_data = 0; 1511 1.198 kamil #endif 1512 1.198 kamil phdr_info->dlpi_adds = _rtld_objloads; 1513 1.198 kamil phdr_info->dlpi_subs = _rtld_objloads - _rtld_objcount; 1514 1.198 kamil } 1515 1.198 kamil 1516 1.131 skrll __strong_alias(__dl_iterate_phdr,dl_iterate_phdr); 1517 1.131 skrll int 1518 1.131 skrll dl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *), void *param) 1519 1.131 skrll { 1520 1.131 skrll struct dl_phdr_info phdr_info; 1521 1.131 skrll const Obj_Entry *obj; 1522 1.131 skrll int error = 0; 1523 1.131 skrll 1524 1.144 joerg dbg(("dl_iterate_phdr")); 1525 1.144 joerg 1526 1.141 joerg _rtld_shared_enter(); 1527 1.141 joerg 1528 1.131 skrll for (obj = _rtld_objlist; obj != NULL; obj = obj->next) { 1529 1.198 kamil _rtld_fill_dl_phdr_info(obj, &phdr_info); 1530 1.131 skrll 1531 1.141 joerg /* XXXlocking: exit point */ 1532 1.131 skrll error = callback(&phdr_info, sizeof(phdr_info), param); 1533 1.131 skrll if (error) 1534 1.131 skrll break; 1535 1.131 skrll } 1536 1.131 skrll 1537 1.198 kamil if (error == 0) { 1538 1.198 kamil _rtld_fill_dl_phdr_info(&_rtld_objself, &phdr_info); 1539 1.198 kamil 1540 1.198 kamil /* XXXlocking: exit point */ 1541 1.198 kamil error = callback(&phdr_info, sizeof(phdr_info), param); 1542 1.198 kamil } 1543 1.198 kamil 1544 1.141 joerg _rtld_shared_exit(); 1545 1.131 skrll return error; 1546 1.131 skrll } 1547 1.131 skrll 1548 1.185 joerg void 1549 1.185 joerg __dl_cxa_refcount(void *addr, ssize_t delta) 1550 1.185 joerg { 1551 1.185 joerg sigset_t mask; 1552 1.185 joerg Obj_Entry *obj; 1553 1.185 joerg 1554 1.185 joerg if (delta == 0) 1555 1.185 joerg return; 1556 1.185 joerg 1557 1.185 joerg dbg(("__dl_cxa_refcount of %p with %zd", addr, delta)); 1558 1.185 joerg 1559 1.185 joerg _rtld_exclusive_enter(&mask); 1560 1.185 joerg obj = _rtld_obj_from_addr(addr); 1561 1.185 joerg 1562 1.185 joerg if (obj == NULL) { 1563 1.185 joerg dbg(("__dl_cxa_refcont: address not found")); 1564 1.185 joerg _rtld_error("No shared object contains address"); 1565 1.185 joerg _rtld_exclusive_exit(&mask); 1566 1.185 joerg return; 1567 1.185 joerg } 1568 1.185 joerg if (delta > 0 && obj->cxa_refcount > SIZE_MAX - delta) 1569 1.185 joerg _rtld_error("Reference count overflow"); 1570 1.185 joerg else if (delta < 0 && obj->cxa_refcount < -1 + (size_t)-(delta + 1)) 1571 1.185 joerg _rtld_error("Reference count underflow"); 1572 1.185 joerg else { 1573 1.185 joerg if (obj->cxa_refcount == 0) 1574 1.185 joerg ++obj->refcount; 1575 1.185 joerg obj->cxa_refcount += delta; 1576 1.185 joerg dbg(("new reference count: %zu", obj->cxa_refcount)); 1577 1.185 joerg if (obj->cxa_refcount == 0) { 1578 1.185 joerg --obj->refcount; 1579 1.185 joerg if (obj->refcount == 0) 1580 1.185 joerg _rtld_unload_object(&mask, obj, true); 1581 1.185 joerg } 1582 1.185 joerg } 1583 1.185 joerg 1584 1.185 joerg _rtld_exclusive_exit(&mask); 1585 1.185 joerg } 1586 1.185 joerg 1587 1.204 joerg __dso_public pid_t 1588 1.205 joerg __locked_fork(int *my_errno) 1589 1.204 joerg { 1590 1.204 joerg pid_t result; 1591 1.204 joerg 1592 1.212 riastrad _rtld_shared_enter(); 1593 1.204 joerg result = __fork(); 1594 1.205 joerg if (result == -1) 1595 1.205 joerg *my_errno = errno; 1596 1.212 riastrad _rtld_shared_exit(); 1597 1.204 joerg 1598 1.204 joerg return result; 1599 1.204 joerg } 1600 1.204 joerg 1601 1.1 cgd /* 1602 1.1 cgd * Error reporting function. Use it like printf. If formats the message 1603 1.1 cgd * into a buffer, and sets things up so that the next call to dlerror() 1604 1.1 cgd * will return the message. 1605 1.1 cgd */ 1606 1.1 cgd void 1607 1.15 christos _rtld_error(const char *fmt,...) 1608 1.1 cgd { 1609 1.15 christos static char buf[512]; 1610 1.15 christos va_list ap; 1611 1.49 wiz 1612 1.15 christos va_start(ap, fmt); 1613 1.15 christos xvsnprintf(buf, sizeof buf, fmt, ap); 1614 1.214 riastrad dbg(("%s: %s", __func__, buf)); 1615 1.15 christos error_message = buf; 1616 1.15 christos va_end(ap); 1617 1.1 cgd } 1618 1.14 pk 1619 1.1 cgd void 1620 1.98 skrll _rtld_debug_state(void) 1621 1.1 cgd { 1622 1.175 skrll #if defined(__hppa__) 1623 1.175 skrll __asm volatile("nop" ::: "memory"); 1624 1.175 skrll #endif 1625 1.94 simonb 1626 1.157 joerg /* Prevent optimizer from removing calls to this function */ 1627 1.157 joerg __insn_barrier(); 1628 1.1 cgd } 1629 1.1 cgd 1630 1.1 cgd void 1631 1.98 skrll _rtld_linkmap_add(Obj_Entry *obj) 1632 1.1 cgd { 1633 1.15 christos struct link_map *l = &obj->linkmap; 1634 1.15 christos struct link_map *prev; 1635 1.1 cgd 1636 1.15 christos obj->linkmap.l_name = obj->path; 1637 1.68 mycroft obj->linkmap.l_addr = obj->relocbase; 1638 1.15 christos obj->linkmap.l_ld = obj->dynamic; 1639 1.6 mhitch #ifdef __mips__ 1640 1.72 mycroft /* XXX This field is not standard and will be removed eventually. */ 1641 1.15 christos obj->linkmap.l_offs = obj->relocbase; 1642 1.6 mhitch #endif 1643 1.1 cgd 1644 1.15 christos if (_rtld_debug.r_map == NULL) { 1645 1.15 christos _rtld_debug.r_map = l; 1646 1.15 christos return; 1647 1.15 christos } 1648 1.109 skrll 1649 1.109 skrll /* 1650 1.109 skrll * Scan to the end of the list, but not past the entry for the 1651 1.109 skrll * dynamic linker, which we want to keep at the very end. 1652 1.109 skrll */ 1653 1.109 skrll for (prev = _rtld_debug.r_map; 1654 1.109 skrll prev->l_next != NULL && prev->l_next != &_rtld_objself.linkmap; 1655 1.109 skrll prev = prev->l_next); 1656 1.109 skrll 1657 1.15 christos l->l_prev = prev; 1658 1.109 skrll l->l_next = prev->l_next; 1659 1.109 skrll if (l->l_next != NULL) 1660 1.109 skrll l->l_next->l_prev = l; 1661 1.15 christos prev->l_next = l; 1662 1.1 cgd } 1663 1.1 cgd 1664 1.1 cgd void 1665 1.98 skrll _rtld_linkmap_delete(Obj_Entry *obj) 1666 1.1 cgd { 1667 1.15 christos struct link_map *l = &obj->linkmap; 1668 1.1 cgd 1669 1.15 christos if (l->l_prev == NULL) { 1670 1.15 christos if ((_rtld_debug.r_map = l->l_next) != NULL) 1671 1.15 christos l->l_next->l_prev = NULL; 1672 1.15 christos return; 1673 1.15 christos } 1674 1.15 christos if ((l->l_prev->l_next = l->l_next) != NULL) 1675 1.15 christos l->l_next->l_prev = l->l_prev; 1676 1.25 mycroft } 1677 1.25 mycroft 1678 1.25 mycroft static Obj_Entry * 1679 1.25 mycroft _rtld_obj_from_addr(const void *addr) 1680 1.25 mycroft { 1681 1.25 mycroft Obj_Entry *obj; 1682 1.165 skrll 1683 1.25 mycroft for (obj = _rtld_objlist; obj != NULL; obj = obj->next) { 1684 1.25 mycroft if (addr < (void *) obj->mapbase) 1685 1.25 mycroft continue; 1686 1.67 mycroft if (addr < (void *) (obj->mapbase + obj->mapsize)) 1687 1.25 mycroft return obj; 1688 1.25 mycroft } 1689 1.25 mycroft return NULL; 1690 1.25 mycroft } 1691 1.25 mycroft 1692 1.25 mycroft static void 1693 1.117 ad _rtld_objlist_clear(Objlist *list) 1694 1.117 ad { 1695 1.117 ad while (!SIMPLEQ_EMPTY(list)) { 1696 1.117 ad Objlist_Entry* elm = SIMPLEQ_FIRST(list); 1697 1.117 ad SIMPLEQ_REMOVE_HEAD(list, link); 1698 1.117 ad xfree(elm); 1699 1.117 ad } 1700 1.117 ad } 1701 1.117 ad 1702 1.117 ad static void 1703 1.98 skrll _rtld_objlist_remove(Objlist *list, Obj_Entry *obj) 1704 1.25 mycroft { 1705 1.25 mycroft Objlist_Entry *elm; 1706 1.165 skrll 1707 1.25 mycroft if ((elm = _rtld_objlist_find(list, obj)) != NULL) { 1708 1.50 lukem SIMPLEQ_REMOVE(list, elm, Struct_Objlist_Entry, link); 1709 1.116 ad xfree(elm); 1710 1.25 mycroft } 1711 1.1 cgd } 1712 1.141 joerg 1713 1.141 joerg #define RTLD_EXCLUSIVE_MASK 0x80000000U 1714 1.141 joerg static volatile unsigned int _rtld_mutex; 1715 1.141 joerg static volatile unsigned int _rtld_waiter_exclusive; 1716 1.141 joerg static volatile unsigned int _rtld_waiter_shared; 1717 1.141 joerg 1718 1.141 joerg void 1719 1.141 joerg _rtld_shared_enter(void) 1720 1.141 joerg { 1721 1.141 joerg unsigned int cur; 1722 1.141 joerg lwpid_t waiter, self = 0; 1723 1.141 joerg 1724 1.141 joerg for (;;) { 1725 1.141 joerg cur = _rtld_mutex; 1726 1.141 joerg /* 1727 1.141 joerg * First check if we are currently not exclusively locked. 1728 1.141 joerg */ 1729 1.141 joerg if ((cur & RTLD_EXCLUSIVE_MASK) == 0) { 1730 1.141 joerg /* Yes, so increment use counter */ 1731 1.141 joerg if (atomic_cas_uint(&_rtld_mutex, cur, cur + 1) != cur) 1732 1.141 joerg continue; 1733 1.211 riastrad membar_acquire(); 1734 1.141 joerg return; 1735 1.141 joerg } 1736 1.141 joerg /* 1737 1.141 joerg * Someone has an exclusive lock. Puts us on the waiter list. 1738 1.141 joerg */ 1739 1.141 joerg if (!self) 1740 1.141 joerg self = _lwp_self(); 1741 1.141 joerg if (cur == (self | RTLD_EXCLUSIVE_MASK)) { 1742 1.141 joerg if (_rtld_mutex_may_recurse) 1743 1.141 joerg return; 1744 1.200 christos _rtld_error("%s: dead lock detected", __func__); 1745 1.141 joerg _rtld_die(); 1746 1.141 joerg } 1747 1.141 joerg waiter = atomic_swap_uint(&_rtld_waiter_shared, self); 1748 1.141 joerg /* 1749 1.141 joerg * Check for race against _rtld_exclusive_exit before sleeping. 1750 1.141 joerg */ 1751 1.177 yamt membar_sync(); 1752 1.141 joerg if ((_rtld_mutex & RTLD_EXCLUSIVE_MASK) || 1753 1.141 joerg _rtld_waiter_exclusive) 1754 1.172 joerg _lwp_park(CLOCK_REALTIME, 0, NULL, 0, 1755 1.172 joerg __UNVOLATILE(&_rtld_mutex), NULL); 1756 1.141 joerg /* Try to remove us from the waiter list. */ 1757 1.141 joerg atomic_cas_uint(&_rtld_waiter_shared, self, 0); 1758 1.141 joerg if (waiter) 1759 1.141 joerg _lwp_unpark(waiter, __UNVOLATILE(&_rtld_mutex)); 1760 1.141 joerg } 1761 1.141 joerg } 1762 1.141 joerg 1763 1.141 joerg void 1764 1.141 joerg _rtld_shared_exit(void) 1765 1.141 joerg { 1766 1.141 joerg lwpid_t waiter; 1767 1.141 joerg 1768 1.141 joerg /* 1769 1.141 joerg * Shared lock taken after an exclusive lock. 1770 1.141 joerg * Just assume this is a partial recursion. 1771 1.141 joerg */ 1772 1.141 joerg if (_rtld_mutex & RTLD_EXCLUSIVE_MASK) 1773 1.141 joerg return; 1774 1.141 joerg 1775 1.141 joerg /* 1776 1.141 joerg * Wakeup LWPs waiting for an exclusive lock if this is the last 1777 1.141 joerg * LWP on the shared lock. 1778 1.141 joerg */ 1779 1.211 riastrad membar_release(); 1780 1.141 joerg if (atomic_dec_uint_nv(&_rtld_mutex)) 1781 1.141 joerg return; 1782 1.177 yamt membar_sync(); 1783 1.141 joerg if ((waiter = _rtld_waiter_exclusive) != 0) 1784 1.141 joerg _lwp_unpark(waiter, __UNVOLATILE(&_rtld_mutex)); 1785 1.141 joerg } 1786 1.141 joerg 1787 1.141 joerg void 1788 1.148 joerg _rtld_exclusive_enter(sigset_t *mask) 1789 1.141 joerg { 1790 1.141 joerg lwpid_t waiter, self = _lwp_self(); 1791 1.141 joerg unsigned int locked_value = (unsigned int)self | RTLD_EXCLUSIVE_MASK; 1792 1.141 joerg unsigned int cur; 1793 1.148 joerg sigset_t blockmask; 1794 1.148 joerg 1795 1.148 joerg sigfillset(&blockmask); 1796 1.153 christos sigdelset(&blockmask, SIGTRAP); /* Allow the debugger */ 1797 1.148 joerg sigprocmask(SIG_BLOCK, &blockmask, mask); 1798 1.141 joerg 1799 1.141 joerg for (;;) { 1800 1.177 yamt if (atomic_cas_uint(&_rtld_mutex, 0, locked_value) == 0) { 1801 1.211 riastrad membar_acquire(); 1802 1.141 joerg break; 1803 1.177 yamt } 1804 1.141 joerg waiter = atomic_swap_uint(&_rtld_waiter_exclusive, self); 1805 1.177 yamt membar_sync(); 1806 1.141 joerg cur = _rtld_mutex; 1807 1.141 joerg if (cur == locked_value) { 1808 1.200 christos _rtld_error("%s: dead lock detected", __func__); 1809 1.141 joerg _rtld_die(); 1810 1.141 joerg } 1811 1.141 joerg if (cur) 1812 1.172 joerg _lwp_park(CLOCK_REALTIME, 0, NULL, 0, 1813 1.172 joerg __UNVOLATILE(&_rtld_mutex), NULL); 1814 1.141 joerg atomic_cas_uint(&_rtld_waiter_exclusive, self, 0); 1815 1.141 joerg if (waiter) 1816 1.141 joerg _lwp_unpark(waiter, __UNVOLATILE(&_rtld_mutex)); 1817 1.141 joerg } 1818 1.141 joerg } 1819 1.141 joerg 1820 1.141 joerg void 1821 1.148 joerg _rtld_exclusive_exit(sigset_t *mask) 1822 1.141 joerg { 1823 1.141 joerg lwpid_t waiter; 1824 1.141 joerg 1825 1.211 riastrad membar_release(); 1826 1.141 joerg _rtld_mutex = 0; 1827 1.177 yamt membar_sync(); 1828 1.141 joerg if ((waiter = _rtld_waiter_exclusive) != 0) 1829 1.141 joerg _lwp_unpark(waiter, __UNVOLATILE(&_rtld_mutex)); 1830 1.141 joerg 1831 1.141 joerg if ((waiter = _rtld_waiter_shared) != 0) 1832 1.141 joerg _lwp_unpark(waiter, __UNVOLATILE(&_rtld_mutex)); 1833 1.141 joerg 1834 1.148 joerg sigprocmask(SIG_SETMASK, mask, NULL); 1835 1.141 joerg } 1836 1.195 christos 1837 1.195 christos int 1838 1.195 christos _rtld_relro(const Obj_Entry *obj, bool wantmain) 1839 1.195 christos { 1840 1.195 christos #ifdef GNU_RELRO 1841 1.203 thorpej /* 1842 1.203 thorpej * If our VM page size is larger than the page size used by the 1843 1.203 thorpej * linker when laying out the object, we could end up making data 1844 1.203 thorpej * read-only that is unintended. Detect and avoid this situation. 1845 1.203 thorpej * It may mean we are unable to protect everything we'd like, but 1846 1.203 thorpej * it's better than crashing. 1847 1.203 thorpej */ 1848 1.203 thorpej uintptr_t relro_end = (uintptr_t)obj->relro_page + obj->relro_size; 1849 1.203 thorpej uintptr_t relro_start = round_down((uintptr_t)obj->relro_page); 1850 1.203 thorpej assert(relro_end >= relro_start); 1851 1.203 thorpej size_t relro_size = round_down(relro_end) - relro_start; 1852 1.203 thorpej 1853 1.203 thorpej if (relro_size == 0) 1854 1.195 christos return 0; 1855 1.195 christos if (wantmain != (obj ==_rtld_objmain)) 1856 1.195 christos return 0; 1857 1.195 christos 1858 1.203 thorpej dbg(("RELRO %s %p %zx\n", obj->path, (void *)relro_start, relro_size)); 1859 1.203 thorpej if (mprotect((void *)relro_start, relro_size, PROT_READ) == -1) { 1860 1.195 christos _rtld_error("%s: Cannot enforce relro " "protection: %s", 1861 1.195 christos obj->path, xstrerror(errno)); 1862 1.195 christos return -1; 1863 1.195 christos } 1864 1.195 christos #endif 1865 1.195 christos return 0; 1866 1.195 christos } 1867