Skip to content

Commit 4464ad3

Browse files
authored
Merge pull request managarm#1775 from no92/gcc-16
GCC 16 support
2 parents 0f4dd06 + 2e24ade commit 4464ad3

4 files changed

Lines changed: 162 additions & 82 deletions

File tree

options/rtld/aarch64/runtime.S

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,14 @@ __mlibcTlsdescStatic:
1313
.type __mlibcTlsdescDynamic,@function
1414
__mlibcTlsdescDynamic:
1515
stp x1, x2, [sp, #-16]!
16-
ldr x0, [x0, #8]
17-
ldp x1, x2, [x0] // tlsIndex, addend
18-
mrs x0, tpidr_el0 // tp
19-
ldr x0, [x0, #-104] // tp->dtvPointers
20-
ldr x0, [x0, x1, lsl 3] // [tlsIndex]
16+
ldr x1, [x0, #8] // TlsdescData *
17+
ldp x0, x2, [x1] // tlsIndex, addend
18+
19+
mrs x1, tpidr_el0 // tp
20+
sub x1, x1, #104 // address of tp->dtvPointers
21+
ldar x1, [x1] // load dtvPointers with acquire
22+
ldr x0, [x1, x0, lsl 3] // dtvPointers[tlsIndex]
23+
2124
add x0, x0, x2 // + addend
2225
mrs x1, tpidr_el0 // tp
2326
sub x0, x0, x1 // result - tp

options/rtld/generic/linker.cpp

Lines changed: 144 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1351,7 +1351,7 @@ void doDestruct(SharedObject *object) {
13511351
// --------------------------------------------------------
13521352

13531353
RuntimeTlsMap::RuntimeTlsMap()
1354-
: initialPtr{0}, initialLimit{0}, indices{getAllocator()} { }
1354+
: initialPtr{0}, initialLimit{0}, indices{getAllocator()}, tcbs{getAllocator()} { }
13551355

13561356
void 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

14531460
void *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

14891470
void *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
// --------------------------------------------------------
@@ -1577,14 +1561,12 @@ frg::optional<ObjectSymbol> resolveInObject(SharedObject *object, frg::string_vi
15771561

15781562
// Checks if the symbol's version matches the desired version.
15791563
auto correctVersion = [&] (SymbolVersion candVersion) {
1580-
// Local version symbols shouldn't participate in symbol resolution.
1581-
// Only time .dynsym can contain a local version symbol is if it's
1582-
// undefined, so it should be discarded earlier.
1583-
__ensure(!candVersion.isLocal());
1564+
if (object->definedVersions.size())
1565+
__ensure(!candVersion.isLocal());
15841566

15851567
// Caller requested default version, ...
15861568
// ... and this symbol matches.
1587-
if(!version && (candVersion.isDefault() || candVersion.isGlobal()))
1569+
if(!version && (candVersion.isDefault() || candVersion.isGlobal() || candVersion.isLocal()))
15881570
return true;
15891571
// ... but this symbol isn't the default.
15901572
if(!version)
@@ -1594,9 +1576,9 @@ frg::optional<ObjectSymbol> resolveInObject(SharedObject *object, frg::string_vi
15941576
// LLD prior to version 22, and binutils between versions 2.35 and 2.45
15951577
// produce a global version symbol for this case, while newer ones produce
15961578
// a local version symbol.
1597-
// In this case, accept either the global or default version.
1579+
// In this case, accept either the global, default, or local version.
15981580
if((version->isLocal() || version->isGlobal())
1599-
&& (candVersion.isGlobal() || candVersion.isDefault()))
1581+
&& (candVersion.isGlobal() || candVersion.isDefault() || candVersion.isLocal()))
16001582
return true;
16011583

16021584
// Otherwise, make sure the version is correct.
@@ -1939,6 +1921,50 @@ void Loader::_buildTlsMaps() {
19391921
}
19401922
}
19411923
}
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+
}
19421968
}
19431969

19441970
void Loader::initObjects(ObjectRepository *repository) {
@@ -1988,6 +2014,17 @@ void Loader::_scheduleInit(SharedObject *object) {
19882014
object->onInitStack = false;
19892015
}
19902016

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+
19912028
void Loader::_processRelocations(Relocation &rel) {
19922029
// copy and irelative relocations have to be performed after all other relocations
19932030
if(rel.type() == R_COPY || rel.type() == R_IRELATIVE)
@@ -2094,6 +2131,53 @@ void Loader::_processRelocations(Relocation &rel) {
20942131
off += tls_offset + tlsOffsetFromTp;
20952132
rel.relocate(off);
20962133
} 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
20972181
default:
20982182
mlibc::panicLogger() << "Unexpected relocation type "
20992183
<< (void *) rel.type() << frg::endlog;
@@ -2196,12 +2280,6 @@ void Loader::_processStaticRelocations(SharedObject *object) {
21962280
}
21972281
}
21982282

2199-
// TODO: TLSDESC relocations aren't aarch64/x86_64 specific
2200-
#if defined(__aarch64__) || defined(__x86_64__)
2201-
extern "C" void *__mlibcTlsdescStatic(void *);
2202-
extern "C" void *__mlibcTlsdescDynamic(void *);
2203-
#endif
2204-
22052283
void Loader::_processLazyRelocations(SharedObject *object) {
22062284
if(object->globalOffsetTable == nullptr) {
22072285
__ensure(object->lazyRelocTableOffset == 0);
@@ -2278,9 +2356,12 @@ void Loader::_processLazyRelocations(SharedObject *object) {
22782356
auto p = Scope::resolveGlobalOrLocal(*globalScope, object->localScope, sym.getString(), object->objectRts, 0, ver);
22792357

22802358
if (!p) {
2281-
__ensure(ELF_ST_BIND(sym.symbol()->st_info) != STB_WEAK);
2282-
mlibc::panicLogger() << "rtld: Unresolved TLSDESC for symbol "
2283-
<< 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;
22842365
} else {
22852366
target = p->object();
22862367
if (p->symbol())
@@ -2290,21 +2371,14 @@ void Loader::_processLazyRelocations(SharedObject *object) {
22902371
target = object;
22912372
}
22922373

2293-
__ensure(target);
2294-
2295-
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) {
22962378
((uint64_t *)rel_addr)[0] = reinterpret_cast<uintptr_t>(&__mlibcTlsdescStatic);
22972379
uint64_t value = symValue + target->tlsOffset + tlsOffsetFromTp + addend;
22982380
((uint64_t *)rel_addr)[1] = value;
22992381
} else {
2300-
struct TlsdescData {
2301-
uintptr_t tlsIndex;
2302-
uintptr_t addend;
2303-
};
2304-
2305-
// Access DTV for object to force the entry to be allocated and initialized
2306-
accessDtv(target);
2307-
23082382
__ensure(target->tlsIndex < mlibc::get_current_tcb()->dtvSize);
23092383

23102384
// TODO: We should free this when the DSO gets destroyed

options/rtld/generic/linker.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,9 @@ struct RuntimeTlsMap {
345345

346346
// TLS indices.
347347
frg::vector<SharedObject *, MemoryAllocator> indices;
348+
349+
// Track all allocated TCBs.
350+
frg::vector<Tcb *, MemoryAllocator> tcbs;
348351
};
349352

350353
extern frg::manual_box<FutexLock> runtimeTlsMapLock;

options/rtld/x86_64/runtime.S

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ __mlibcTlsdescDynamic:
1212
push %rbx
1313
push %rcx
1414

15-
mov 8(%rax), %rax
15+
mov 8(%rax), %rbx # TlsdescData*
16+
mov (%rbx), %rcx # tlsIndex
1617

17-
mov (%rax), %rbx // index
18-
mov 8(%rax), %rcx // addend
18+
mov %fs:16, %rax # dtvPointers
19+
mov (%rax, %rcx, 8), %rax # dtvPointers[tlsIndex]
1920

20-
mov %fs:16, %rax // *tp->dtvPointers
21-
mov (%rax, %rbx, 8), %rax // dtvPointers[0][index]
22-
add %rcx, %rax // + addend
21+
mov 8(%rbx), %rcx # addend
22+
add %rcx, %rax
2323
sub %fs:0, %rax
2424

2525
pop %rcx
@@ -53,7 +53,7 @@ pltRelocateStub:
5353
pop %rdx
5454
pop %rcx
5555
pop %rax
56-
56+
5757
pop %rdi
5858
pop %rsi
5959
add $16, %rsp

0 commit comments

Comments
 (0)