@@ -1351,7 +1351,7 @@ void doDestruct(SharedObject *object) {
13511351// --------------------------------------------------------
13521352
13531353RuntimeTlsMap::RuntimeTlsMap ()
1354- : initialPtr{0 }, initialLimit{0 }, indices{getAllocator ()} { }
1354+ : initialPtr{0 }, initialLimit{0 }, indices{getAllocator ()}, tcbs{ getAllocator ()} { }
13551355
13561356void initTlsObjects (Tcb *tcb, const frg::vector<SharedObject *, MemoryAllocator> &objects, bool checkInitialized) {
13571357 // Initialize TLS segments that follow the static model.
@@ -1437,64 +1437,48 @@ Tcb *allocateTcb() {
14371437 memset (tcb_ptr->dtvPointers , 0 , sizeof (void *) * runtimeTlsMap->indices .size ());
14381438 for (size_t i = 0 ; i < runtimeTlsMap->indices .size (); ++i) {
14391439 auto object = runtimeTlsMap->indices [i];
1440- if (object->tlsModel != TlsModel::initial)
1441- continue ;
1442-
1443- if constexpr (tlsAboveTp) {
1444- tcb_ptr->dtvPointers [i] = reinterpret_cast <char *>(tcb_ptr) + sizeof (Tcb) + object->tlsOffset ;
1445- } else {
1446- tcb_ptr->dtvPointers [i] = reinterpret_cast <char *>(tcb_ptr) + object->tlsOffset ;
1440+ if (object->tlsModel == TlsModel::initial) {
1441+ if constexpr (tlsAboveTp) {
1442+ tcb_ptr->dtvPointers [i] = reinterpret_cast <char *>(tcb_ptr) + sizeof (Tcb) + object->tlsOffset ;
1443+ } else {
1444+ tcb_ptr->dtvPointers [i] = reinterpret_cast <char *>(tcb_ptr) + object->tlsOffset ;
1445+ }
1446+ } else if (object->tlsModel == TlsModel::dynamic) {
1447+ auto buffer = getAllocator ().allocate (object->tlsSegmentSize );
1448+ __ensure (!(reinterpret_cast <uintptr_t >(buffer) & (object->tlsAlignment - 1 )));
1449+ memset (buffer, 0 , object->tlsSegmentSize );
1450+ memcpy (buffer, object->tlsImagePtr , object->tlsImageSize );
1451+ tcb_ptr->dtvPointers [i] = buffer;
14471452 }
14481453 }
14491454
1455+ runtimeTlsMap->tcbs .push_back (tcb_ptr);
1456+
14501457 return tcb_ptr;
14511458}
14521459
14531460void *accessDtv (SharedObject *object) {
14541461 Tcb *tcb_ptr = mlibc::get_current_tcb ();
1455-
1456- {
1457- frg::unique_lock lock{*runtimeTlsMapLock};
1458-
1459- // We might need to reallocate the DTV.
1460- if (object->tlsIndex >= tcb_ptr->dtvSize ) {
1461- auto ndtv = frg::construct_n<void *>(getAllocator (), runtimeTlsMap->indices .size ());
1462- memset (ndtv, 0 , sizeof (void *) * runtimeTlsMap->indices .size ());
1463- memcpy (ndtv, tcb_ptr->dtvPointers , sizeof (void *) * tcb_ptr->dtvSize );
1464- frg::destruct_n (getAllocator (), tcb_ptr->dtvPointers , tcb_ptr->dtvSize );
1465- tcb_ptr->dtvSize = runtimeTlsMap->indices .size ();
1466- tcb_ptr->dtvPointers = ndtv;
1467- }
1468- }
1469-
1470- // We might need to fill in a new DTV entry.
1471- if (!tcb_ptr->dtvPointers [object->tlsIndex ]) {
1472- __ensure (object->tlsModel == TlsModel::dynamic);
1473-
1474- auto buffer = getAllocator ().allocate (object->tlsSegmentSize );
1475- __ensure (!(reinterpret_cast <uintptr_t >(buffer) & (object->tlsAlignment - 1 )));
1476- memset (buffer, 0 , object->tlsSegmentSize );
1477- memcpy (buffer, object->tlsImagePtr , object->tlsImageSize );
1478- tcb_ptr->dtvPointers [object->tlsIndex ] = buffer;
1479-
1480- if (rtldConfig.debugVerbose ) {
1481- mlibc::infoLogger () << " rtld: accessDtv wrote tls image at " << buffer
1482- << " , size = 0x" << frg::hex_fmt{object->tlsSegmentSize } << frg::endlog;
1483- }
1484- }
1485-
1486- return (void *)((char *)tcb_ptr->dtvPointers [object->tlsIndex ] + TLS_DTV_OFFSET );
1462+ size_t size = __atomic_load_n (&tcb_ptr->dtvSize , __ATOMIC_ACQUIRE);
1463+ __ensure (object->tlsIndex < size);
1464+ void **pointers = __atomic_load_n (&tcb_ptr->dtvPointers , __ATOMIC_ACQUIRE);
1465+ void *ptr = pointers[object->tlsIndex ];
1466+ __ensure (ptr);
1467+ return (void *)((char *)ptr + TLS_DTV_OFFSET );
14871468}
14881469
14891470void *tryAccessDtv (SharedObject *object) {
14901471 Tcb *tcb_ptr = mlibc::get_current_tcb ();
14911472
1492- if (object->tlsIndex >= tcb_ptr->dtvSize )
1473+ size_t size = __atomic_load_n (&tcb_ptr->dtvSize , __ATOMIC_ACQUIRE);
1474+ if (object->tlsIndex >= size)
14931475 return nullptr ;
1494- if (!tcb_ptr->dtvPointers [object->tlsIndex ])
1476+ void **pointers = __atomic_load_n (&tcb_ptr->dtvPointers , __ATOMIC_ACQUIRE);
1477+ void *ptr = pointers[object->tlsIndex ];
1478+ if (!ptr)
14951479 return nullptr ;
14961480
1497- return (void *)((char *)tcb_ptr-> dtvPointers [object-> tlsIndex ] + TLS_DTV_OFFSET );
1481+ return (void *)((char *)ptr + TLS_DTV_OFFSET );
14981482}
14991483
15001484// --------------------------------------------------------
@@ -1937,6 +1921,50 @@ void Loader::_buildTlsMaps() {
19371921 }
19381922 }
19391923 }
1924+
1925+ size_t new_size = runtimeTlsMap->indices .size ();
1926+
1927+ for (auto tcb : runtimeTlsMap->tcbs ) {
1928+ if (tcb->didExit )
1929+ continue ;
1930+
1931+ size_t size = __atomic_load_n (&tcb->dtvSize , __ATOMIC_ACQUIRE);
1932+ if (new_size > size) {
1933+ void **ndtv = frg::construct_n<void *>(getAllocator (), new_size);
1934+ void **pointers = __atomic_load_n (&tcb->dtvPointers , __ATOMIC_ACQUIRE);
1935+ memcpy (ndtv, pointers, sizeof (void *) * size);
1936+ memset (ndtv + size, 0 , sizeof (void *) * (new_size - size));
1937+
1938+ for (size_t i = size; i < new_size; i++) {
1939+ auto object = runtimeTlsMap->indices [i];
1940+ if (object->tlsModel == TlsModel::dynamic) {
1941+ auto buffer = getAllocator ().allocate (object->tlsSegmentSize );
1942+ __ensure (!(reinterpret_cast <uintptr_t >(buffer) & (object->tlsAlignment - 1 )));
1943+ memset (buffer, 0 , object->tlsSegmentSize );
1944+ memcpy (buffer, object->tlsImagePtr , object->tlsImageSize );
1945+ ndtv[i] = buffer;
1946+ } else if (object->tlsModel == TlsModel::initial) {
1947+ char *tls_ptr;
1948+ if constexpr (tlsAboveTp) {
1949+ tls_ptr = reinterpret_cast <char *>(tcb) + sizeof (Tcb) + object->tlsOffset ;
1950+ } else {
1951+ tls_ptr = reinterpret_cast <char *>(tcb) + object->tlsOffset ;
1952+ }
1953+ ndtv[i] = tls_ptr;
1954+
1955+ // Initialize the TLS segment for this thread as well.
1956+ memset (tls_ptr, 0 , object->tlsSegmentSize );
1957+ memcpy (tls_ptr, object->tlsImagePtr , object->tlsImageSize );
1958+ }
1959+ }
1960+
1961+ // Note: We intentionally leak the old `dtvPointers` array here. Since other threads
1962+ // can concurrently access their own TCB's `dtvPointers` lock-free, freeing the old
1963+ // array immediately would lead to use-after-free races.
1964+ __atomic_store_n (&tcb->dtvPointers , ndtv, __ATOMIC_RELEASE);
1965+ __atomic_store_n (&tcb->dtvSize , new_size, __ATOMIC_RELEASE);
1966+ }
1967+ }
19401968}
19411969
19421970void Loader::initObjects (ObjectRepository *repository) {
@@ -1986,6 +2014,17 @@ void Loader::_scheduleInit(SharedObject *object) {
19862014 object->onInitStack = false ;
19872015}
19882016
2017+ // TODO: TLSDESC relocations aren't aarch64/x86_64 specific
2018+ #if defined(__aarch64__) || defined(__x86_64__)
2019+ extern " C" void *__mlibcTlsdescStatic (void *);
2020+ extern " C" void *__mlibcTlsdescDynamic (void *);
2021+
2022+ struct TlsdescData {
2023+ uintptr_t tlsIndex;
2024+ uintptr_t addend;
2025+ };
2026+ #endif
2027+
19892028void Loader::_processRelocations (Relocation &rel) {
19902029 // copy and irelative relocations have to be performed after all other relocations
19912030 if (rel.type () == R_COPY || rel.type () == R_IRELATIVE )
@@ -2092,6 +2131,53 @@ void Loader::_processRelocations(Relocation &rel) {
20922131 off += tls_offset + tlsOffsetFromTp;
20932132 rel.relocate (off);
20942133 } break ;
2134+ // TODO: TLSDESC relocations aren't aarch64/x86_64 specific, but require an assembly implementation
2135+ // of the resolver functions
2136+ #if defined(__aarch64__) || defined(__x86_64__)
2137+ case R_TLSDESC : {
2138+ size_t symValue = 0 ;
2139+ SharedObject *target = nullptr ;
2140+
2141+ if (rel.symbol_index ()) {
2142+ auto [sym, ver] = rel.object ()->getSymbolByIndex (rel.symbol_index ());
2143+ auto p = Scope::resolveGlobalOrLocal (*globalScope, rel.object ()->localScope , sym.getString (), rel.object ()->objectRts , 0 , ver);
2144+
2145+ if (!p) {
2146+ if (ELF_ST_BIND (sym.symbol ()->st_info ) != STB_WEAK ) {
2147+ mlibc::panicLogger () << " rtld: Unresolved TLSDESC for symbol "
2148+ << sym.getString () << " in object " << rel.object ()->name << frg::endlog;
2149+ }
2150+ target = nullptr ;
2151+ symValue = 0 ;
2152+ } else {
2153+ target = p->object ();
2154+ if (p->symbol ())
2155+ symValue = p->symbol ()->st_value ;
2156+ }
2157+ } else {
2158+ target = rel.object ();
2159+ }
2160+
2161+ if (!target) {
2162+ ((uint64_t *)rel.destination ())[0 ] = reinterpret_cast <uintptr_t >(&__mlibcTlsdescStatic);
2163+ ((uint64_t *)rel.destination ())[1 ] = 0 ;
2164+ } else if (target->tlsModel == TlsModel::initial) {
2165+ ((uint64_t *)rel.destination ())[0 ] = reinterpret_cast <uintptr_t >(&__mlibcTlsdescStatic);
2166+ uint64_t value = symValue + target->tlsOffset + tlsOffsetFromTp + rel.addend_norel ();
2167+ ((uint64_t *)rel.destination ())[1 ] = value;
2168+ } else {
2169+ __ensure (target->tlsIndex < mlibc::get_current_tcb ()->dtvSize );
2170+
2171+ // TODO: We should free this when the DSO gets destroyed
2172+ auto data = frg::construct<TlsdescData>(getAllocator ());
2173+ data->tlsIndex = target->tlsIndex ;
2174+ data->addend = symValue + rel.addend_norel ();
2175+
2176+ ((uint64_t *)rel.destination ())[0 ] = reinterpret_cast <uintptr_t >(&__mlibcTlsdescDynamic);
2177+ ((uint64_t *)rel.destination ())[1 ] = reinterpret_cast <uintptr_t >(data);
2178+ }
2179+ } break ;
2180+ #endif
20952181 default :
20962182 mlibc::panicLogger () << " Unexpected relocation type "
20972183 << (void *) rel.type () << frg::endlog;
@@ -2194,12 +2280,6 @@ void Loader::_processStaticRelocations(SharedObject *object) {
21942280 }
21952281}
21962282
2197- // TODO: TLSDESC relocations aren't aarch64/x86_64 specific
2198- #if defined(__aarch64__) || defined(__x86_64__)
2199- extern " C" void *__mlibcTlsdescStatic (void *);
2200- extern " C" void *__mlibcTlsdescDynamic (void *);
2201- #endif
2202-
22032283void Loader::_processLazyRelocations (SharedObject *object) {
22042284 if (object->globalOffsetTable == nullptr ) {
22052285 __ensure (object->lazyRelocTableOffset == 0 );
@@ -2276,9 +2356,12 @@ void Loader::_processLazyRelocations(SharedObject *object) {
22762356 auto p = Scope::resolveGlobalOrLocal (*globalScope, object->localScope , sym.getString (), object->objectRts , 0 , ver);
22772357
22782358 if (!p) {
2279- __ensure (ELF_ST_BIND (sym.symbol ()->st_info ) != STB_WEAK );
2280- mlibc::panicLogger () << " rtld: Unresolved TLSDESC for symbol "
2281- << sym.getString () << " in object " << object->name << frg::endlog;
2359+ if (ELF_ST_BIND (sym.symbol ()->st_info ) != STB_WEAK ) {
2360+ mlibc::panicLogger () << " rtld: Unresolved TLSDESC for symbol "
2361+ << sym.getString () << " in object " << object->name << frg::endlog;
2362+ }
2363+ target = nullptr ;
2364+ symValue = 0 ;
22822365 } else {
22832366 target = p->object ();
22842367 if (p->symbol ())
@@ -2288,21 +2371,14 @@ void Loader::_processLazyRelocations(SharedObject *object) {
22882371 target = object;
22892372 }
22902373
2291- __ensure (target);
2292-
2293- if (target->tlsModel == TlsModel::initial) {
2374+ if (!target) {
2375+ ((uint64_t *)rel_addr)[0 ] = reinterpret_cast <uintptr_t >(&__mlibcTlsdescStatic);
2376+ ((uint64_t *)rel_addr)[1 ] = 0 ;
2377+ } else if (target->tlsModel == TlsModel::initial) {
22942378 ((uint64_t *)rel_addr)[0 ] = reinterpret_cast <uintptr_t >(&__mlibcTlsdescStatic);
22952379 uint64_t value = symValue + target->tlsOffset + tlsOffsetFromTp + addend;
22962380 ((uint64_t *)rel_addr)[1 ] = value;
22972381 } else {
2298- struct TlsdescData {
2299- uintptr_t tlsIndex;
2300- uintptr_t addend;
2301- };
2302-
2303- // Access DTV for object to force the entry to be allocated and initialized
2304- accessDtv (target);
2305-
23062382 __ensure (target->tlsIndex < mlibc::get_current_tcb ()->dtvSize );
23072383
23082384 // TODO: We should free this when the DSO gets destroyed
0 commit comments