Home | History | Annotate | Download | only in src
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Delta encode and decode REL/RELA section of elf file.
      6 //
      7 // The encoded data format is sequence of elements of ElfAddr type (unsigned long):
      8 //
      9 // [00] relocation_count - the total count of relocations
     10 // [01] initial r_offset - this is initial r_offset for the
     11 //                         relocation table.
     12 // followed by group structures:
     13 // [02] group
     14 // ...
     15 // [nn] group
     16 
     17 // the generalized format of the group is (! - always present ? - depends on group_flags):
     18 // --------------
     19 // ! group_size
     20 // ! group_flags
     21 // ? group_r_offset_delta when RELOCATION_GROUPED_BY_OFFSET_DELTA flag is set
     22 // ? group_r_info when RELOCATION_GROUPED_BY_INFO flag is set
     23 // ? group_r_addend_group_delta when RELOCATION_GROUP_HAS_ADDEND and RELOCATION_GROUPED_BY_ADDEND
     24 //   flag is set
     25 //
     26 // The group description is followed by individual relocations.
     27 // please note that there is a case when individual relocation
     28 // section could be empty - that is if every field ends up grouped.
     29 //
     30 // The format for individual relocations section is:
     31 // ? r_offset_delta - when RELOCATION_GROUPED_BY_OFFSET_DELTA is not set
     32 // ? r_info - when RELOCATION_GROUPED_BY_INFO flag is not set
     33 // ? r_addend_delta - RELOCATION_GROUP_HAS_ADDEND is set and RELOCATION_GROUPED_BY_ADDEND is not set
     34 //
     35 // For example lets pack the following relocations:
     36 //
     37 // Relocation section '.rela.dyn' at offset 0xbf58 contains 939 entries:
     38 //     Offset             Info             Type               Symbol's Value  Symbol's Name + Addend
     39 //     00000000000a2178  0000000000000403 R_AARCH64_RELATIVE                        177a8
     40 //     00000000000a2180  0000000000000403 R_AARCH64_RELATIVE                        177cc
     41 //     00000000000a2188  0000000000000403 R_AARCH64_RELATIVE                        177e0
     42 //     00000000000a2190  0000000000000403 R_AARCH64_RELATIVE                        177f4
     43 //     00000000000a2198  0000000000000403 R_AARCH64_RELATIVE                        17804
     44 //     00000000000a21a0  0000000000000403 R_AARCH64_RELATIVE                        17818
     45 //     00000000000a21a8  0000000000000403 R_AARCH64_RELATIVE                        1782c
     46 //     00000000000a21b0  0000000000000403 R_AARCH64_RELATIVE                        17840
     47 //     00000000000a21b8  0000000000000403 R_AARCH64_RELATIVE                        17854
     48 //     00000000000a21c0  0000000000000403 R_AARCH64_RELATIVE                        17868
     49 //     00000000000a21c8  0000000000000403 R_AARCH64_RELATIVE                        1787c
     50 //     00000000000a21d0  0000000000000403 R_AARCH64_RELATIVE                        17890
     51 //     00000000000a21d8  0000000000000403 R_AARCH64_RELATIVE                        178a4
     52 //     00000000000a21e8  0000000000000403 R_AARCH64_RELATIVE                        178b8
     53 //
     54 // The header is going to be
     55 // [00] 14                 <- count
     56 // [01] 0x00000000000a2170 <- initial relocation (first relocation - delta,
     57 //                            the delta is 8 in this case)
     58 // -- starting the first and only group
     59 // [03] 14                 <- group size
     60 // [03] 0xb                <- flags RELOCATION_GROUP_HAS_ADDEND | RELOCATION_GROUPED_BY_OFFSET_DELTA
     61 //                            | RELOCATION_GROUPED_BY_INFO
     62 // [04] 8                  <- offset delta
     63 // [05] 0x403              <- r_info
     64 // -- end of group definition, starting list of r_addend deltas
     65 // [06] 0x177a8
     66 // [07] 0x24               = 177cc - 177a8
     67 // [08] 0x14               = 177e0 - 177cc
     68 // [09] 0x14               = 177f4 - 177e0
     69 // [10] 0x10               = 17804 - 177f4
     70 // [11] 0x14               = 17818 - 17804
     71 // [12] 0x14               = 1782c - 17818
     72 // [13] 0x14               = 17840 - 1782c
     73 // [14] 0x14               = 17854 - 17840
     74 // [15] 0x14               = 17868 - 17854
     75 // [16] 0x14               = 1787c - 17868
     76 // [17] 0x14               = 17890 - 1787c
     77 // [18] 0x14               = 178a4 - 17890
     78 // [19] 0x14               = 178b8 - 178a4
     79 // -- the end.
     80 
     81 // TODO (dimitry): consider using r_addend_group_delta in the way we use group offset delta, it can
     82 //                 save us more bytes...
     83 
     84 // The input ends when sum(group_size) == relocation_count
     85 
     86 #ifndef TOOLS_RELOCATION_PACKER_SRC_DELTA_ENCODER_H_
     87 #define TOOLS_RELOCATION_PACKER_SRC_DELTA_ENCODER_H_
     88 
     89 #include <vector>
     90 
     91 #include "elf.h"
     92 #include "elf_traits.h"
     93 
     94 namespace relocation_packer {
     95 
     96 // A RelocationDeltaCodec packs vectors of relative relocations with
     97 // addends into more compact forms, and unpacks them to reproduce the
     98 // pre-packed data.
     99 template <typename ELF>
    100 class RelocationDeltaCodec {
    101  public:
    102   typedef typename ELF::Addr ElfAddr;
    103   typedef typename ELF::Rela ElfRela;
    104 
    105   // Encode relocations with addends into a more compact form.
    106   // |relocations| is a vector of relative relocation with addend structs.
    107   // |packed| is the vector of packed words into which relocations are packed.
    108   static void Encode(const std::vector<ElfRela>& relocations,
    109                      std::vector<ElfAddr>* packed);
    110 
    111   // Decode relative relocations with addends from their more compact form.
    112   // |packed| is the vector of packed relocations.
    113   // |relocations| is a vector of unpacked relative relocations.
    114   static void Decode(const std::vector<ElfAddr>& packed,
    115                      std::vector<ElfRela>* relocations);
    116 
    117  private:
    118   static void DetectGroup(const std::vector<ElfRela>& relocations,
    119                           size_t group_starts_with, ElfAddr previous_offset,
    120                           ElfAddr* group_size, ElfAddr* group_flags,
    121                           ElfAddr* group_offset_delta, ElfAddr* group_info,
    122                           ElfAddr* group_addend);
    123 
    124   static void DetectGroupFields(const ElfRela& reloc_one, const ElfRela& reloc_two,
    125                                 ElfAddr current_offset_delta, ElfAddr* group_flags,
    126                                 ElfAddr* group_offset_delta, ElfAddr* group_info,
    127                                 ElfAddr* group_addend);
    128 };
    129 
    130 }  // namespace relocation_packer
    131 
    132 #endif  // TOOLS_RELOCATION_PACKER_SRC_DELTA_ENCODER_H_
    133