Kaynağa Gözat

LibELF: Implement support for RELA relocations

Gunnar Beutner 4 yıl önce
ebeveyn
işleme
f9a8c6f053

+ 8 - 2
Userland/Libraries/LibELF/DynamicLoader.cpp

@@ -422,7 +422,10 @@ DynamicLoader::RelocationResult DynamicLoader::do_relocation(const ELF::DynamicO
             return RelocationResult::Failed;
             return RelocationResult::Failed;
         }
         }
         auto symbol_address = res.value().address;
         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;
         break;
     }
     }
 #ifndef __LP64__
 #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.
         // 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
         //     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 :)
         //     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;
         break;
     }
     }
 #ifndef __LP64__
 #ifndef __LP64__

+ 8 - 6
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();
             m_plt_relocation_offset_location = entry.ptr() - (FlatPtr)m_elf_base_address.as_ptr();
             break;
             break;
         case DT_RELA:
         case DT_RELA:
+            m_addend_used = true;
+            [[fallthrough]];
         case DT_REL:
         case DT_REL:
             m_relocation_table_offset = entry.ptr() - (FlatPtr)m_elf_base_address.as_ptr();
             m_relocation_table_offset = entry.ptr() - (FlatPtr)m_elf_base_address.as_ptr();
             break;
             break;
@@ -189,15 +191,15 @@ DynamicObject::Relocation DynamicObject::RelocationSection::relocation(unsigned
 {
 {
     VERIFY(index < entry_count());
     VERIFY(index < entry_count());
     unsigned offset_in_section = index * entry_size();
     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
 DynamicObject::Relocation DynamicObject::RelocationSection::relocation_at_offset(unsigned offset) const
 {
 {
     VERIFY(offset <= (m_section_size_bytes - m_entry_size));
     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
 DynamicObject::Symbol DynamicObject::symbol(unsigned index) const
@@ -229,12 +231,12 @@ DynamicObject::Section DynamicObject::fini_array_section() const
 
 
 DynamicObject::RelocationSection DynamicObject::relocation_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
 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
 ElfW(Half) DynamicObject::program_header_count() const

+ 17 - 3
Userland/Libraries/LibELF/DynamicObject.h

@@ -133,8 +133,9 @@ public:
 
 
     class RelocationSection : public Section {
     class RelocationSection : public Section {
     public:
     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)
             : 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(); }
         unsigned relocation_count() const { return entry_count(); }
@@ -145,14 +146,18 @@ public:
         void for_each_relocation(F) const;
         void for_each_relocation(F) const;
         template<VoidFunction<DynamicObject::Relocation&> F>
         template<VoidFunction<DynamicObject::Relocation&> F>
         void for_each_relocation(F func) const;
         void for_each_relocation(F func) const;
+
+    private:
+        const bool m_addend_used;
     };
     };
 
 
     class Relocation {
     class Relocation {
     public:
     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_dynamic(dynamic)
             , m_rel(rel)
             , m_rel(rel)
             , m_offset_in_section(offset_in_section)
             , 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); }
         unsigned symbol_index() const { return ELF64_R_SYM(m_rel.r_info); }
 #endif
 #endif
+        unsigned addend() const
+        {
+            VERIFY(m_addend_used);
+            return m_rel.r_addend;
+        }
+        bool addend_used() const { return m_addend_used; }
+
         Symbol symbol() const
         Symbol symbol() const
         {
         {
             return m_dynamic.symbol(symbol_index());
             return m_dynamic.symbol(symbol_index());
@@ -186,8 +198,9 @@ public:
 
 
     private:
     private:
         const DynamicObject& m_dynamic;
         const DynamicObject& m_dynamic;
-        const ElfW(Rel) & m_rel;
+        const ElfW(Rela) & m_rel;
         const unsigned m_offset_in_section;
         const unsigned m_offset_in_section;
+        const bool m_addend_used;
     };
     };
 
 
     enum class HashType {
     enum class HashType {
@@ -357,6 +370,7 @@ private:
     size_t m_number_of_relocations { 0 };
     size_t m_number_of_relocations { 0 };
     size_t m_size_of_relocation_entry { 0 };
     size_t m_size_of_relocation_entry { 0 };
     size_t m_size_of_relocation_table { 0 };
     size_t m_size_of_relocation_table { 0 };
+    bool m_addend_used { false };
     FlatPtr m_relocation_table_offset { 0 };
     FlatPtr m_relocation_table_offset { 0 };
     bool m_is_elf_dynamic { false };
     bool m_is_elf_dynamic { false };