mirror of
https://github.com/RGBCube/serenity
synced 2025-06-01 11:18:13 +00:00
LibELF: Change TLS offset calculation
This changes the TLS offset calculation logic to be based on the symbol's size instead of the total size of the TLS. Because of this change, we no longer need to pipe "m_tls_size" to so many functions. Also, After this patch, the TLS data of the main program exists at the "end" of the TLS block (Highest addresses). This fixes a part of #6609.
This commit is contained in:
parent
6bbd2ebf83
commit
101ac45c1a
5 changed files with 36 additions and 33 deletions
|
@ -170,7 +170,7 @@ static void allocate_tls()
|
|||
|
||||
// Initialize TLS data
|
||||
for (const auto& entry : s_loaders) {
|
||||
entry.value->copy_initial_tls_data_into(initial_tls_data, s_total_tls_size);
|
||||
entry.value->copy_initial_tls_data_into(initial_tls_data);
|
||||
}
|
||||
|
||||
void* master_tls = ::allocate_tls((char*)initial_tls_data.data(), initial_tls_data.size());
|
||||
|
@ -282,14 +282,14 @@ static Result<NonnullRefPtr<DynamicLoader>, DlErrorMessage> load_main_library(co
|
|||
}
|
||||
|
||||
for (auto& loader : loaders) {
|
||||
bool success = loader.link(flags, s_total_tls_size);
|
||||
bool success = loader.link(flags);
|
||||
if (!success) {
|
||||
return DlErrorMessage { String::formatted("Failed to link library {}", loader.filename()) };
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& loader : loaders) {
|
||||
auto result = loader.load_stage_3(flags, s_total_tls_size);
|
||||
auto result = loader.load_stage_3(flags);
|
||||
VERIFY(!result.is_error());
|
||||
auto& object = result.value();
|
||||
|
||||
|
|
|
@ -146,12 +146,12 @@ RefPtr<DynamicObject> DynamicLoader::map()
|
|||
return m_dynamic_object;
|
||||
}
|
||||
|
||||
bool DynamicLoader::link(unsigned flags, size_t total_tls_size)
|
||||
bool DynamicLoader::link(unsigned flags)
|
||||
{
|
||||
return load_stage_2(flags, total_tls_size);
|
||||
return load_stage_2(flags);
|
||||
}
|
||||
|
||||
bool DynamicLoader::load_stage_2(unsigned flags, size_t total_tls_size)
|
||||
bool DynamicLoader::load_stage_2(unsigned flags)
|
||||
{
|
||||
VERIFY(flags & RTLD_GLOBAL);
|
||||
|
||||
|
@ -173,14 +173,14 @@ bool DynamicLoader::load_stage_2(unsigned flags, size_t total_tls_size)
|
|||
}
|
||||
}
|
||||
}
|
||||
do_main_relocations(total_tls_size);
|
||||
do_main_relocations();
|
||||
return true;
|
||||
}
|
||||
|
||||
void DynamicLoader::do_main_relocations(size_t total_tls_size)
|
||||
void DynamicLoader::do_main_relocations()
|
||||
{
|
||||
auto do_single_relocation = [&](const ELF::DynamicObject::Relocation& relocation) {
|
||||
switch (do_relocation(total_tls_size, relocation, ShouldInitializeWeak::No)) {
|
||||
switch (do_relocation(relocation, ShouldInitializeWeak::No)) {
|
||||
case RelocationResult::Failed:
|
||||
dbgln("Loader.so: {} unresolved symbol '{}'", m_filename, relocation.symbol().name());
|
||||
VERIFY_NOT_REACHED();
|
||||
|
@ -196,9 +196,9 @@ void DynamicLoader::do_main_relocations(size_t total_tls_size)
|
|||
m_dynamic_object->plt_relocation_section().for_each_relocation(do_single_relocation);
|
||||
}
|
||||
|
||||
Result<NonnullRefPtr<DynamicObject>, DlErrorMessage> DynamicLoader::load_stage_3(unsigned flags, size_t total_tls_size)
|
||||
Result<NonnullRefPtr<DynamicObject>, DlErrorMessage> DynamicLoader::load_stage_3(unsigned flags)
|
||||
{
|
||||
do_lazy_relocations(total_tls_size);
|
||||
do_lazy_relocations();
|
||||
if (flags & RTLD_LAZY) {
|
||||
if (m_dynamic_object->has_plt())
|
||||
setup_plt_trampoline();
|
||||
|
@ -230,10 +230,10 @@ void DynamicLoader::load_stage_4()
|
|||
call_object_init_functions();
|
||||
}
|
||||
|
||||
void DynamicLoader::do_lazy_relocations(size_t total_tls_size)
|
||||
void DynamicLoader::do_lazy_relocations()
|
||||
{
|
||||
for (const auto& relocation : m_unresolved_relocations) {
|
||||
if (auto res = do_relocation(total_tls_size, relocation, ShouldInitializeWeak::Yes); res != RelocationResult::Success) {
|
||||
if (auto res = do_relocation(relocation, ShouldInitializeWeak::Yes); res != RelocationResult::Success) {
|
||||
dbgln("Loader.so: {} unresolved symbol '{}'", m_filename, relocation.symbol().name());
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
@ -389,7 +389,7 @@ void DynamicLoader::load_program_headers()
|
|||
// FIXME: Initialize the values in the TLS section. Currently, it is zeroed.
|
||||
}
|
||||
|
||||
DynamicLoader::RelocationResult DynamicLoader::do_relocation(size_t total_tls_size, const ELF::DynamicObject::Relocation& relocation, ShouldInitializeWeak should_initialize_weak)
|
||||
DynamicLoader::RelocationResult DynamicLoader::do_relocation(const ELF::DynamicObject::Relocation& relocation, ShouldInitializeWeak should_initialize_weak)
|
||||
{
|
||||
FlatPtr* patch_ptr = nullptr;
|
||||
if (is_dynamic())
|
||||
|
@ -462,7 +462,7 @@ DynamicLoader::RelocationResult DynamicLoader::do_relocation(size_t total_tls_si
|
|||
break;
|
||||
auto* dynamic_object_of_symbol = res.value().dynamic_object;
|
||||
VERIFY(dynamic_object_of_symbol);
|
||||
*patch_ptr = negative_offset_from_tls_block_end(res.value().value, dynamic_object_of_symbol->tls_offset().value(), total_tls_size);
|
||||
*patch_ptr = negative_offset_from_tls_block_end(res.value().value, dynamic_object_of_symbol->tls_offset().value(), res.value().size);
|
||||
break;
|
||||
}
|
||||
case R_386_JMP_SLOT: {
|
||||
|
@ -487,15 +487,16 @@ DynamicLoader::RelocationResult DynamicLoader::do_relocation(size_t total_tls_si
|
|||
return RelocationResult::Success;
|
||||
}
|
||||
|
||||
ssize_t DynamicLoader::negative_offset_from_tls_block_end(size_t value_of_symbol, size_t tls_offset, size_t total_tls_size) const
|
||||
ssize_t DynamicLoader::negative_offset_from_tls_block_end(size_t value_of_symbol, size_t tls_offset, size_t symbol_size) const
|
||||
{
|
||||
auto negative_offset = static_cast<ssize_t>(tls_offset + value_of_symbol - total_tls_size);
|
||||
// Offset has to be strictly negative. Otherwise we'd collide with the thread's ThreadSpecificData structure.
|
||||
VERIFY(negative_offset < 0);
|
||||
return negative_offset;
|
||||
VERIFY(symbol_size > 0);
|
||||
ssize_t offset = -static_cast<ssize_t>(value_of_symbol + tls_offset + symbol_size);
|
||||
// At offset 0 there's the thread's ThreadSpecificData structure, we don't want to collide with it.
|
||||
VERIFY(offset < 0);
|
||||
return offset;
|
||||
}
|
||||
|
||||
void DynamicLoader::copy_initial_tls_data_into(ByteBuffer& buffer, size_t total_tls_size) const
|
||||
void DynamicLoader::copy_initial_tls_data_into(ByteBuffer& buffer) const
|
||||
{
|
||||
const u8* tls_data = nullptr;
|
||||
size_t tls_size_in_image = 0;
|
||||
|
@ -512,11 +513,11 @@ void DynamicLoader::copy_initial_tls_data_into(ByteBuffer& buffer, size_t total_
|
|||
if (!tls_data || !tls_size_in_image)
|
||||
return;
|
||||
|
||||
m_elf_image.for_each_symbol([this, &buffer, total_tls_size, tls_data](ELF::Image::Symbol symbol) {
|
||||
m_elf_image.for_each_symbol([this, &buffer, tls_data](ELF::Image::Symbol symbol) {
|
||||
if (symbol.type() != STT_TLS)
|
||||
return IterationDecision::Continue;
|
||||
|
||||
ssize_t negative_offset = negative_offset_from_tls_block_end(symbol.value(), m_tls_offset, total_tls_size);
|
||||
ssize_t negative_offset = negative_offset_from_tls_block_end(symbol.value(), m_tls_offset, symbol.size());
|
||||
VERIFY(symbol.size() != 0);
|
||||
VERIFY(buffer.size() + negative_offset + symbol.size() <= buffer.size());
|
||||
memcpy(buffer.data() + buffer.size() + negative_offset, tls_data + symbol.value(), symbol.size());
|
||||
|
@ -576,7 +577,8 @@ Optional<DynamicObject::SymbolLookupResult> DynamicLoader::lookup_symbol(const E
|
|||
{
|
||||
if (symbol.is_undefined() || symbol.bind() == STB_WEAK)
|
||||
return DynamicLinker::lookup_global_symbol(symbol.name());
|
||||
return DynamicObject::SymbolLookupResult { symbol.value(), symbol.address(), symbol.bind(), &symbol.object() };
|
||||
|
||||
return DynamicObject::SymbolLookupResult { symbol.value(), symbol.size(), symbol.address(), symbol.bind(), &symbol.object() };
|
||||
}
|
||||
|
||||
} // end namespace ELF
|
||||
|
|
|
@ -54,13 +54,13 @@ public:
|
|||
// Note that the DynamicObject will not be linked yet. Callers are responsible for calling link() to finish it.
|
||||
RefPtr<DynamicObject> map();
|
||||
|
||||
bool link(unsigned flags, size_t total_tls_size);
|
||||
bool link(unsigned flags);
|
||||
|
||||
// Stage 2 of loading: dynamic object loading and primary relocations
|
||||
bool load_stage_2(unsigned flags, size_t total_tls_size);
|
||||
bool load_stage_2(unsigned flags);
|
||||
|
||||
// Stage 3 of loading: lazy relocations
|
||||
Result<NonnullRefPtr<DynamicObject>, DlErrorMessage> load_stage_3(unsigned flags, size_t total_tls_size);
|
||||
Result<NonnullRefPtr<DynamicObject>, DlErrorMessage> load_stage_3(unsigned flags);
|
||||
|
||||
// Stage 4 of loading: initializers
|
||||
void load_stage_4();
|
||||
|
@ -78,7 +78,7 @@ public:
|
|||
bool is_dynamic() const { return m_elf_image.is_dynamic(); }
|
||||
|
||||
static Optional<DynamicObject::SymbolLookupResult> lookup_symbol(const ELF::DynamicObject::Symbol&);
|
||||
void copy_initial_tls_data_into(ByteBuffer& buffer, size_t total_tls_size) const;
|
||||
void copy_initial_tls_data_into(ByteBuffer& buffer) const;
|
||||
|
||||
private:
|
||||
DynamicLoader(int fd, String filename, void* file_data, size_t file_size);
|
||||
|
@ -113,10 +113,10 @@ private:
|
|||
void load_program_headers();
|
||||
|
||||
// Stage 2
|
||||
void do_main_relocations(size_t total_tls_size);
|
||||
void do_main_relocations();
|
||||
|
||||
// Stage 3
|
||||
void do_lazy_relocations(size_t total_tls_size);
|
||||
void do_lazy_relocations();
|
||||
void setup_plt_trampoline();
|
||||
|
||||
// Stage 4
|
||||
|
@ -129,9 +129,9 @@ private:
|
|||
Success = 1,
|
||||
ResolveLater = 2,
|
||||
};
|
||||
RelocationResult do_relocation(size_t total_tls_size, const DynamicObject::Relocation&, ShouldInitializeWeak should_initialize_weak);
|
||||
RelocationResult do_relocation(const DynamicObject::Relocation&, ShouldInitializeWeak should_initialize_weak);
|
||||
size_t calculate_tls_size() const;
|
||||
ssize_t negative_offset_from_tls_block_end(size_t value_of_symbol, size_t tls_offset, size_t total_tls_size) const;
|
||||
ssize_t negative_offset_from_tls_block_end(size_t value_of_symbol, size_t tls_offset, size_t symbol_size) const;
|
||||
|
||||
String m_filename;
|
||||
String m_program_interpreter;
|
||||
|
|
|
@ -440,7 +440,7 @@ auto DynamicObject::lookup_symbol(const HashSymbol& symbol) const -> Optional<Sy
|
|||
auto symbol_result = result.value();
|
||||
if (symbol_result.is_undefined())
|
||||
return {};
|
||||
return SymbolLookupResult { symbol_result.value(), symbol_result.address(), symbol_result.bind(), this };
|
||||
return SymbolLookupResult { symbol_result.value(), symbol_result.size(), symbol_result.address(), symbol_result.bind(), this };
|
||||
}
|
||||
|
||||
NonnullRefPtr<DynamicObject> DynamicObject::create(const String& filename, VirtualAddress base_address, VirtualAddress dynamic_section_address)
|
||||
|
|
|
@ -264,6 +264,7 @@ public:
|
|||
|
||||
struct SymbolLookupResult {
|
||||
FlatPtr value { 0 };
|
||||
size_t size { 0 };
|
||||
VirtualAddress address;
|
||||
unsigned bind { STB_LOCAL };
|
||||
const ELF::DynamicObject* dynamic_object { nullptr }; // The object in which the symbol is defined
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue