blob: 46c324c4905998936a716ada163ba81a11d69051 [file] [log] [blame]
Dmitriy Ivanov87a06172015-02-06 10:56:28 -08001// 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
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -08005// Delta encode and decode REL/RELA section of elf file.
Dmitriy Ivanov87a06172015-02-06 10:56:28 -08006//
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -08007// The encoded data format is sequence of elements of ElfAddr type (unsigned long):
Dmitriy Ivanov87a06172015-02-06 10:56:28 -08008//
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -08009// [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
Dmitriy Ivanov87a06172015-02-06 10:56:28 -080025//
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -080026// 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.
Dmitriy Ivanov87a06172015-02-06 10:56:28 -080029//
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -080030// 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
Dmitriy Ivanov87a06172015-02-06 10:56:28 -080034//
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -080035// For example lets pack the following relocations:
Dmitriy Ivanov87a06172015-02-06 10:56:28 -080036//
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -080037// 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
Dmitriy Ivanov87a06172015-02-06 10:56:28 -080053//
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -080054// 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
Dmitriy Ivanov87a06172015-02-06 10:56:28 -080085
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
94namespace 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.
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -080099template <typename ELF>
Dmitriy Ivanov87a06172015-02-06 10:56:28 -0800100class RelocationDeltaCodec {
101 public:
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -0800102 typedef typename ELF::Addr ElfAddr;
103 typedef typename ELF::Rela ElfRela;
104
105 // Encode relocations with addends into a more compact form.
Dmitriy Ivanov87a06172015-02-06 10:56:28 -0800106 // |relocations| is a vector of relative relocation with addend structs.
107 // |packed| is the vector of packed words into which relocations are packed.
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -0800108 static void Encode(const std::vector<ElfRela>& relocations,
109 std::vector<ElfAddr>* packed);
Dmitriy Ivanov87a06172015-02-06 10:56:28 -0800110
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.
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -0800114 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);
Dmitriy Ivanov87a06172015-02-06 10:56:28 -0800128};
129
130} // namespace relocation_packer
131
132#endif // TOOLS_RELOCATION_PACKER_SRC_DELTA_ENCODER_H_