blob: 8dddd8b412a0583c7095774d7e2d14f5199ff1d7 [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
5#include "packer.h"
6
7#include <vector>
8#include "elf.h"
9#include "elf_traits.h"
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -080010#include "gtest/gtest.h"
Dmitriy Ivanov87a06172015-02-06 10:56:28 -080011
Dmitriy Ivanov87a06172015-02-06 10:56:28 -080012
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -080013template <typename ELF>
14static void AddRelocation(typename ELF::Addr addr,
15 typename ELF::Xword info,
16 typename ELF::Sxword addend,
17 std::vector<typename ELF::Rela>* relocations) {
18 typename ELF::Rela relocation;
Dmitriy Ivanov87a06172015-02-06 10:56:28 -080019 relocation.r_offset = addr;
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -080020 relocation.r_info = info;
Dmitriy Ivanov87a06172015-02-06 10:56:28 -080021 relocation.r_addend = addend;
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -080022
Dmitriy Ivanov87a06172015-02-06 10:56:28 -080023 relocations->push_back(relocation);
24}
25
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -080026template <typename ELF>
27static bool CheckRelocation(typename ELF::Addr addr,
28 typename ELF::Xword info,
29 typename ELF::Sxword addend,
30 const typename ELF::Rela& relocation) {
Dmitriy Ivanov87a06172015-02-06 10:56:28 -080031 return relocation.r_offset == addr &&
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -080032 relocation.r_info == info &&
Dmitriy Ivanov87a06172015-02-06 10:56:28 -080033 relocation.r_addend == addend;
34}
35
Dmitriy Ivanov87a06172015-02-06 10:56:28 -080036namespace relocation_packer {
37
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -080038template <typename ELF>
39static void DoPackNoAddend() {
40 std::vector<typename ELF::Rela> relocations;
Dmitriy Ivanov87a06172015-02-06 10:56:28 -080041 std::vector<uint8_t> packed;
Dmitriy Ivanov87a06172015-02-06 10:56:28 -080042 // Initial relocation.
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -080043 AddRelocation<ELF>(0xd1ce0000, 0x11, 0, &relocations);
Dmitriy Ivanov87a06172015-02-06 10:56:28 -080044 // Two more relocations, 4 byte deltas.
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -080045 AddRelocation<ELF>(0xd1ce0004, 0x11, 0, &relocations);
46 AddRelocation<ELF>(0xd1ce0008, 0x11, 0, &relocations);
Dmitriy Ivanov87a06172015-02-06 10:56:28 -080047 // Three more relocations, 8 byte deltas.
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -080048 AddRelocation<ELF>(0xd1ce0010, 0x11, 0, &relocations);
49 AddRelocation<ELF>(0xd1ce0018, 0x11, 0, &relocations);
50 AddRelocation<ELF>(0xd1ce0020, 0x11, 0, &relocations);
51
52 RelocationPacker<ELF> packer;
Dmitriy Ivanov87a06172015-02-06 10:56:28 -080053
54 packed.clear();
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -080055 packer.PackRelocations(relocations, &packed);
Dmitriy Ivanov87a06172015-02-06 10:56:28 -080056
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -080057 ASSERT_EQ(18U, packed.size());
Dmitriy Ivanov87a06172015-02-06 10:56:28 -080058 // Identifier.
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -080059 size_t ndx = 0;
60 EXPECT_EQ('A', packed[ndx++]);
61 EXPECT_EQ('P', packed[ndx++]);
62 EXPECT_EQ('U', packed[ndx++]);
63 EXPECT_EQ('2', packed[ndx++]);
64 // relocation count
65 EXPECT_EQ(6, packed[ndx++]);
66 // base relocation = 0xd1cdfffc -> fc, ff, b7, 8e, 0d
67 EXPECT_EQ(0xfc, packed[ndx++]);
68 EXPECT_EQ(0xff, packed[ndx++]);
69 EXPECT_EQ(0xb7, packed[ndx++]);
70 EXPECT_EQ(0x8e, packed[ndx++]);
71 EXPECT_EQ(0x0d, packed[ndx++]);
72 // first group
73 EXPECT_EQ(3, packed[ndx++]); // size
74 EXPECT_EQ(3, packed[ndx++]); // flags
75 EXPECT_EQ(4, packed[ndx++]); // r_offset_delta
76 EXPECT_EQ(0x11, packed[ndx++]); // r_info
77 // second group
78 EXPECT_EQ(3, packed[ndx++]); // size
79 EXPECT_EQ(3, packed[ndx++]); // flags
80 EXPECT_EQ(8, packed[ndx++]); // r_offset_delta
81 EXPECT_EQ(0x11, packed[ndx++]); // r_info
82
83 EXPECT_EQ(ndx, packed.size());
Dmitriy Ivanov87a06172015-02-06 10:56:28 -080084}
85
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -080086TEST(Packer, PackNoAddend) {
87 DoPackNoAddend<ELF32_traits>();
88 DoPackNoAddend<ELF64_traits>();
89}
90
91template <typename ELF>
92static void DoUnpackNoAddend() {
93 std::vector<typename ELF::Rela> relocations;
Dmitriy Ivanov87a06172015-02-06 10:56:28 -080094 std::vector<uint8_t> packed;
Dmitriy Ivanov87a06172015-02-06 10:56:28 -080095 packed.push_back('A');
96 packed.push_back('P');
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -080097 packed.push_back('U');
98 packed.push_back('2');
99 // relocation count
Dmitriy Ivanov87a06172015-02-06 10:56:28 -0800100 packed.push_back(6);
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -0800101 // base relocation = 0xd1cdfffc -> fc, ff, b7, 8e, 0d
102 packed.push_back(0xfc);
103 packed.push_back(0xff);
104 packed.push_back(0xb7);
105 packed.push_back(0x8e);
106 packed.push_back(0x0d);
107 // first group
108 packed.push_back(3); // size
109 packed.push_back(3); // flags
110 packed.push_back(4); // r_offset_delta
111 packed.push_back(0x11); // r_info
112 // second group
113 packed.push_back(3); // size
114 packed.push_back(3); // flags
115 packed.push_back(8); // r_offset_delta
116 packed.push_back(0x11); // r_info
117
118 RelocationPacker<ELF> packer;
119 packer.UnpackRelocations(packed, &relocations);
120
121 size_t ndx = 0;
122 EXPECT_EQ(6U, relocations.size());
123 EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0000, 0x11, 0, relocations[ndx++]));
124 EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0004, 0x11, 0, relocations[ndx++]));
125 EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0008, 0x11, 0, relocations[ndx++]));
126
127 EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0010, 0x11, 0, relocations[ndx++]));
128 EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0018, 0x11, 0, relocations[ndx++]));
129 EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0020, 0x11, 0, relocations[ndx++]));
130
131 EXPECT_EQ(ndx, relocations.size());
132}
133
134TEST(Packer, UnpackNoAddend) {
135 DoUnpackNoAddend<ELF32_traits>();
136 DoUnpackNoAddend<ELF64_traits>();
137}
138
139template <typename ELF>
140static void DoPackWithAddend() {
141 std::vector<typename ELF::Rela> relocations;
142
143 // Initial relocation.
144 AddRelocation<ELF>(0xd1ce0000, 0x01, 10024, &relocations);
145 // Two more relocations, 4 byte offset deltas, 12 byte addend deltas.
146 AddRelocation<ELF>(0xd1ce0004, 0x01, 10012, &relocations);
147 AddRelocation<ELF>(0xd1ce0008, 0x01, 10024, &relocations);
148 // Three more relocations, 8 byte deltas, -24 byte addend deltas.
149 AddRelocation<ELF>(0xd1ce0010, 0x01, 10000, &relocations);
150 AddRelocation<ELF>(0xd1ce0018, 0x01, 9976, &relocations);
151 AddRelocation<ELF>(0xd1ce0020, 0x01, 9952, &relocations);
152
153 std::vector<uint8_t> packed;
154
155 RelocationPacker<ELF> packer;
156
157 packed.clear();
158 packer.PackRelocations(relocations, &packed);
159
160 EXPECT_EQ(26U, packed.size());
161 size_t ndx = 0;
162 // Identifier.
163 EXPECT_EQ('A', packed[ndx++]);
164 EXPECT_EQ('P', packed[ndx++]);
165 EXPECT_EQ('S', packed[ndx++]);
166 EXPECT_EQ('2', packed[ndx++]);
167 // Relocation count
168 EXPECT_EQ(6U, packed[ndx++]);
169 // base relocation = 0xd1cdfffc -> fc, ff, b7, 8e, 0d/7d (depending on ELF::Addr)
170 EXPECT_EQ(0xfc, packed[ndx++]);
171 EXPECT_EQ(0xff, packed[ndx++]);
172 EXPECT_EQ(0xb7, packed[ndx++]);
173 EXPECT_EQ(0x8e, packed[ndx++]);
174 if (sizeof(typename ELF::Addr) == 8) {
175 // positive for uint64_t
176 EXPECT_EQ(0x0d, packed[ndx++]);
177 } else {
178 // negative for uint32_t
179 EXPECT_EQ(0x7d, packed[ndx++]);
180 }
181 // group 1
182 EXPECT_EQ(0x03, packed[ndx++]); // size
183 EXPECT_EQ(0x0b, packed[ndx++]); // flags
184 EXPECT_EQ(0x04, packed[ndx++]); // r_offset_delta
185 EXPECT_EQ(0x01, packed[ndx++]); // r_info
186 // group 1 - addend 1: 10024 = 0xa8, 0xce, 0x80
187 EXPECT_EQ(0xa8, packed[ndx++]);
188 EXPECT_EQ(0xce, packed[ndx++]);
189 EXPECT_EQ(0x00, packed[ndx++]);
190 // group 1 - addend 2: -12 = 0x74
191 EXPECT_EQ(0x74, packed[ndx++]);
192 // group 1 - addend 3: +12 = 0x0c
193 EXPECT_EQ(0x0c, packed[ndx++]);
194
195 // group 2
196 EXPECT_EQ(0x03, packed[ndx++]); // size
197 EXPECT_EQ(0x0b, packed[ndx++]); // flags
198 EXPECT_EQ(0x08, packed[ndx++]); // r_offset_delta
199 EXPECT_EQ(0x01, packed[ndx++]); // r_info
200
201 // group 2 - addend 1: -24 = 0x68
202 EXPECT_EQ(0x68, packed[ndx++]);
203 // group 2 - addend 2: -24 = 0x68
204 EXPECT_EQ(0x68, packed[ndx++]);
205 // group 2 - addend 3: -24 = 0x68
206 EXPECT_EQ(0x68, packed[ndx++]);
207
208 EXPECT_EQ(ndx, packed.size());
209}
210
211TEST(Packer, PackWithAddend) {
212 DoPackWithAddend<ELF32_traits>();
213 DoPackWithAddend<ELF64_traits>();
214}
215
216template <typename ELF>
217static void DoUnpackWithAddend() {
218 std::vector<uint8_t> packed;
219 // Identifier.
220 packed.push_back('A');
221 packed.push_back('P');
222 packed.push_back('S');
223 packed.push_back('2');
224 // Relocation count
225 packed.push_back(6U);
226 // base relocation = 0xd1cdfffc -> fc, ff, b7, 8e, 0d
227 packed.push_back(0xfc);
228 packed.push_back(0xff);
229 packed.push_back(0xb7);
230 packed.push_back(0x8e);
231 if (sizeof(typename ELF::Addr) == 8) {
232 // positive for uint64_t
233 packed.push_back(0x0d);
234 } else {
235 // negative for uint32_t
236 packed.push_back(0x7d);
237 }
238 // group 1
239 packed.push_back(0x03); // size
240 packed.push_back(0x0b); // flags
241 packed.push_back(0x04); // r_offset_delta
242 packed.push_back(0x01); // r_info
243 // group 1 - addend 1: 10024 = 0xa8, 0xce, 0x80
244 packed.push_back(0xa8);
245 packed.push_back(0xce);
246 packed.push_back(0x00);
247 // group 1 - addend 2: -12 = 0x74
248 packed.push_back(0x74);
249 // group 1 - addend 3: +12 = 0x0c
250 packed.push_back(0x0c);
251
252 // group 2
253 packed.push_back(0x03); // size
254 packed.push_back(0x0b); // flags
255 packed.push_back(0x08); // r_offset_delta
256 packed.push_back(0x01); // r_info
257
258 // group 2 - addend 1: -24 = 0x68
259 packed.push_back(0x68);
260 // group 2 - addend 2: -24 = 0x68
261 packed.push_back(0x68);
262 // group 2 - addend 3: -24 = 0x68
263 packed.push_back(0x68);
264
265 std::vector<typename ELF::Rela> relocations;
266
267 RelocationPacker<ELF> packer;
Dmitriy Ivanov87a06172015-02-06 10:56:28 -0800268
269 relocations.clear();
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -0800270 packer.UnpackRelocations(packed, &relocations);
Dmitriy Ivanov87a06172015-02-06 10:56:28 -0800271
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -0800272 EXPECT_EQ(6U, relocations.size());
273 size_t ndx = 0;
Dmitriy Ivanov87a06172015-02-06 10:56:28 -0800274 // Initial relocation.
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -0800275 EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0000, 0x01, 10024, relocations[ndx++]));
Dmitriy Ivanov87a06172015-02-06 10:56:28 -0800276 // Two more relocations, 4 byte offset deltas, 12 byte addend deltas.
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -0800277 EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0004, 0x01, 10012, relocations[ndx++]));
278 EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0008, 0x01, 10024, relocations[ndx++]));
Dmitriy Ivanov87a06172015-02-06 10:56:28 -0800279 // Three more relocations, 8 byte offset deltas, -24 byte addend deltas.
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -0800280 EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0010, 0x01, 10000, relocations[ndx++]));
281 EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0018, 0x01, 9976, relocations[ndx++]));
282 EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0020, 0x01, 9952, relocations[ndx++]));
283
284 EXPECT_EQ(ndx, relocations.size());
285}
286
287TEST(Packer, UnpackWithAddend) {
288 DoUnpackWithAddend<ELF32_traits>();
289 DoUnpackWithAddend<ELF64_traits>();
Dmitriy Ivanov87a06172015-02-06 10:56:28 -0800290}
291
292} // namespace relocation_packer