summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibELF/DynamicObject.h
diff options
context:
space:
mode:
authorDaniel Bertalan <dani@danielbertalan.dev>2021-10-28 09:31:51 +0200
committerAndreas Kling <kling@serenityos.org>2022-02-11 18:07:53 +0100
commit3974cac148ff12f04fd98fa3a1c4578767988897 (patch)
treed3c262e97055e52a1aba8061402153382c7e2899 /Userland/Libraries/LibELF/DynamicObject.h
parent32b8795091681de7296074fb9a7b4f63a17e475a (diff)
downloadserenity-3974cac148ff12f04fd98fa3a1c4578767988897.zip
LibELF: Implement support for DT_RELR relative relocations
The DT_RELR relocation is a relatively new relocation encoding designed to achieve space-efficient relative relocations in PIE programs. The description of the format is available here: https://groups.google.com/g/generic-abi/c/bX460iggiKg/m/Pi9aSwwABgAJ It works by using a bitmap to store the offsets which need to be relocated. Even entries are *address* entries: they contain an address (relative to the base of the executable) which needs to be relocated. Subsequent even entries are *bitmap* entries: "1" bits encode offsets (in word size increments) relative to the last address entry which need to be relocated. This is in contrast to the REL/RELA format, where each entry takes up 2/3 machine words. Certain kinds of relocations store useful data in that space (like the name of the referenced symbol), so not everything can be encoded in this format. But as position-independent executables and shared libraries tend to have a lot of relative relocations, a specialized encoding for them absolutely makes sense. The authors of the format suggest an overall 5-20% reduction in the file size of various programs. Due to our extensive use of dynamic linking and us not stripping debug info, relative relocations don't make up such a large portion of the binary's size, so the measurements will tend to skew to the lower side of the spectrum. The following measurements were made with the x86-64 Clang toolchain: - The kernel contains 290989 relocations. Enabling RELR decreased its size from 30 MiB to 23 MiB. - LibUnicodeData contains 190262 relocations, almost all of them relative. Its file size changed from 17 MiB to 13 MiB. - /bin/WebContent contains 1300 relocations, 66% of which are relative relocations. With RELR, its size changed from 832 KiB to 812 KiB. This change was inspired by the following blog post: https://maskray.me/blog/2021-10-31-relative-relocations-and-relr
Diffstat (limited to 'Userland/Libraries/LibELF/DynamicObject.h')
-rw-r--r--Userland/Libraries/LibELF/DynamicObject.h36
1 files changed, 36 insertions, 0 deletions
diff --git a/Userland/Libraries/LibELF/DynamicObject.h b/Userland/Libraries/LibELF/DynamicObject.h
index bc1b3a7a57..24fb27d785 100644
--- a/Userland/Libraries/LibELF/DynamicObject.h
+++ b/Userland/Libraries/LibELF/DynamicObject.h
@@ -272,6 +272,7 @@ public:
RelocationSection relocation_section() const;
RelocationSection plt_relocation_section() const;
+ Section relr_relocation_section() const;
bool should_process_origin() const { return m_dt_flags & DF_ORIGIN; }
bool requires_symbolic_symbol_resolution() const { return m_dt_flags & DF_SYMBOLIC; }
@@ -312,6 +313,9 @@ public:
template<VoidFunction<Symbol&> F>
void for_each_symbol(F) const;
+ template<typename F>
+ void for_each_relr_relocation(F) const;
+
struct SymbolLookupResult {
FlatPtr value { 0 };
size_t size { 0 };
@@ -374,6 +378,9 @@ private:
size_t m_size_of_relocation_table { 0 };
bool m_addend_used { false };
FlatPtr m_relocation_table_offset { 0 };
+ size_t m_size_of_relr_relocations_entry { 0 };
+ size_t m_size_of_relr_relocation_table { 0 };
+ FlatPtr m_relr_relocation_table_offset { 0 };
bool m_is_elf_dynamic { false };
// DT_FLAGS
@@ -412,6 +419,35 @@ inline void DynamicObject::RelocationSection::for_each_relocation(F func) const
});
}
+template<typename F>
+inline void DynamicObject::for_each_relr_relocation(F f) const
+{
+ auto section = relr_relocation_section();
+ if (section.entry_count() == 0)
+ return;
+
+ VERIFY(section.entry_size() == sizeof(FlatPtr));
+ VERIFY(section.size() >= section.entry_size() * section.entry_count());
+
+ auto* entries = reinterpret_cast<ElfW(Relr)*>(section.address().get());
+ auto base = base_address().get();
+ FlatPtr patch_addr = 0;
+ for (unsigned i = 0; i < section.entry_count(); ++i) {
+ if ((entries[i] & 1u) == 0) {
+ patch_addr = base + entries[i];
+ f(patch_addr);
+ patch_addr += sizeof(FlatPtr);
+ } else {
+ unsigned j = 0;
+ for (auto bitmap = entries[i]; (bitmap >>= 1u) != 0; ++j)
+ if (bitmap & 1u)
+ f(patch_addr + j * sizeof(FlatPtr));
+
+ patch_addr += (8 * sizeof(FlatPtr) - 1) * sizeof(FlatPtr);
+ }
+ }
+}
+
template<VoidFunction<DynamicObject::Symbol&> F>
inline void DynamicObject::for_each_symbol(F func) const
{