// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Delta encode and decode REL/RELA section of elf file. // // The encoded data format is sequence of elements of ElfAddr type (unsigned long): // // [00] relocation_count - the total count of relocations // [01] initial r_offset - this is initial r_offset for the // relocation table. // followed by group structures: // [02] group // ... // [nn] group // the generalized format of the group is (! - always present ? - depends on group_flags): // -------------- // ! group_size // ! group_flags // ? group_r_offset_delta when RELOCATION_GROUPED_BY_OFFSET_DELTA flag is set // ? group_r_info when RELOCATION_GROUPED_BY_INFO flag is set // ? group_r_addend_group_delta when RELOCATION_GROUP_HAS_ADDEND and RELOCATION_GROUPED_BY_ADDEND // flag is set // // The group description is followed by individual relocations. // please note that there is a case when individual relocation // section could be empty - that is if every field ends up grouped. // // The format for individual relocations section is: // ? r_offset_delta - when RELOCATION_GROUPED_BY_OFFSET_DELTA is not set // ? r_info - when RELOCATION_GROUPED_BY_INFO flag is not set // ? r_addend_delta - RELOCATION_GROUP_HAS_ADDEND is set and RELOCATION_GROUPED_BY_ADDEND is not set // // For example lets pack the following relocations: // // Relocation section '.rela.dyn' at offset 0xbf58 contains 939 entries: // Offset Info Type Symbol's Value Symbol's Name + Addend // 00000000000a2178 0000000000000403 R_AARCH64_RELATIVE 177a8 // 00000000000a2180 0000000000000403 R_AARCH64_RELATIVE 177cc // 00000000000a2188 0000000000000403 R_AARCH64_RELATIVE 177e0 // 00000000000a2190 0000000000000403 R_AARCH64_RELATIVE 177f4 // 00000000000a2198 0000000000000403 R_AARCH64_RELATIVE 17804 // 00000000000a21a0 0000000000000403 R_AARCH64_RELATIVE 17818 // 00000000000a21a8 0000000000000403 R_AARCH64_RELATIVE 1782c // 00000000000a21b0 0000000000000403 R_AARCH64_RELATIVE 17840 // 00000000000a21b8 0000000000000403 R_AARCH64_RELATIVE 17854 // 00000000000a21c0 0000000000000403 R_AARCH64_RELATIVE 17868 // 00000000000a21c8 0000000000000403 R_AARCH64_RELATIVE 1787c // 00000000000a21d0 0000000000000403 R_AARCH64_RELATIVE 17890 // 00000000000a21d8 0000000000000403 R_AARCH64_RELATIVE 178a4 // 00000000000a21e8 0000000000000403 R_AARCH64_RELATIVE 178b8 // // The header is going to be // [00] 14 <- count // [01] 0x00000000000a2170 <- initial relocation (first relocation - delta, // the delta is 8 in this case) // -- starting the first and only group // [03] 14 <- group size // [03] 0xb <- flags RELOCATION_GROUP_HAS_ADDEND | RELOCATION_GROUPED_BY_OFFSET_DELTA // | RELOCATION_GROUPED_BY_INFO // [04] 8 <- offset delta // [05] 0x403 <- r_info // -- end of group definition, starting list of r_addend deltas // [06] 0x177a8 // [07] 0x24 = 177cc - 177a8 // [08] 0x14 = 177e0 - 177cc // [09] 0x14 = 177f4 - 177e0 // [10] 0x10 = 17804 - 177f4 // [11] 0x14 = 17818 - 17804 // [12] 0x14 = 1782c - 17818 // [13] 0x14 = 17840 - 1782c // [14] 0x14 = 17854 - 17840 // [15] 0x14 = 17868 - 17854 // [16] 0x14 = 1787c - 17868 // [17] 0x14 = 17890 - 1787c // [18] 0x14 = 178a4 - 17890 // [19] 0x14 = 178b8 - 178a4 // -- the end. // TODO (dimitry): consider using r_addend_group_delta in the way we use group offset delta, it can // save us more bytes... // The input ends when sum(group_size) == relocation_count #ifndef TOOLS_RELOCATION_PACKER_SRC_DELTA_ENCODER_H_ #define TOOLS_RELOCATION_PACKER_SRC_DELTA_ENCODER_H_ #include <vector> #include "elf.h" #include "elf_traits.h" namespace relocation_packer { // A RelocationDeltaCodec packs vectors of relative relocations with // addends into more compact forms, and unpacks them to reproduce the // pre-packed data. template <typename ELF> class RelocationDeltaCodec { public: typedef typename ELF::Addr ElfAddr; typedef typename ELF::Rela ElfRela; // Encode relocations with addends into a more compact form. // |relocations| is a vector of relative relocation with addend structs. // |packed| is the vector of packed words into which relocations are packed. static void Encode(const std::vector<ElfRela>& relocations, std::vector<ElfAddr>* packed); // Decode relative relocations with addends from their more compact form. // |packed| is the vector of packed relocations. // |relocations| is a vector of unpacked relative relocations. static void Decode(const std::vector<ElfAddr>& packed, std::vector<ElfRela>* relocations); private: static void DetectGroup(const std::vector<ElfRela>& relocations, size_t group_starts_with, ElfAddr previous_offset, ElfAddr* group_size, ElfAddr* group_flags, ElfAddr* group_offset_delta, ElfAddr* group_info, ElfAddr* group_addend); static void DetectGroupFields(const ElfRela& reloc_one, const ElfRela& reloc_two, ElfAddr current_offset_delta, ElfAddr* group_flags, ElfAddr* group_offset_delta, ElfAddr* group_info, ElfAddr* group_addend); }; } // namespace relocation_packer #endif // TOOLS_RELOCATION_PACKER_SRC_DELTA_ENCODER_H_