// The old external/libcxx doesn't have operator<< for nullptr. // TODO(b/175635923): Remove this hack after upgrading libc++. template <class T>
T fix_nullptr(T&& arg) { return arg;
} void* fix_nullptr(nullptr_t arg) { returnstatic_cast<void*>(arg);
}
static size_t highest_modid_in_dtv() {
TlsDtv* current_dtv = dtv();
size_t result = 0; for (size_t i = 0; i < current_dtv->count; ++i) { if (current_dtv->modules[i] != nullptr) {
result = __tls_module_idx_to_id(i);
}
} return result;
}
// Unused, but ensures that the test executable has a TLS segment. With a // new-enough libc++_static.a, the test executable will tend to has a TLS // segment to hold the libc++ EH globals pointer.
__thread int g_tls_var_placeholder = 42;
int main() { // Prevent this TLS variable from being optimized away.
ASSERT_EQ(42, g_tls_var_placeholder);
static_assert(sizeof(TlsDtv) == 3 * sizeof(void*), "This test assumes that the Dtv has a 3-word header");
// Initially there are 2-4 modules: // - 1: test executable // - 2: libc // - 3: libc++ (when using a new-enough libc++) // - 4: libclang_rt.hwasan (when running with HWASan)
size_t first_filler_modid = highest_loaded_modid() + 1;
ASSERT_LE(2, highest_loaded_modid());
ASSERT_LE(highest_loaded_modid(), 4);
// The initial DTV is an empty DTV with no generation and a size of 0.
TlsDtv* zero_dtv = dtv();
ASSERT_EQ(0u, zero_dtv->count);
ASSERT_EQ(nullptr, zero_dtv->next);
ASSERT_EQ(kTlsGenerationNone, zero_dtv->generation);
// Load a module. The DTV is still empty unless the TLS variable is accessed. auto func1 = load_lib("libtest_elftls_dynamic_filler_1.so");
ASSERT_EQ(zero_dtv, dtv());
ASSERT_EQ(first_filler_modid, highest_loaded_modid());
// After accessing a TLS variable, the DTV should be initialized. It should be // 8 words in size, with a 5-entry capacity.
ASSERT_EQ(101, func1());
TlsDtv* initial_dtv = dtv();
ASSERT_EQ(5u, dtv()->count);
ASSERT_EQ(zero_dtv, initial_dtv->next);
ASSERT_LT(0u, initial_dtv->generation);
ASSERT_EQ(first_filler_modid, highest_modid_in_dtv());
ASSERT_NE(nullptr, initial_dtv->modules[__tls_module_id_to_idx(first_filler_modid)]);
// Fill the rest of the DTV up. (i.e. Ensure that exactly 5 modules with TLS // segments are loaded.) auto fill_entry = [&](size_t modid, constchar* soname, int tls_var_value) { if (highest_modid_in_dtv() == modid - 1) { auto func = load_lib(soname);
// Loading the module doesn't affect the DTV yet.
ASSERT_EQ(initial_dtv, dtv());
ASSERT_EQ(modid, highest_loaded_modid());
ASSERT_EQ(modid - 1, highest_modid_in_dtv());
ASSERT_EQ(current_generation, initial_dtv->generation);
// Access the TLS variable, which will allocate it in the DTV.
ASSERT_EQ(tls_var_value, func());
// Verify allocation and a bumped generation.
ASSERT_EQ(initial_dtv, dtv());
ASSERT_EQ(modid, highest_modid_in_dtv());
ASSERT_LT(current_generation, initial_dtv->generation);
current_generation = initial_dtv->generation;
}
};
// Load module 6, which will require doubling the size of the DTV. auto func4 = load_lib("libtest_elftls_dynamic_filler_4.so");
ASSERT_EQ(6u, highest_loaded_modid());
ASSERT_EQ(5u, highest_modid_in_dtv());
ASSERT_EQ(initial_dtv, dtv());
// Access a TLS variable from the first filler module.
ASSERT_EQ(102, func1());
ASSERT_EQ(5u, highest_modid_in_dtv()); #ifdefined(__aarch64__) || defined(__riscv) // The arm64 and riscv64 TLSDESC resolver doesn't update the DTV if it is new enough for // the given access.
ASSERT_EQ(initial_dtv, dtv());
ASSERT_EQ(5u, dtv()->count);
ASSERT_EQ(current_generation, dtv()->generation); #else // __tls_get_addr updates the DTV anytime the generation counter changes, but // the highest modid in the DTV is still 5, because module 6 hasn't been // allocated yet.
ASSERT_NE(initial_dtv, dtv());
ASSERT_EQ(13u, dtv()->count);
ASSERT_LT(current_generation, dtv()->generation); #endif
// Accessing the TLS variable in the latest module will always expand the DTV.
ASSERT_EQ(401, func4());
TlsDtv* new_dtv = dtv();
ASSERT_NE(initial_dtv, new_dtv);
ASSERT_EQ(initial_dtv, new_dtv->next);
ASSERT_EQ(13u, new_dtv->count);
ASSERT_LT(current_generation, new_dtv->generation);
ASSERT_EQ(6u, highest_modid_in_dtv());
current_generation = new_dtv->generation;
// Load one more filler, module 7. auto func5 = load_lib("libtest_elftls_dynamic_filler_5.so");
ASSERT_EQ(103, func1());
ASSERT_EQ(402, func4());
ASSERT_EQ(6u, highest_modid_in_dtv());
ASSERT_EQ(501, func5());
ASSERT_EQ(7u, highest_modid_in_dtv());
// Verify that no new DTV has been allocated.
ASSERT_EQ(new_dtv, dtv());
ASSERT_EQ(13u, new_dtv->count);
ASSERT_LT(current_generation, new_dtv->generation);
return0;
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.10 Sekunden
(vorverarbeitet am 2026-06-28)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.