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:
parent
33214c29d3
commit
753844ec96
3 changed files with 19 additions and 12 deletions
|
@ -96,6 +96,8 @@ static Result<NonnullRefPtr<DynamicLoader>, DlErrorMessage> map_library(String c
|
|||
s_loaders.set(get_library_name(filename), *loader);
|
||||
|
||||
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);
|
||||
|
||||
// This actually maps the library at the intended and final place.
|
||||
|
@ -196,8 +198,8 @@ static void allocate_tls()
|
|||
{
|
||||
s_total_tls_size = 0;
|
||||
for (auto const& data : s_loaders) {
|
||||
dbgln_if(DYNAMIC_LOAD_DEBUG, "{}: TLS Size: {}", data.key, data.value->tls_size_of_current_object());
|
||||
s_total_tls_size += 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() + data.value->tls_alignment_of_current_object();
|
||||
}
|
||||
|
||||
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)
|
||||
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");
|
||||
|
||||
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())
|
||||
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);
|
||||
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");
|
||||
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();
|
||||
|
|
|
@ -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_valid = validate();
|
||||
if (m_valid)
|
||||
m_tls_size_of_current_object = calculate_tls_size();
|
||||
find_tls_size_and_alignment();
|
||||
else
|
||||
dbgln("Image validation failed for file {}", m_filename);
|
||||
}
|
||||
|
@ -105,15 +105,18 @@ DynamicObject const& DynamicLoader::dynamic_object() const
|
|||
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([&tls_size](auto program_header) {
|
||||
image().for_each_program_header([this](auto program_header) {
|
||||
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()
|
||||
|
|
|
@ -67,6 +67,7 @@ public:
|
|||
|
||||
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_alignment_of_current_object() const { return m_tls_alignment_of_current_object; }
|
||||
size_t tls_offset() const { return m_tls_offset; }
|
||||
const ELF::Image& image() const { return *m_elf_image; }
|
||||
|
||||
|
@ -134,7 +135,7 @@ private:
|
|||
};
|
||||
RelocationResult do_relocation(DynamicObject::Relocation const&, ShouldInitializeWeak should_initialize_weak);
|
||||
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;
|
||||
|
||||
String m_filename;
|
||||
|
@ -157,6 +158,7 @@ private:
|
|||
|
||||
ssize_t m_tls_offset { 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;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue