1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 06:27:45 +00:00

LibELF: Take TLS segment alignment into account in DynamicLoader

Previously we would just tightly pack the different libraries' TLS
segments together, but that is incorrect, as they might require some
kind of minimum alignment for their TLS base address.

We now plumb the required TLS segment alignment down to the TLS block
linear allocator and align the base address down to the appropriate
alignment.
This commit is contained in:
Idan Horowitz 2022-07-05 01:18:40 +03:00 committed by Andreas Kling
parent 33214c29d3
commit 753844ec96
3 changed files with 19 additions and 12 deletions

View file

@ -96,6 +96,8 @@ static Result<NonnullRefPtr<DynamicLoader>, DlErrorMessage> map_library(String c
s_loaders.set(get_library_name(filename), *loader); s_loaders.set(get_library_name(filename), *loader);
s_current_tls_offset -= loader->tls_size_of_current_object(); s_current_tls_offset -= loader->tls_size_of_current_object();
if (loader->tls_alignment_of_current_object())
s_current_tls_offset = align_down_to(s_current_tls_offset, loader->tls_alignment_of_current_object());
loader->set_tls_offset(s_current_tls_offset); loader->set_tls_offset(s_current_tls_offset);
// This actually maps the library at the intended and final place. // This actually maps the library at the intended and final place.
@ -196,8 +198,8 @@ static void allocate_tls()
{ {
s_total_tls_size = 0; s_total_tls_size = 0;
for (auto const& data : s_loaders) { for (auto const& data : s_loaders) {
dbgln_if(DYNAMIC_LOAD_DEBUG, "{}: TLS Size: {}", data.key, data.value->tls_size_of_current_object()); dbgln_if(DYNAMIC_LOAD_DEBUG, "{}: TLS Size: {}, TLS Alignment: {}", data.key, data.value->tls_size_of_current_object(), data.value->tls_alignment_of_current_object());
s_total_tls_size += data.value->tls_size_of_current_object(); s_total_tls_size += data.value->tls_size_of_current_object() + data.value->tls_alignment_of_current_object();
} }
if (!s_total_tls_size) if (!s_total_tls_size)
@ -393,7 +395,7 @@ static Optional<DlErrorMessage> verify_tls_for_dlopen(DynamicLoader const& loade
if (loader.tls_size_of_current_object() == 0) if (loader.tls_size_of_current_object() == 0)
return {}; return {};
if (s_total_tls_size + loader.tls_size_of_current_object() > s_allocated_tls_block_size) if (s_total_tls_size + loader.tls_size_of_current_object() + loader.tls_alignment_of_current_object() > s_allocated_tls_block_size)
return DlErrorMessage("TLS size too large"); return DlErrorMessage("TLS size too large");
bool tls_data_is_all_zero = true; bool tls_data_is_all_zero = true;
@ -461,7 +463,7 @@ static Result<void*, DlErrorMessage> __dlopen(char const* filename, int flags)
if (result.is_error()) if (result.is_error())
return result.error(); return result.error();
s_total_tls_size += result1.value()->tls_size_of_current_object(); s_total_tls_size += result1.value()->tls_size_of_current_object() + result1.value()->tls_alignment_of_current_object();
auto object = s_global_objects.get(library_name); auto object = s_global_objects.get(library_name);
if (!object.has_value()) if (!object.has_value())
@ -586,7 +588,7 @@ void ELF::DynamicLinker::linker_main(String&& main_program_name, int main_progra
dbgln_if(DYNAMIC_LOAD_DEBUG, "loaded all dependencies"); dbgln_if(DYNAMIC_LOAD_DEBUG, "loaded all dependencies");
for ([[maybe_unused]] auto& lib : s_loaders) { for ([[maybe_unused]] auto& lib : s_loaders) {
dbgln_if(DYNAMIC_LOAD_DEBUG, "{} - tls size: {}, tls offset: {}", lib.key, lib.value->tls_size_of_current_object(), lib.value->tls_offset()); dbgln_if(DYNAMIC_LOAD_DEBUG, "{} - tls size: {}, tls alignment: {}, tls offset: {}", lib.key, lib.value->tls_size_of_current_object(), lib.value->tls_alignment_of_current_object(), lib.value->tls_offset());
} }
allocate_tls(); allocate_tls();

View file

@ -71,7 +71,7 @@ DynamicLoader::DynamicLoader(int fd, String filename, void* data, size_t size, S
m_elf_image = adopt_own(*new ELF::Image((u8*)m_file_data, m_file_size)); m_elf_image = adopt_own(*new ELF::Image((u8*)m_file_data, m_file_size));
m_valid = validate(); m_valid = validate();
if (m_valid) if (m_valid)
m_tls_size_of_current_object = calculate_tls_size(); find_tls_size_and_alignment();
else else
dbgln("Image validation failed for file {}", m_filename); dbgln("Image validation failed for file {}", m_filename);
} }
@ -105,15 +105,18 @@ DynamicObject const& DynamicLoader::dynamic_object() const
return *m_cached_dynamic_object; return *m_cached_dynamic_object;
} }
size_t DynamicLoader::calculate_tls_size() const void DynamicLoader::find_tls_size_and_alignment()
{ {
size_t tls_size = 0; image().for_each_program_header([this](auto program_header) {
image().for_each_program_header([&tls_size](auto program_header) {
if (program_header.type() == PT_TLS) { if (program_header.type() == PT_TLS) {
tls_size = program_header.size_in_memory(); m_tls_size_of_current_object = program_header.size_in_memory();
auto alignment = program_header.alignment();
VERIFY(!alignment || is_power_of_two(alignment));
m_tls_alignment_of_current_object = alignment > 1 ? alignment : 0; // No need to reserve extra space for single byte alignment
return IterationDecision::Break;
} }
return IterationDecision::Continue;
}); });
return tls_size;
} }
bool DynamicLoader::validate() bool DynamicLoader::validate()

View file

@ -67,6 +67,7 @@ public:
void set_tls_offset(size_t offset) { m_tls_offset = offset; }; void set_tls_offset(size_t offset) { m_tls_offset = offset; };
size_t tls_size_of_current_object() const { return m_tls_size_of_current_object; } size_t tls_size_of_current_object() const { return m_tls_size_of_current_object; }
size_t tls_alignment_of_current_object() const { return m_tls_alignment_of_current_object; }
size_t tls_offset() const { return m_tls_offset; } size_t tls_offset() const { return m_tls_offset; }
const ELF::Image& image() const { return *m_elf_image; } const ELF::Image& image() const { return *m_elf_image; }
@ -134,7 +135,7 @@ private:
}; };
RelocationResult do_relocation(DynamicObject::Relocation const&, ShouldInitializeWeak should_initialize_weak); RelocationResult do_relocation(DynamicObject::Relocation const&, ShouldInitializeWeak should_initialize_weak);
void do_relr_relocations(); void do_relr_relocations();
size_t calculate_tls_size() const; void find_tls_size_and_alignment();
ssize_t negative_offset_from_tls_block_end(ssize_t tls_offset, size_t value_of_symbol) const; ssize_t negative_offset_from_tls_block_end(ssize_t tls_offset, size_t value_of_symbol) const;
String m_filename; String m_filename;
@ -157,6 +158,7 @@ private:
ssize_t m_tls_offset { 0 }; ssize_t m_tls_offset { 0 };
size_t m_tls_size_of_current_object { 0 }; size_t m_tls_size_of_current_object { 0 };
size_t m_tls_alignment_of_current_object { 0 };
Vector<DynamicObject::Relocation> m_unresolved_relocations; Vector<DynamicObject::Relocation> m_unresolved_relocations;