1 1.1 mrg // ELF-specific support for sections with shared libraries. 2 1.1 mrg // Copyright (C) 2019-2022 Free Software Foundation, Inc. 3 1.1 mrg 4 1.1 mrg // GCC is free software; you can redistribute it and/or modify it under 5 1.1 mrg // the terms of the GNU General Public License as published by the Free 6 1.1 mrg // Software Foundation; either version 3, or (at your option) any later 7 1.1 mrg // version. 8 1.1 mrg 9 1.1 mrg // GCC is distributed in the hope that it will be useful, but WITHOUT ANY 10 1.1 mrg // WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 1.1 mrg // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 1.1 mrg // for more details. 13 1.1 mrg 14 1.1 mrg // Under Section 7 of GPL version 3, you are granted additional 15 1.1 mrg // permissions described in the GCC Runtime Library Exception, version 16 1.1 mrg // 3.1, as published by the Free Software Foundation. 17 1.1 mrg 18 1.1 mrg // You should have received a copy of the GNU General Public License and 19 1.1 mrg // a copy of the GCC Runtime Library Exception along with this program; 20 1.1 mrg // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 21 1.1 mrg // <http://www.gnu.org/licenses/>. 22 1.1 mrg 23 1.1 mrg module gcc.sections.elf; 24 1.1 mrg 25 1.1 mrg version (MIPS32) version = MIPS_Any; 26 1.1 mrg version (MIPS64) version = MIPS_Any; 27 1.1 mrg version (RISCV32) version = RISCV_Any; 28 1.1 mrg version (RISCV64) version = RISCV_Any; 29 1.1 mrg version (S390) version = IBMZ_Any; 30 1.1 mrg version (SystemZ) version = IBMZ_Any; 31 1.1 mrg 32 1.1 mrg version (CRuntime_Glibc) enum SharedELF = true; 33 1.1 mrg else version (CRuntime_Musl) enum SharedELF = true; 34 1.1 mrg else version (FreeBSD) enum SharedELF = true; 35 1.1 mrg else version (NetBSD) enum SharedELF = true; 36 1.1 mrg else version (OpenBSD) enum SharedELF = true; 37 1.1 mrg else version (DragonFlyBSD) enum SharedELF = true; 38 1.1 mrg else version (CRuntime_UClibc) enum SharedELF = true; 39 1.1 mrg else version (Solaris) enum SharedELF = true; 40 1.1 mrg else enum SharedELF = false; 41 1.1 mrg static if (SharedELF): 42 1.1 mrg 43 1.1 mrg import core.memory; 44 1.1 mrg import core.stdc.config; 45 1.1 mrg import core.stdc.stdio; 46 1.1 mrg import core.stdc.stdlib : calloc, exit, free, malloc, EXIT_FAILURE; 47 1.1 mrg import core.stdc.string : strlen; 48 1.1 mrg version (linux) 49 1.1 mrg { 50 1.1 mrg import core.sys.linux.dlfcn; 51 1.1 mrg import core.sys.linux.elf; 52 1.1 mrg import core.sys.linux.link; 53 1.1 mrg } 54 1.1 mrg else version (FreeBSD) 55 1.1 mrg { 56 1.1 mrg import core.sys.freebsd.dlfcn; 57 1.1 mrg import core.sys.freebsd.sys.elf; 58 1.1 mrg import core.sys.freebsd.sys.link_elf; 59 1.1 mrg } 60 1.1 mrg else version (NetBSD) 61 1.1 mrg { 62 1.1 mrg import core.sys.netbsd.dlfcn; 63 1.1 mrg import core.sys.netbsd.sys.elf; 64 1.1 mrg import core.sys.netbsd.sys.link_elf; 65 1.1 mrg } 66 1.1 mrg else version (OpenBSD) 67 1.1 mrg { 68 1.1 mrg import core.sys.openbsd.dlfcn; 69 1.1 mrg import core.sys.openbsd.sys.elf; 70 1.1 mrg import core.sys.openbsd.sys.link_elf; 71 1.1 mrg } 72 1.1 mrg else version (DragonFlyBSD) 73 1.1 mrg { 74 1.1 mrg import core.sys.dragonflybsd.dlfcn; 75 1.1 mrg import core.sys.dragonflybsd.sys.elf; 76 1.1 mrg import core.sys.dragonflybsd.sys.link_elf; 77 1.1 mrg } 78 1.1 mrg else version (Solaris) 79 1.1 mrg { 80 1.1 mrg import core.sys.solaris.dlfcn; 81 1.1 mrg import core.sys.solaris.link; 82 1.1 mrg import core.sys.solaris.sys.elf; 83 1.1 mrg import core.sys.solaris.sys.link; 84 1.1 mrg } 85 1.1 mrg else 86 1.1 mrg { 87 1.1 mrg static assert(0, "unimplemented"); 88 1.1 mrg } 89 1.1 mrg import core.sys.posix.pthread; 90 1.1 mrg import rt.deh; 91 1.1 mrg import rt.dmain2; 92 1.1 mrg import rt.minfo; 93 1.1 mrg import core.internal.container.array; 94 1.1 mrg import core.internal.container.hashtab; 95 1.1 mrg import gcc.builtins; 96 1.1 mrg import gcc.config; 97 1.1 mrg import gcc.sections.common; 98 1.1 mrg 99 1.1 mrg alias DSO SectionGroup; 100 1.1 mrg struct DSO 101 1.1 mrg { 102 1.1 mrg static int opApply(scope int delegate(ref DSO) dg) 103 1.1 mrg { 104 1.1 mrg foreach (dso; _loadedDSOs) 105 1.1 mrg { 106 1.1 mrg if (auto res = dg(*dso)) 107 1.1 mrg return res; 108 1.1 mrg } 109 1.1 mrg return 0; 110 1.1 mrg } 111 1.1 mrg 112 1.1 mrg static int opApplyReverse(scope int delegate(ref DSO) dg) 113 1.1 mrg { 114 1.1 mrg foreach_reverse (dso; _loadedDSOs) 115 1.1 mrg { 116 1.1 mrg if (auto res = dg(*dso)) 117 1.1 mrg return res; 118 1.1 mrg } 119 1.1 mrg return 0; 120 1.1 mrg } 121 1.1 mrg 122 1.1 mrg @property immutable(ModuleInfo*)[] modules() const nothrow @nogc 123 1.1 mrg { 124 1.1 mrg return _moduleGroup.modules; 125 1.1 mrg } 126 1.1 mrg 127 1.1 mrg @property ref inout(ModuleGroup) moduleGroup() inout return nothrow @nogc 128 1.1 mrg { 129 1.1 mrg return _moduleGroup; 130 1.1 mrg } 131 1.1 mrg 132 1.1 mrg @property inout(void[])[] gcRanges() inout nothrow @nogc 133 1.1 mrg { 134 1.1 mrg return _gcRanges[]; 135 1.1 mrg } 136 1.1 mrg 137 1.1 mrg private: 138 1.1 mrg 139 1.1 mrg invariant() 140 1.1 mrg { 141 1.1 mrg safeAssert(_moduleGroup.modules.length > 0, "No modules for DSO."); 142 1.1 mrg safeAssert(_tlsMod || !_tlsSize, "Inconsistent TLS fields for DSO."); 143 1.1 mrg } 144 1.1 mrg 145 1.1 mrg ModuleGroup _moduleGroup; 146 1.1 mrg Array!(void[]) _gcRanges; 147 1.1 mrg size_t _tlsMod; 148 1.1 mrg size_t _tlsSize; 149 1.1 mrg 150 1.1 mrg version (Shared) 151 1.1 mrg { 152 1.1 mrg Array!(void[]) _codeSegments; // array of code segments 153 1.1 mrg Array!(DSO*) _deps; // D libraries needed by this DSO 154 1.1 mrg void* _handle; // corresponding handle 155 1.1 mrg } 156 1.1 mrg 157 1.1 mrg // get the TLS range for the executing thread 158 1.1 mrg void[] tlsRange() const nothrow @nogc 159 1.1 mrg { 160 1.1 mrg return getTLSRange(_tlsMod, _tlsSize); 161 1.1 mrg } 162 1.1 mrg } 163 1.1 mrg 164 1.1 mrg /**** 165 1.1 mrg * Boolean flag set to true while the runtime is initialized. 166 1.1 mrg */ 167 1.1 mrg __gshared bool _isRuntimeInitialized; 168 1.1 mrg 169 1.1 mrg 170 1.1 mrg /**** 171 1.1 mrg * Gets called on program startup just before GC is initialized. 172 1.1 mrg */ 173 1.1 mrg void initSections() nothrow @nogc 174 1.1 mrg { 175 1.1 mrg _isRuntimeInitialized = true; 176 1.1 mrg } 177 1.1 mrg 178 1.1 mrg 179 1.1 mrg /*** 180 1.1 mrg * Gets called on program shutdown just after GC is terminated. 181 1.1 mrg */ 182 1.1 mrg void finiSections() nothrow @nogc 183 1.1 mrg { 184 1.1 mrg _isRuntimeInitialized = false; 185 1.1 mrg } 186 1.1 mrg 187 1.1 mrg alias ScanDG = void delegate(void* pbeg, void* pend) nothrow; 188 1.1 mrg 189 1.1 mrg version (Shared) 190 1.1 mrg { 191 1.1 mrg import gcc.sections : pinLoadedLibraries, unpinLoadedLibraries, 192 1.1 mrg inheritLoadedLibraries, cleanupLoadedLibraries; 193 1.1 mrg 194 1.1 mrg /*** 195 1.1 mrg * Called once per thread; returns array of thread local storage ranges 196 1.1 mrg */ 197 1.1 mrg Array!(ThreadDSO)* initTLSRanges() @nogc nothrow 198 1.1 mrg { 199 1.1 mrg return &_loadedDSOs(); 200 1.1 mrg } 201 1.1 mrg 202 1.1 mrg void finiTLSRanges(Array!(ThreadDSO)* tdsos) @nogc nothrow 203 1.1 mrg { 204 1.1 mrg // Nothing to do here. tdsos used to point to the _loadedDSOs instance 205 1.1 mrg // in the dying thread's TLS segment and as such is not valid anymore. 206 1.1 mrg // The memory for the array contents was already reclaimed in 207 1.1 mrg // cleanupLoadedLibraries(). 208 1.1 mrg } 209 1.1 mrg 210 1.1 mrg void scanTLSRanges(Array!(ThreadDSO)* tdsos, scope ScanDG dg) nothrow 211 1.1 mrg { 212 1.1 mrg version (GNU_EMUTLS) 213 1.1 mrg { 214 1.1 mrg import gcc.emutls; 215 1.1 mrg _d_emutls_scan(dg); 216 1.1 mrg } 217 1.1 mrg else 218 1.1 mrg { 219 1.1 mrg foreach (ref tdso; *tdsos) 220 1.1 mrg dg(tdso._tlsRange.ptr, tdso._tlsRange.ptr + tdso._tlsRange.length); 221 1.1 mrg } 222 1.1 mrg } 223 1.1 mrg 224 1.1 mrg size_t sizeOfTLS() nothrow @nogc 225 1.1 mrg { 226 1.1 mrg auto tdsos = initTLSRanges(); 227 1.1 mrg size_t sum; 228 1.1 mrg foreach (ref tdso; *tdsos) 229 1.1 mrg sum += tdso._tlsRange.length; 230 1.1 mrg return sum; 231 1.1 mrg } 232 1.1 mrg 233 1.1 mrg // interface for core.thread to inherit loaded libraries 234 1.1 mrg pragma(mangle, gcc.sections.pinLoadedLibraries.mangleof) 235 1.1 mrg void* pinLoadedLibraries() nothrow @nogc 236 1.1 mrg { 237 1.1 mrg auto res = cast(Array!(ThreadDSO)*)calloc(1, Array!(ThreadDSO).sizeof); 238 1.1 mrg res.length = _loadedDSOs.length; 239 1.1 mrg foreach (i, ref tdso; _loadedDSOs) 240 1.1 mrg { 241 1.1 mrg (*res)[i] = tdso; 242 1.1 mrg if (tdso._addCnt) 243 1.1 mrg { 244 1.1 mrg // Increment the dlopen ref for explicitly loaded libraries to pin them. 245 1.1 mrg const success = .dlopen(linkMapForHandle(tdso._pdso._handle).l_name, RTLD_LAZY) !is null; 246 1.1 mrg safeAssert(success, "Failed to increment dlopen ref."); 247 1.1 mrg (*res)[i]._addCnt = 1; // new array takes over the additional ref count 248 1.1 mrg } 249 1.1 mrg } 250 1.1 mrg return res; 251 1.1 mrg } 252 1.1 mrg 253 1.1 mrg pragma(mangle, gcc.sections.unpinLoadedLibraries.mangleof) 254 1.1 mrg void unpinLoadedLibraries(void* p) nothrow @nogc 255 1.1 mrg { 256 1.1 mrg auto pary = cast(Array!(ThreadDSO)*)p; 257 1.1 mrg // In case something failed we need to undo the pinning. 258 1.1 mrg foreach (ref tdso; *pary) 259 1.1 mrg { 260 1.1 mrg if (tdso._addCnt) 261 1.1 mrg { 262 1.1 mrg auto handle = tdso._pdso._handle; 263 1.1 mrg safeAssert(handle !is null, "Invalid library handle."); 264 1.1 mrg .dlclose(handle); 265 1.1 mrg } 266 1.1 mrg } 267 1.1 mrg pary.reset(); 268 1.1 mrg .free(pary); 269 1.1 mrg } 270 1.1 mrg 271 1.1 mrg // Called before TLS ctors are ran, copy over the loaded libraries 272 1.1 mrg // of the parent thread. 273 1.1 mrg pragma(mangle, gcc.sections.inheritLoadedLibraries.mangleof) 274 1.1 mrg void inheritLoadedLibraries(void* p) nothrow @nogc 275 1.1 mrg { 276 1.1 mrg safeAssert(_loadedDSOs.empty, "DSOs have already been registered for this thread."); 277 1.1 mrg _loadedDSOs.swap(*cast(Array!(ThreadDSO)*)p); 278 1.1 mrg .free(p); 279 1.1 mrg foreach (ref dso; _loadedDSOs) 280 1.1 mrg { 281 1.1 mrg // the copied _tlsRange corresponds to parent thread 282 1.1 mrg dso.updateTLSRange(); 283 1.1 mrg } 284 1.1 mrg } 285 1.1 mrg 286 1.1 mrg // Called after all TLS dtors ran, decrements all remaining dlopen refs. 287 1.1 mrg pragma(mangle, gcc.sections.cleanupLoadedLibraries.mangleof) 288 1.1 mrg void cleanupLoadedLibraries() nothrow @nogc 289 1.1 mrg { 290 1.1 mrg foreach (ref tdso; _loadedDSOs) 291 1.1 mrg { 292 1.1 mrg if (tdso._addCnt == 0) continue; 293 1.1 mrg 294 1.1 mrg auto handle = tdso._pdso._handle; 295 1.1 mrg safeAssert(handle !is null, "Invalid DSO handle."); 296 1.1 mrg for (; tdso._addCnt > 0; --tdso._addCnt) 297 1.1 mrg .dlclose(handle); 298 1.1 mrg } 299 1.1 mrg 300 1.1 mrg // Free the memory for the array contents. 301 1.1 mrg _loadedDSOs.reset(); 302 1.1 mrg } 303 1.1 mrg } 304 1.1 mrg else 305 1.1 mrg { 306 1.1 mrg /*** 307 1.1 mrg * Called once per thread; returns array of thread local storage ranges 308 1.1 mrg */ 309 1.1 mrg Array!(void[])* initTLSRanges() nothrow @nogc 310 1.1 mrg { 311 1.1 mrg auto rngs = &_tlsRanges(); 312 1.1 mrg if (rngs.empty) 313 1.1 mrg { 314 1.1 mrg foreach (ref pdso; _loadedDSOs) 315 1.1 mrg rngs.insertBack(pdso.tlsRange()); 316 1.1 mrg } 317 1.1 mrg return rngs; 318 1.1 mrg } 319 1.1 mrg 320 1.1 mrg void finiTLSRanges(Array!(void[])* rngs) nothrow @nogc 321 1.1 mrg { 322 1.1 mrg rngs.reset(); 323 1.1 mrg } 324 1.1 mrg 325 1.1 mrg void scanTLSRanges(Array!(void[])* rngs, scope ScanDG dg) nothrow 326 1.1 mrg { 327 1.1 mrg version (GNU_EMUTLS) 328 1.1 mrg { 329 1.1 mrg import gcc.emutls; 330 1.1 mrg _d_emutls_scan(dg); 331 1.1 mrg } 332 1.1 mrg else 333 1.1 mrg { 334 1.1 mrg foreach (rng; *rngs) 335 1.1 mrg dg(rng.ptr, rng.ptr + rng.length); 336 1.1 mrg } 337 1.1 mrg } 338 1.1 mrg 339 1.1 mrg size_t sizeOfTLS() nothrow @nogc 340 1.1 mrg { 341 1.1 mrg auto rngs = initTLSRanges(); 342 1.1 mrg size_t sum; 343 1.1 mrg foreach (rng; *rngs) 344 1.1 mrg sum += rng.length; 345 1.1 mrg return sum; 346 1.1 mrg } 347 1.1 mrg } 348 1.1 mrg 349 1.1 mrg private: 350 1.1 mrg 351 1.1 mrg version (Shared) 352 1.1 mrg { 353 1.1 mrg /* 354 1.1 mrg * Array of thread local DSO metadata for all libraries loaded and 355 1.1 mrg * initialized in this thread. 356 1.1 mrg * 357 1.1 mrg * Note: 358 1.1 mrg * A newly spawned thread will inherit these libraries. 359 1.1 mrg * Note: 360 1.1 mrg * We use an array here to preserve the order of 361 1.1 mrg * initialization. If that became a performance issue, we 362 1.1 mrg * could use a hash table and enumerate the DSOs during 363 1.1 mrg * loading so that the hash table values could be sorted when 364 1.1 mrg * necessary. 365 1.1 mrg */ 366 1.1 mrg struct ThreadDSO 367 1.1 mrg { 368 1.1 mrg DSO* _pdso; 369 1.1 mrg static if (_pdso.sizeof == 8) uint _refCnt, _addCnt; 370 1.1 mrg else static if (_pdso.sizeof == 4) ushort _refCnt, _addCnt; 371 1.1 mrg else static assert(0, "unimplemented"); 372 1.1 mrg void[] _tlsRange; 373 1.1 mrg alias _pdso this; 374 1.1 mrg // update the _tlsRange for the executing thread 375 1.1 mrg void updateTLSRange() nothrow @nogc 376 1.1 mrg { 377 1.1 mrg _tlsRange = _pdso.tlsRange(); 378 1.1 mrg } 379 1.1 mrg } 380 1.1 mrg @property ref Array!(ThreadDSO) _loadedDSOs() @nogc nothrow { static Array!(ThreadDSO) x; return x; } 381 1.1 mrg 382 1.1 mrg /* 383 1.1 mrg * Set to true during rt_loadLibrary/rt_unloadLibrary calls. 384 1.1 mrg */ 385 1.1 mrg bool _rtLoading; 386 1.1 mrg 387 1.1 mrg /* 388 1.1 mrg * Hash table to map link_map* to corresponding DSO*. 389 1.1 mrg * The hash table is protected by a Mutex. 390 1.1 mrg */ 391 1.1 mrg __gshared pthread_mutex_t _handleToDSOMutex; 392 1.1 mrg @property ref HashTab!(void*, DSO*) _handleToDSO() @nogc nothrow { __gshared HashTab!(void*, DSO*) x; return x; } 393 1.1 mrg } 394 1.1 mrg else 395 1.1 mrg { 396 1.1 mrg /* 397 1.1 mrg * Static DSOs loaded by the runtime linker. This includes the 398 1.1 mrg * executable. These can't be unloaded. 399 1.1 mrg */ 400 1.1 mrg @property ref Array!(DSO*) _loadedDSOs() @nogc nothrow { __gshared Array!(DSO*) x; return x; } 401 1.1 mrg 402 1.1 mrg /* 403 1.1 mrg * Thread local array that contains TLS memory ranges for each 404 1.1 mrg * library initialized in this thread. 405 1.1 mrg */ 406 1.1 mrg @property ref Array!(void[]) _tlsRanges() @nogc nothrow { static Array!(void[]) x; return x; } 407 1.1 mrg 408 1.1 mrg enum _rtLoading = false; 409 1.1 mrg } 410 1.1 mrg 411 1.1 mrg /////////////////////////////////////////////////////////////////////////////// 412 1.1 mrg // Compiler to runtime interface. 413 1.1 mrg /////////////////////////////////////////////////////////////////////////////// 414 1.1 mrg 415 1.1 mrg /* 416 1.1 mrg * This data structure is generated by the compiler, and then passed to 417 1.1 mrg * _d_dso_registry(). 418 1.1 mrg */ 419 1.1 mrg struct CompilerDSOData 420 1.1 mrg { 421 1.1 mrg size_t _version; // currently 1 422 1.1 mrg void** _slot; // can be used to store runtime data 423 1.1 mrg immutable(object.ModuleInfo*)* _minfo_beg, _minfo_end; // array of modules in this object file 424 1.1 mrg } 425 1.1 mrg 426 1.1 mrg T[] toRange(T)(T* beg, T* end) { return beg[0 .. end - beg]; } 427 1.1 mrg 428 1.1 mrg /* For each shared library and executable, the compiler generates code that 429 1.1 mrg * sets up CompilerDSOData and calls _d_dso_registry(). 430 1.1 mrg * A pointer to that code is inserted into both the .ctors and .dtors 431 1.1 mrg * segment so it gets called by the loader on startup and shutdown. 432 1.1 mrg */ 433 1.1 mrg extern(C) void _d_dso_registry(CompilerDSOData* data) 434 1.1 mrg { 435 1.1 mrg // only one supported currently 436 1.1 mrg safeAssert(data._version >= 1, "Incompatible compiler-generated DSO data version."); 437 1.1 mrg 438 1.1 mrg // no backlink => register 439 1.1 mrg if (*data._slot is null) 440 1.1 mrg { 441 1.1 mrg immutable firstDSO = _loadedDSOs.empty; 442 1.1 mrg if (firstDSO) initLocks(); 443 1.1 mrg 444 1.1 mrg DSO* pdso = cast(DSO*).calloc(1, DSO.sizeof); 445 1.1 mrg assert(typeid(DSO).initializer().ptr is null); 446 1.1 mrg *data._slot = pdso; // store backlink in library record 447 1.1 mrg 448 1.1 mrg pdso._moduleGroup = ModuleGroup(toRange(data._minfo_beg, data._minfo_end)); 449 1.1 mrg 450 1.1 mrg dl_phdr_info info = void; 451 1.1 mrg const headerFound = findDSOInfoForAddr(data._slot, &info); 452 1.1 mrg safeAssert(headerFound, "Failed to find image header."); 453 1.1 mrg 454 1.1 mrg scanSegments(info, pdso); 455 1.1 mrg 456 1.1 mrg version (Shared) 457 1.1 mrg { 458 1.1 mrg auto handle = handleForAddr(data._slot); 459 1.1 mrg 460 1.1 mrg getDependencies(info, pdso._deps); 461 1.1 mrg pdso._handle = handle; 462 1.1 mrg setDSOForHandle(pdso, pdso._handle); 463 1.1 mrg 464 1.1 mrg if (!_rtLoading) 465 1.1 mrg { 466 1.1 mrg /* This DSO was not loaded by rt_loadLibrary which 467 1.1 mrg * happens for all dependencies of an executable or 468 1.1 mrg * the first dlopen call from a C program. 469 1.1 mrg * In this case we add the DSO to the _loadedDSOs of this 470 1.1 mrg * thread with a refCnt of 1 and call the TlsCtors. 471 1.1 mrg */ 472 1.1 mrg immutable ushort refCnt = 1, addCnt = 0; 473 1.1 mrg _loadedDSOs.insertBack(ThreadDSO(pdso, refCnt, addCnt, pdso.tlsRange())); 474 1.1 mrg } 475 1.1 mrg } 476 1.1 mrg else 477 1.1 mrg { 478 1.1 mrg foreach (p; _loadedDSOs) 479 1.1 mrg safeAssert(p !is pdso, "DSO already registered."); 480 1.1 mrg _loadedDSOs.insertBack(pdso); 481 1.1 mrg _tlsRanges.insertBack(pdso.tlsRange()); 482 1.1 mrg } 483 1.1 mrg 484 1.1 mrg // don't initialize modules before rt_init was called (see Bugzilla 11378) 485 1.1 mrg if (_isRuntimeInitialized) 486 1.1 mrg { 487 1.1 mrg registerGCRanges(pdso); 488 1.1 mrg // rt_loadLibrary will run tls ctors, so do this only for dlopen 489 1.1 mrg immutable runTlsCtors = !_rtLoading; 490 1.1 mrg runModuleConstructors(pdso, runTlsCtors); 491 1.1 mrg } 492 1.1 mrg } 493 1.1 mrg // has backlink => unregister 494 1.1 mrg else 495 1.1 mrg { 496 1.1 mrg DSO* pdso = cast(DSO*)*data._slot; 497 1.1 mrg *data._slot = null; 498 1.1 mrg 499 1.1 mrg // don't finalizes modules after rt_term was called (see Bugzilla 11378) 500 1.1 mrg if (_isRuntimeInitialized) 501 1.1 mrg { 502 1.1 mrg // rt_unloadLibrary already ran tls dtors, so do this only for dlclose 503 1.1 mrg immutable runTlsDtors = !_rtLoading; 504 1.1 mrg runModuleDestructors(pdso, runTlsDtors); 505 1.1 mrg unregisterGCRanges(pdso); 506 1.1 mrg // run finalizers after module dtors (same order as in rt_term) 507 1.1 mrg version (Shared) runFinalizers(pdso); 508 1.1 mrg } 509 1.1 mrg 510 1.1 mrg version (Shared) 511 1.1 mrg { 512 1.1 mrg if (!_rtLoading) 513 1.1 mrg { 514 1.1 mrg /* This DSO was not unloaded by rt_unloadLibrary so we 515 1.1 mrg * have to remove it from _loadedDSOs here. 516 1.1 mrg */ 517 1.1 mrg foreach (i, ref tdso; _loadedDSOs) 518 1.1 mrg { 519 1.1 mrg if (tdso._pdso == pdso) 520 1.1 mrg { 521 1.1 mrg _loadedDSOs.remove(i); 522 1.1 mrg break; 523 1.1 mrg } 524 1.1 mrg } 525 1.1 mrg } 526 1.1 mrg 527 1.1 mrg unsetDSOForHandle(pdso, pdso._handle); 528 1.1 mrg } 529 1.1 mrg else 530 1.1 mrg { 531 1.1 mrg // static DSOs are unloaded in reverse order 532 1.1 mrg safeAssert(pdso == _loadedDSOs.back, "DSO being unregistered isn't current last one."); 533 1.1 mrg _loadedDSOs.popBack(); 534 1.1 mrg } 535 1.1 mrg 536 1.1 mrg freeDSO(pdso); 537 1.1 mrg 538 1.1 mrg // last DSO being unloaded => shutdown registry 539 1.1 mrg if (_loadedDSOs.empty) 540 1.1 mrg { 541 1.1 mrg version (Shared) 542 1.1 mrg { 543 1.1 mrg safeAssert(_handleToDSO.empty, "_handleToDSO not in sync with _loadedDSOs."); 544 1.1 mrg _handleToDSO.reset(); 545 1.1 mrg } 546 1.1 mrg finiLocks(); 547 1.1 mrg version (GNU_EMUTLS) 548 1.1 mrg { 549 1.1 mrg import gcc.emutls; 550 1.1 mrg _d_emutls_destroy(); 551 1.1 mrg } 552 1.1 mrg } 553 1.1 mrg } 554 1.1 mrg } 555 1.1 mrg 556 1.1 mrg /////////////////////////////////////////////////////////////////////////////// 557 1.1 mrg // Dynamic loading 558 1.1 mrg /////////////////////////////////////////////////////////////////////////////// 559 1.1 mrg 560 1.1 mrg // Shared D libraries are only supported when linking against a shared druntime library. 561 1.1 mrg 562 1.1 mrg version (Shared) 563 1.1 mrg { 564 1.1 mrg ThreadDSO* findThreadDSO(DSO* pdso) nothrow @nogc 565 1.1 mrg { 566 1.1 mrg foreach (ref tdata; _loadedDSOs) 567 1.1 mrg if (tdata._pdso == pdso) return &tdata; 568 1.1 mrg return null; 569 1.1 mrg } 570 1.1 mrg 571 1.1 mrg void incThreadRef(DSO* pdso, bool incAdd) 572 1.1 mrg { 573 1.1 mrg if (auto tdata = findThreadDSO(pdso)) // already initialized 574 1.1 mrg { 575 1.1 mrg if (incAdd && ++tdata._addCnt > 1) return; 576 1.1 mrg ++tdata._refCnt; 577 1.1 mrg } 578 1.1 mrg else 579 1.1 mrg { 580 1.1 mrg foreach (dep; pdso._deps) 581 1.1 mrg incThreadRef(dep, false); 582 1.1 mrg immutable ushort refCnt = 1, addCnt = incAdd ? 1 : 0; 583 1.1 mrg _loadedDSOs.insertBack(ThreadDSO(pdso, refCnt, addCnt, pdso.tlsRange())); 584 1.1 mrg pdso._moduleGroup.runTlsCtors(); 585 1.1 mrg } 586 1.1 mrg } 587 1.1 mrg 588 1.1 mrg void decThreadRef(DSO* pdso, bool decAdd) 589 1.1 mrg { 590 1.1 mrg auto tdata = findThreadDSO(pdso); 591 1.1 mrg safeAssert(tdata !is null, "Failed to find thread DSO."); 592 1.1 mrg safeAssert(!decAdd || tdata._addCnt > 0, "Mismatching rt_unloadLibrary call."); 593 1.1 mrg 594 1.1 mrg if (decAdd && --tdata._addCnt > 0) return; 595 1.1 mrg if (--tdata._refCnt > 0) return; 596 1.1 mrg 597 1.1 mrg pdso._moduleGroup.runTlsDtors(); 598 1.1 mrg foreach (i, ref td; _loadedDSOs) 599 1.1 mrg if (td._pdso == pdso) _loadedDSOs.remove(i); 600 1.1 mrg foreach (dep; pdso._deps) 601 1.1 mrg decThreadRef(dep, false); 602 1.1 mrg } 603 1.1 mrg 604 1.1 mrg extern(C) void* rt_loadLibrary(const char* name) 605 1.1 mrg { 606 1.1 mrg immutable save = _rtLoading; 607 1.1 mrg _rtLoading = true; 608 1.1 mrg scope (exit) _rtLoading = save; 609 1.1 mrg 610 1.1 mrg auto handle = .dlopen(name, RTLD_LAZY); 611 1.1 mrg if (handle is null) return null; 612 1.1 mrg 613 1.1 mrg // if it's a D library 614 1.1 mrg if (auto pdso = dsoForHandle(handle)) 615 1.1 mrg incThreadRef(pdso, true); 616 1.1 mrg return handle; 617 1.1 mrg } 618 1.1 mrg 619 1.1 mrg extern(C) int rt_unloadLibrary(void* handle) 620 1.1 mrg { 621 1.1 mrg if (handle is null) return false; 622 1.1 mrg 623 1.1 mrg immutable save = _rtLoading; 624 1.1 mrg _rtLoading = true; 625 1.1 mrg scope (exit) _rtLoading = save; 626 1.1 mrg 627 1.1 mrg // if it's a D library 628 1.1 mrg if (auto pdso = dsoForHandle(handle)) 629 1.1 mrg decThreadRef(pdso, true); 630 1.1 mrg return .dlclose(handle) == 0; 631 1.1 mrg } 632 1.1 mrg } 633 1.1 mrg 634 1.1 mrg /////////////////////////////////////////////////////////////////////////////// 635 1.1 mrg // Helper functions 636 1.1 mrg /////////////////////////////////////////////////////////////////////////////// 637 1.1 mrg 638 1.1 mrg void initLocks() nothrow @nogc 639 1.1 mrg { 640 1.1 mrg version (Shared) 641 1.1 mrg !pthread_mutex_init(&_handleToDSOMutex, null) || assert(0); 642 1.1 mrg } 643 1.1 mrg 644 1.1 mrg void finiLocks() nothrow @nogc 645 1.1 mrg { 646 1.1 mrg version (Shared) 647 1.1 mrg !pthread_mutex_destroy(&_handleToDSOMutex) || assert(0); 648 1.1 mrg } 649 1.1 mrg 650 1.1 mrg void runModuleConstructors(DSO* pdso, bool runTlsCtors) 651 1.1 mrg { 652 1.1 mrg pdso._moduleGroup.sortCtors(); 653 1.1 mrg pdso._moduleGroup.runCtors(); 654 1.1 mrg if (runTlsCtors) pdso._moduleGroup.runTlsCtors(); 655 1.1 mrg } 656 1.1 mrg 657 1.1 mrg void runModuleDestructors(DSO* pdso, bool runTlsDtors) 658 1.1 mrg { 659 1.1 mrg if (runTlsDtors) pdso._moduleGroup.runTlsDtors(); 660 1.1 mrg pdso._moduleGroup.runDtors(); 661 1.1 mrg } 662 1.1 mrg 663 1.1 mrg void registerGCRanges(DSO* pdso) nothrow @nogc 664 1.1 mrg { 665 1.1 mrg foreach (rng; pdso._gcRanges) 666 1.1 mrg GC.addRange(rng.ptr, rng.length); 667 1.1 mrg } 668 1.1 mrg 669 1.1 mrg void unregisterGCRanges(DSO* pdso) nothrow @nogc 670 1.1 mrg { 671 1.1 mrg foreach (rng; pdso._gcRanges) 672 1.1 mrg GC.removeRange(rng.ptr); 673 1.1 mrg } 674 1.1 mrg 675 1.1 mrg version (Shared) void runFinalizers(DSO* pdso) 676 1.1 mrg { 677 1.1 mrg foreach (seg; pdso._codeSegments) 678 1.1 mrg GC.runFinalizers(seg); 679 1.1 mrg } 680 1.1 mrg 681 1.1 mrg void freeDSO(DSO* pdso) nothrow @nogc 682 1.1 mrg { 683 1.1 mrg pdso._gcRanges.reset(); 684 1.1 mrg version (Shared) 685 1.1 mrg { 686 1.1 mrg pdso._codeSegments.reset(); 687 1.1 mrg pdso._deps.reset(); 688 1.1 mrg pdso._handle = null; 689 1.1 mrg } 690 1.1 mrg .free(pdso); 691 1.1 mrg } 692 1.1 mrg 693 1.1 mrg version (Shared) 694 1.1 mrg { 695 1.1 mrg @nogc nothrow: 696 1.1 mrg link_map* linkMapForHandle(void* handle) 697 1.1 mrg { 698 1.1 mrg static if (__traits(compiles, RTLD_DI_LINKMAP)) 699 1.1 mrg { 700 1.1 mrg link_map* map; 701 1.1 mrg const success = dlinfo(handle, RTLD_DI_LINKMAP, &map) == 0; 702 1.1 mrg safeAssert(success, "Failed to get DSO info."); 703 1.1 mrg return map; 704 1.1 mrg } 705 1.1 mrg else version (OpenBSD) 706 1.1 mrg { 707 1.1 mrg safeAssert(handle !is null, "Failed to get DSO info."); 708 1.1 mrg return cast(link_map*)handle; 709 1.1 mrg } 710 1.1 mrg else 711 1.1 mrg static assert(0, "unimplemented"); 712 1.1 mrg } 713 1.1 mrg 714 1.1 mrg DSO* dsoForHandle(void* handle) 715 1.1 mrg { 716 1.1 mrg DSO* pdso; 717 1.1 mrg !pthread_mutex_lock(&_handleToDSOMutex) || assert(0); 718 1.1 mrg if (auto ppdso = handle in _handleToDSO) 719 1.1 mrg pdso = *ppdso; 720 1.1 mrg !pthread_mutex_unlock(&_handleToDSOMutex) || assert(0); 721 1.1 mrg return pdso; 722 1.1 mrg } 723 1.1 mrg 724 1.1 mrg void setDSOForHandle(DSO* pdso, void* handle) 725 1.1 mrg { 726 1.1 mrg !pthread_mutex_lock(&_handleToDSOMutex) || assert(0); 727 1.1 mrg safeAssert(handle !in _handleToDSO, "DSO already registered."); 728 1.1 mrg _handleToDSO[handle] = pdso; 729 1.1 mrg !pthread_mutex_unlock(&_handleToDSOMutex) || assert(0); 730 1.1 mrg } 731 1.1 mrg 732 1.1 mrg void unsetDSOForHandle(DSO* pdso, void* handle) 733 1.1 mrg { 734 1.1 mrg !pthread_mutex_lock(&_handleToDSOMutex) || assert(0); 735 1.1 mrg safeAssert(_handleToDSO[handle] == pdso, "Handle doesn't match registered DSO."); 736 1.1 mrg _handleToDSO.remove(handle); 737 1.1 mrg !pthread_mutex_unlock(&_handleToDSOMutex) || assert(0); 738 1.1 mrg } 739 1.1 mrg 740 1.1 mrg void getDependencies(in ref dl_phdr_info info, ref Array!(DSO*) deps) 741 1.1 mrg { 742 1.1 mrg // get the entries of the .dynamic section 743 1.1 mrg ElfW!"Dyn"[] dyns; 744 1.1 mrg foreach (ref phdr; info.dlpi_phdr[0 .. info.dlpi_phnum]) 745 1.1 mrg { 746 1.1 mrg if (phdr.p_type == PT_DYNAMIC) 747 1.1 mrg { 748 1.1 mrg auto p = cast(ElfW!"Dyn"*)(info.dlpi_addr + (phdr.p_vaddr & ~(size_t.sizeof - 1))); 749 1.1 mrg dyns = p[0 .. phdr.p_memsz / ElfW!"Dyn".sizeof]; 750 1.1 mrg break; 751 1.1 mrg } 752 1.1 mrg } 753 1.1 mrg // find the string table which contains the sonames 754 1.1 mrg const(char)* strtab; 755 1.1 mrg foreach (dyn; dyns) 756 1.1 mrg { 757 1.1 mrg if (dyn.d_tag == DT_STRTAB) 758 1.1 mrg { 759 1.1 mrg version (CRuntime_Musl) 760 1.1 mrg strtab = cast(const(char)*)(info.dlpi_addr + dyn.d_un.d_ptr); // relocate 761 1.1 mrg else version (linux) 762 1.1 mrg { 763 1.1 mrg // This might change in future glibc releases (after 2.29) as dynamic sections 764 1.1 mrg // are not required to be read-only on RISC-V. This was copy & pasted from MIPS 765 1.1 mrg // while upstreaming RISC-V support. Otherwise MIPS is the only arch which sets 766 1.1 mrg // in glibc: #define DL_RO_DYN_SECTION 1 767 1.1 mrg version (RISCV_Any) 768 1.1 mrg strtab = cast(const(char)*)(info.dlpi_addr + dyn.d_un.d_ptr); // relocate 769 1.1 mrg else version (MIPS_Any) 770 1.1 mrg strtab = cast(const(char)*)(info.dlpi_addr + dyn.d_un.d_ptr); // relocate 771 1.1 mrg else 772 1.1 mrg strtab = cast(const(char)*)dyn.d_un.d_ptr; 773 1.1 mrg } 774 1.1 mrg else version (FreeBSD) 775 1.1 mrg strtab = cast(const(char)*)(info.dlpi_addr + dyn.d_un.d_ptr); // relocate 776 1.1 mrg else version (NetBSD) 777 1.1 mrg strtab = cast(const(char)*)(info.dlpi_addr + dyn.d_un.d_ptr); // relocate 778 1.1 mrg else version (OpenBSD) 779 1.1 mrg strtab = cast(const(char)*)(info.dlpi_addr + dyn.d_un.d_ptr); // relocate 780 1.1 mrg else version (DragonFlyBSD) 781 1.1 mrg strtab = cast(const(char)*)(info.dlpi_addr + dyn.d_un.d_ptr); // relocate 782 1.1 mrg else version (Solaris) 783 1.1 mrg strtab = cast(const(char)*)(info.dlpi_addr + dyn.d_un.d_ptr); // relocate 784 1.1 mrg else 785 1.1 mrg static assert(0, "unimplemented"); 786 1.1 mrg break; 787 1.1 mrg } 788 1.1 mrg } 789 1.1 mrg foreach (dyn; dyns) 790 1.1 mrg { 791 1.1 mrg immutable tag = dyn.d_tag; 792 1.1 mrg if (!(tag == DT_NEEDED || tag == DT_AUXILIARY || tag == DT_FILTER)) 793 1.1 mrg continue; 794 1.1 mrg 795 1.1 mrg // soname of the dependency 796 1.1 mrg auto name = strtab + dyn.d_un.d_val; 797 1.1 mrg // get handle without loading the library 798 1.1 mrg auto handle = handleForName(name); 799 1.1 mrg // the runtime linker has already loaded all dependencies 800 1.1 mrg safeAssert(handle !is null, "Failed to get library handle."); 801 1.1 mrg // if it's a D library 802 1.1 mrg if (auto pdso = dsoForHandle(handle)) 803 1.1 mrg deps.insertBack(pdso); // append it to the dependencies 804 1.1 mrg } 805 1.1 mrg } 806 1.1 mrg 807 1.1 mrg void* handleForName(const char* name) 808 1.1 mrg { 809 1.1 mrg version (Solaris) enum refCounted = false; 810 1.1 mrg else version (OpenBSD) enum refCounted = false; 811 1.1 mrg else enum refCounted = true; 812 1.1 mrg 813 1.1 mrg static if (__traits(compiles, RTLD_NOLOAD)) 814 1.1 mrg enum flags = (RTLD_NOLOAD | RTLD_LAZY); 815 1.1 mrg else 816 1.1 mrg enum flags = RTLD_LAZY; 817 1.1 mrg 818 1.1 mrg auto handle = .dlopen(name, flags); 819 1.1 mrg static if (refCounted) 820 1.1 mrg { 821 1.1 mrg if (handle !is null) 822 1.1 mrg .dlclose(handle); // drop reference count 823 1.1 mrg } 824 1.1 mrg return handle; 825 1.1 mrg } 826 1.1 mrg } 827 1.1 mrg 828 1.1 mrg /////////////////////////////////////////////////////////////////////////////// 829 1.1 mrg // Elf program header iteration 830 1.1 mrg /////////////////////////////////////////////////////////////////////////////// 831 1.1 mrg 832 1.1 mrg /************ 833 1.1 mrg * Scan segments in Linux dl_phdr_info struct and store 834 1.1 mrg * the TLS and writeable data segments in *pdso. 835 1.1 mrg */ 836 1.1 mrg void scanSegments(in ref dl_phdr_info info, DSO* pdso) nothrow @nogc 837 1.1 mrg { 838 1.1 mrg foreach (ref phdr; info.dlpi_phdr[0 .. info.dlpi_phnum]) 839 1.1 mrg { 840 1.1 mrg switch (phdr.p_type) 841 1.1 mrg { 842 1.1 mrg case PT_LOAD: 843 1.1 mrg if (phdr.p_flags & PF_W) // writeable data segment 844 1.1 mrg { 845 1.1 mrg auto beg = cast(void*)(info.dlpi_addr + (phdr.p_vaddr & ~(size_t.sizeof - 1))); 846 1.1 mrg pdso._gcRanges.insertBack(beg[0 .. phdr.p_memsz]); 847 1.1 mrg } 848 1.1 mrg version (Shared) if (phdr.p_flags & PF_X) // code segment 849 1.1 mrg { 850 1.1 mrg auto beg = cast(void*)(info.dlpi_addr + (phdr.p_vaddr & ~(size_t.sizeof - 1))); 851 1.1 mrg pdso._codeSegments.insertBack(beg[0 .. phdr.p_memsz]); 852 1.1 mrg } 853 1.1 mrg break; 854 1.1 mrg 855 1.1 mrg case PT_TLS: // TLS segment 856 1.1 mrg version (GNU_EMUTLS) 857 1.1 mrg { 858 1.1 mrg } 859 1.1 mrg else 860 1.1 mrg { 861 1.1 mrg safeAssert(!pdso._tlsSize, "Multiple TLS segments in image header."); 862 1.1 mrg static if (OS_Have_Dlpi_Tls_Modid) 863 1.1 mrg { 864 1.1 mrg pdso._tlsMod = info.dlpi_tls_modid; 865 1.1 mrg pdso._tlsSize = phdr.p_memsz; 866 1.1 mrg } 867 1.1 mrg else version (Solaris) 868 1.1 mrg { 869 1.1 mrg struct Rt_map 870 1.1 mrg { 871 1.1 mrg Link_map rt_public; 872 1.1 mrg const char* rt_pathname; 873 1.1 mrg c_ulong rt_padstart; 874 1.1 mrg c_ulong rt_padimlen; 875 1.1 mrg c_ulong rt_msize; 876 1.1 mrg uint rt_flags; 877 1.1 mrg uint rt_flags1; 878 1.1 mrg c_ulong rt_tlsmodid; 879 1.1 mrg } 880 1.1 mrg 881 1.1 mrg Rt_map* map; 882 1.1 mrg version (Shared) 883 1.1 mrg dlinfo(handleForName(info.dlpi_name), RTLD_DI_LINKMAP, &map); 884 1.1 mrg else 885 1.1 mrg dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &map); 886 1.1 mrg // Until Solaris 11.4, tlsmodid for the executable is 0. 887 1.1 mrg // Let it start at 1 as the rest of the code expects. 888 1.1 mrg pdso._tlsMod = map.rt_tlsmodid + 1; 889 1.1 mrg pdso._tlsSize = phdr.p_memsz; 890 1.1 mrg } 891 1.1 mrg else 892 1.1 mrg { 893 1.1 mrg pdso._tlsMod = 0; 894 1.1 mrg pdso._tlsSize = 0; 895 1.1 mrg } 896 1.1 mrg } 897 1.1 mrg break; 898 1.1 mrg 899 1.1 mrg default: 900 1.1 mrg break; 901 1.1 mrg } 902 1.1 mrg } 903 1.1 mrg } 904 1.1 mrg 905 1.1 mrg /************************** 906 1.1 mrg * Input: 907 1.1 mrg * result where the output is to be written; dl_phdr_info is an OS struct 908 1.1 mrg * Returns: 909 1.1 mrg * true if found, and *result is filled in 910 1.1 mrg * References: 911 1.1 mrg * http://linux.die.net/man/3/dl_iterate_phdr 912 1.1 mrg */ 913 1.1 mrg bool findDSOInfoForAddr(in void* addr, dl_phdr_info* result=null) nothrow @nogc 914 1.1 mrg { 915 1.1 mrg version (linux) enum IterateManually = true; 916 1.1 mrg else version (NetBSD) enum IterateManually = true; 917 1.1 mrg else version (OpenBSD) enum IterateManually = true; 918 1.1 mrg else version (Solaris) enum IterateManually = true; 919 1.1 mrg else enum IterateManually = false; 920 1.1 mrg 921 1.1 mrg static if (IterateManually) 922 1.1 mrg { 923 1.1 mrg static struct DG { const(void)* addr; dl_phdr_info* result; } 924 1.1 mrg 925 1.1 mrg extern(C) int callback(dl_phdr_info* info, size_t sz, void* arg) nothrow @nogc 926 1.1 mrg { 927 1.1 mrg auto p = cast(DG*)arg; 928 1.1 mrg if (findSegmentForAddr(*info, p.addr)) 929 1.1 mrg { 930 1.1 mrg if (p.result !is null) *p.result = *info; 931 1.1 mrg return 1; // break; 932 1.1 mrg } 933 1.1 mrg return 0; // continue iteration 934 1.1 mrg } 935 1.1 mrg 936 1.1 mrg auto dg = DG(addr, result); 937 1.1 mrg 938 1.1 mrg /* OS function that walks through the list of an application's shared objects and 939 1.1 mrg * calls 'callback' once for each object, until either all shared objects 940 1.1 mrg * have been processed or 'callback' returns a nonzero value. 941 1.1 mrg */ 942 1.1 mrg return dl_iterate_phdr(&callback, &dg) != 0; 943 1.1 mrg } 944 1.1 mrg else version (FreeBSD) 945 1.1 mrg { 946 1.1 mrg return !!_rtld_addr_phdr(addr, result); 947 1.1 mrg } 948 1.1 mrg else version (DragonFlyBSD) 949 1.1 mrg { 950 1.1 mrg return !!_rtld_addr_phdr(addr, result); 951 1.1 mrg } 952 1.1 mrg else 953 1.1 mrg static assert(0, "unimplemented"); 954 1.1 mrg } 955 1.1 mrg 956 1.1 mrg /********************************* 957 1.1 mrg * Determine if 'addr' lies within shared object 'info'. 958 1.1 mrg * If so, return true and fill in 'result' with the corresponding ELF program header. 959 1.1 mrg */ 960 1.1 mrg bool findSegmentForAddr(in ref dl_phdr_info info, in void* addr, ElfW!"Phdr"* result=null) nothrow @nogc 961 1.1 mrg { 962 1.1 mrg if (addr < cast(void*)info.dlpi_addr) // less than base address of object means quick reject 963 1.1 mrg return false; 964 1.1 mrg 965 1.1 mrg foreach (ref phdr; info.dlpi_phdr[0 .. info.dlpi_phnum]) 966 1.1 mrg { 967 1.1 mrg auto beg = cast(void*)(info.dlpi_addr + phdr.p_vaddr); 968 1.1 mrg if (cast(size_t)(addr - beg) < phdr.p_memsz) 969 1.1 mrg { 970 1.1 mrg if (result !is null) *result = phdr; 971 1.1 mrg return true; 972 1.1 mrg } 973 1.1 mrg } 974 1.1 mrg return false; 975 1.1 mrg } 976 1.1 mrg 977 1.1 mrg /************************** 978 1.1 mrg * Input: 979 1.1 mrg * addr an internal address of a DSO 980 1.1 mrg * Returns: 981 1.1 mrg * the dlopen handle for that DSO or null if addr is not within a loaded DSO 982 1.1 mrg */ 983 1.1 mrg version (Shared) void* handleForAddr(void* addr) nothrow @nogc 984 1.1 mrg { 985 1.1 mrg Dl_info info = void; 986 1.1 mrg if (dladdr(addr, &info) != 0) 987 1.1 mrg return handleForName(info.dli_fname); 988 1.1 mrg return null; 989 1.1 mrg } 990 1.1 mrg 991 1.1 mrg /////////////////////////////////////////////////////////////////////////////// 992 1.1 mrg // TLS module helper 993 1.1 mrg /////////////////////////////////////////////////////////////////////////////// 994 1.1 mrg 995 1.1 mrg 996 1.1 mrg /* 997 1.1 mrg * Returns: the TLS memory range for a given module and the calling 998 1.1 mrg * thread or null if that module has no TLS. 999 1.1 mrg * 1000 1.1 mrg * Note: This will cause the TLS memory to be eagerly allocated. 1001 1.1 mrg */ 1002 1.1 mrg struct tls_index 1003 1.1 mrg { 1004 1.1 mrg version (CRuntime_Glibc) 1005 1.1 mrg { 1006 1.1 mrg // For x86_64, fields are of type uint64_t, this is important for x32 1007 1.1 mrg // where tls_index would otherwise have the wrong size. 1008 1.1 mrg // See https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/x86_64/dl-tls.h 1009 1.1 mrg version (X86_64) 1010 1.1 mrg { 1011 1.1 mrg ulong ti_module; 1012 1.1 mrg ulong ti_offset; 1013 1.1 mrg } 1014 1.1 mrg else 1015 1.1 mrg { 1016 1.1 mrg c_ulong ti_module; 1017 1.1 mrg c_ulong ti_offset; 1018 1.1 mrg } 1019 1.1 mrg } 1020 1.1 mrg else 1021 1.1 mrg { 1022 1.1 mrg size_t ti_module; 1023 1.1 mrg size_t ti_offset; 1024 1.1 mrg } 1025 1.1 mrg } 1026 1.1 mrg 1027 1.1 mrg extern(C) void* __tls_get_addr(tls_index* ti) nothrow @nogc; 1028 1.1 mrg extern(C) void* __ibmz_get_tls_offset(tls_index *ti) nothrow @nogc; 1029 1.1 mrg 1030 1.1 mrg /* The dynamic thread vector (DTV) pointers may point 0x8000 past the start of 1031 1.1 mrg * each TLS block. This is at least true for PowerPC and Mips platforms. 1032 1.1 mrg * See: https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/powerpc/dl-tls.h;h=f7cf6f96ebfb505abfd2f02be0ad0e833107c0cd;hb=HEAD#l34 1033 1.1 mrg * https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/mips/dl-tls.h;h=93a6dc050cb144b9f68b96fb3199c60f5b1fcd18;hb=HEAD#l32 1034 1.1 mrg * https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/riscv/dl-tls.h;h=ab2d860314de94c18812bc894ff6b3f55368f20f;hb=HEAD#l32 1035 1.1 mrg */ 1036 1.1 mrg version (X86) 1037 1.1 mrg enum TLS_DTV_OFFSET = 0x0; 1038 1.1 mrg else version (X86_64) 1039 1.1 mrg enum TLS_DTV_OFFSET = 0x0; 1040 1.1 mrg else version (ARM) 1041 1.1 mrg enum TLS_DTV_OFFSET = 0x0; 1042 1.1 mrg else version (AArch64) 1043 1.1 mrg enum TLS_DTV_OFFSET = 0x0; 1044 1.1 mrg else version (RISCV32) 1045 1.1 mrg enum TLS_DTV_OFFSET = 0x800; 1046 1.1 mrg else version (RISCV64) 1047 1.1 mrg enum TLS_DTV_OFFSET = 0x800; 1048 1.1 mrg else version (HPPA) 1049 1.1 mrg enum TLS_DTV_OFFSET = 0x0; 1050 1.1 mrg else version (SPARC) 1051 1.1 mrg enum TLS_DTV_OFFSET = 0x0; 1052 1.1 mrg else version (SPARC64) 1053 1.1 mrg enum TLS_DTV_OFFSET = 0x0; 1054 1.1 mrg else version (PPC) 1055 1.1 mrg enum TLS_DTV_OFFSET = 0x8000; 1056 1.1 mrg else version (PPC64) 1057 1.1 mrg enum TLS_DTV_OFFSET = 0x8000; 1058 1.1 mrg else version (MIPS32) 1059 1.1 mrg enum TLS_DTV_OFFSET = 0x8000; 1060 1.1 mrg else version (MIPS64) 1061 1.1 mrg enum TLS_DTV_OFFSET = 0x8000; 1062 1.1 mrg else version (IBMZ_Any) 1063 1.1 mrg enum TLS_DTV_OFFSET = 0x0; 1064 1.1 mrg else 1065 1.1 mrg static assert( false, "Platform not supported." ); 1066 1.1 mrg 1067 1.1 mrg void[] getTLSRange(size_t mod, size_t sz) nothrow @nogc 1068 1.1 mrg { 1069 1.1 mrg if (mod == 0) 1070 1.1 mrg return null; 1071 1.1 mrg 1072 1.1 mrg version (GNU_EMUTLS) 1073 1.1 mrg return null; // Handled in scanTLSRanges(). 1074 1.1 mrg else 1075 1.1 mrg { 1076 1.1 mrg version (Solaris) 1077 1.1 mrg { 1078 1.1 mrg static if (!OS_Have_Dlpi_Tls_Modid) 1079 1.1 mrg mod -= 1; 1080 1.1 mrg } 1081 1.1 mrg 1082 1.1 mrg // base offset 1083 1.1 mrg auto ti = tls_index(mod, 0); 1084 1.1 mrg version (CRuntime_Musl) 1085 1.1 mrg return (__tls_get_addr(&ti)-TLS_DTV_OFFSET)[0 .. sz]; 1086 1.1 mrg else version (IBMZ_Any) 1087 1.1 mrg { 1088 1.1 mrg // IBM Z only provides __tls_get_offset instead of __tls_get_addr 1089 1.1 mrg // which returns an offset relative to the thread pointer. 1090 1.1 mrg auto addr = __ibmz_get_tls_offset(&ti); 1091 1.1 mrg addr = addr + cast(c_ulong)__builtin_thread_pointer(); 1092 1.1 mrg return addr[0 .. sz]; 1093 1.1 mrg } 1094 1.1 mrg else 1095 1.1 mrg return (__tls_get_addr(&ti)-TLS_DTV_OFFSET)[0 .. sz]; 1096 1.1 mrg } 1097 1.1 mrg } 1098