summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGunnar Beutner <gbeutner@serenityos.org>2021-07-01 02:24:11 +0200
committerAndreas Kling <kling@serenityos.org>2021-07-01 10:50:00 +0200
commitf9a8c6f0535bf46b78a068b9cec35be47ff0350a (patch)
tree939fe1e7e96c11b6ccd0f98c35f7415106df2073
parent1f93ffcd729d778c68f6ed8cca161cd4907e1c66 (diff)
downloadserenity-f9a8c6f0535bf46b78a068b9cec35be47ff0350a.zip
LibELF: Implement support for RELA relocations
-rw-r--r--Userland/Libraries/LibELF/DynamicLoader.cpp10
-rw-r--r--Userland/Libraries/LibELF/DynamicObject.cpp14
-rw-r--r--Userland/Libraries/LibELF/DynamicObject.h20
3 files changed, 33 insertions, 11 deletions
diff --git a/Userland/Libraries/LibELF/DynamicLoader.cpp b/Userland/Libraries/LibELF/DynamicLoader.cpp
index 7065b60380..b09621490b 100644
--- a/Userland/Libraries/LibELF/DynamicLoader.cpp
+++ b/Userland/Libraries/LibELF/DynamicLoader.cpp
@@ -422,7 +422,10 @@ DynamicLoader::RelocationResult DynamicLoader::do_relocation(const ELF::DynamicO
return RelocationResult::Failed;
}
auto symbol_address = res.value().address;
- *patch_ptr += symbol_address.get();
+ if (relocation.addend_used())
+ *patch_ptr = symbol_address.get() + relocation.addend();
+ else
+ *patch_ptr += symbol_address.get();
break;
}
#ifndef __LP64__
@@ -466,7 +469,10 @@ DynamicLoader::RelocationResult DynamicLoader::do_relocation(const ELF::DynamicO
// FIXME: According to the spec, R_386_relative ones must be done first.
// We could explicitly do them first using m_number_of_relocations from DT_RELCOUNT
// However, our compiler is nice enough to put them at the front of the relocations for us :)
- *patch_ptr += (FlatPtr)m_dynamic_object->base_address().as_ptr(); // + addend for RelA (addend for Rel is stored at addr)
+ if (relocation.addend_used())
+ *patch_ptr = (FlatPtr)m_dynamic_object->base_address().as_ptr() + relocation.addend();
+ else
+ *patch_ptr += (FlatPtr)m_dynamic_object->base_address().as_ptr();
break;
}
#ifndef __LP64__
diff --git a/Userland/Libraries/LibELF/DynamicObject.cpp b/Userland/Libraries/LibELF/DynamicObject.cpp
index 65b10d7bab..c79cd5f04b 100644
--- a/Userland/Libraries/LibELF/DynamicObject.cpp
+++ b/Userland/Libraries/LibELF/DynamicObject.cpp
@@ -120,6 +120,8 @@ void DynamicObject::parse()
m_plt_relocation_offset_location = entry.ptr() - (FlatPtr)m_elf_base_address.as_ptr();
break;
case DT_RELA:
+ m_addend_used = true;
+ [[fallthrough]];
case DT_REL:
m_relocation_table_offset = entry.ptr() - (FlatPtr)m_elf_base_address.as_ptr();
break;
@@ -189,15 +191,15 @@ DynamicObject::Relocation DynamicObject::RelocationSection::relocation(unsigned
{
VERIFY(index < entry_count());
unsigned offset_in_section = index * entry_size();
- auto relocation_address = (ElfW(Rel)*)address().offset(offset_in_section).as_ptr();
- return Relocation(m_dynamic, *relocation_address, offset_in_section);
+ auto relocation_address = (ElfW(Rela)*)address().offset(offset_in_section).as_ptr();
+ return Relocation(m_dynamic, *relocation_address, offset_in_section, m_addend_used);
}
DynamicObject::Relocation DynamicObject::RelocationSection::relocation_at_offset(unsigned offset) const
{
VERIFY(offset <= (m_section_size_bytes - m_entry_size));
- auto relocation_address = (ElfW(Rel)*)address().offset(offset).as_ptr();
- return Relocation(m_dynamic, *relocation_address, offset);
+ auto relocation_address = (ElfW(Rela)*)address().offset(offset).as_ptr();
+ return Relocation(m_dynamic, *relocation_address, offset, m_addend_used);
}
DynamicObject::Symbol DynamicObject::symbol(unsigned index) const
@@ -229,12 +231,12 @@ DynamicObject::Section DynamicObject::fini_array_section() const
DynamicObject::RelocationSection DynamicObject::relocation_section() const
{
- return RelocationSection(Section(*this, m_relocation_table_offset, m_size_of_relocation_table, m_size_of_relocation_entry, "DT_REL"sv));
+ return RelocationSection(Section(*this, m_relocation_table_offset, m_size_of_relocation_table, m_size_of_relocation_entry, "DT_REL"sv), m_addend_used);
}
DynamicObject::RelocationSection DynamicObject::plt_relocation_section() const
{
- return RelocationSection(Section(*this, m_plt_relocation_offset_location, m_size_of_plt_relocation_entry_list, m_size_of_relocation_entry, "DT_JMPREL"sv));
+ return RelocationSection(Section(*this, m_plt_relocation_offset_location, m_size_of_plt_relocation_entry_list, m_size_of_relocation_entry, "DT_JMPREL"sv), false);
}
ElfW(Half) DynamicObject::program_header_count() const
diff --git a/Userland/Libraries/LibELF/DynamicObject.h b/Userland/Libraries/LibELF/DynamicObject.h
index 0be9bdb3d4..8c89b4214a 100644
--- a/Userland/Libraries/LibELF/DynamicObject.h
+++ b/Userland/Libraries/LibELF/DynamicObject.h
@@ -133,8 +133,9 @@ public:
class RelocationSection : public Section {
public:
- explicit RelocationSection(const Section& section)
+ explicit RelocationSection(const Section& section, bool addend_used)
: Section(section.m_dynamic, section.m_section_offset, section.m_section_size_bytes, section.m_entry_size, section.m_name)
+ , m_addend_used(addend_used)
{
}
unsigned relocation_count() const { return entry_count(); }
@@ -145,14 +146,18 @@ public:
void for_each_relocation(F) const;
template<VoidFunction<DynamicObject::Relocation&> F>
void for_each_relocation(F func) const;
+
+ private:
+ const bool m_addend_used;
};
class Relocation {
public:
- Relocation(const DynamicObject& dynamic, const ElfW(Rel) & rel, unsigned offset_in_section)
+ Relocation(const DynamicObject& dynamic, const ElfW(Rela) & rel, unsigned offset_in_section, bool addend_used)
: m_dynamic(dynamic)
, m_rel(rel)
, m_offset_in_section(offset_in_section)
+ , m_addend_used(addend_used)
{
}
@@ -173,6 +178,13 @@ public:
}
unsigned symbol_index() const { return ELF64_R_SYM(m_rel.r_info); }
#endif
+ unsigned addend() const
+ {
+ VERIFY(m_addend_used);
+ return m_rel.r_addend;
+ }
+ bool addend_used() const { return m_addend_used; }
+
Symbol symbol() const
{
return m_dynamic.symbol(symbol_index());
@@ -186,8 +198,9 @@ public:
private:
const DynamicObject& m_dynamic;
- const ElfW(Rel) & m_rel;
+ const ElfW(Rela) & m_rel;
const unsigned m_offset_in_section;
+ const bool m_addend_used;
};
enum class HashType {
@@ -357,6 +370,7 @@ private:
size_t m_number_of_relocations { 0 };
size_t m_size_of_relocation_entry { 0 };
size_t m_size_of_relocation_table { 0 };
+ bool m_addend_used { false };
FlatPtr m_relocation_table_offset { 0 };
bool m_is_elf_dynamic { false };