blob: 424b92cd067c146e093394eaccdb5e281ac8b168 [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 Ivanovf15ceeb2015-04-21 15:03:04 -070042 bool is_32 = sizeof(typename ELF::Addr) == 4;
Dmitriy Ivanov87a06172015-02-06 10:56:28 -080043 // Initial relocation.
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -080044 AddRelocation<ELF>(0xd1ce0000, 0x11, 0, &relocations);
Dmitriy Ivanov87a06172015-02-06 10:56:28 -080045 // Two more relocations, 4 byte deltas.
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -080046 AddRelocation<ELF>(0xd1ce0004, 0x11, 0, &relocations);
47 AddRelocation<ELF>(0xd1ce0008, 0x11, 0, &relocations);
Dmitriy Ivanov87a06172015-02-06 10:56:28 -080048 // Three more relocations, 8 byte deltas.
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -080049 AddRelocation<ELF>(0xd1ce0010, 0x11, 0, &relocations);
50 AddRelocation<ELF>(0xd1ce0018, 0x11, 0, &relocations);
51 AddRelocation<ELF>(0xd1ce0020, 0x11, 0, &relocations);
52
53 RelocationPacker<ELF> packer;
Dmitriy Ivanov87a06172015-02-06 10:56:28 -080054
55 packed.clear();
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -080056 packer.PackRelocations(relocations, &packed);
Dmitriy Ivanov87a06172015-02-06 10:56:28 -080057
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -080058 ASSERT_EQ(18U, packed.size());
Dmitriy Ivanov87a06172015-02-06 10:56:28 -080059 // Identifier.
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -080060 size_t ndx = 0;
61 EXPECT_EQ('A', packed[ndx++]);
62 EXPECT_EQ('P', packed[ndx++]);
Dmitriy Ivanovf15ceeb2015-04-21 15:03:04 -070063 EXPECT_EQ('S', packed[ndx++]);
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -080064 EXPECT_EQ('2', packed[ndx++]);
65 // relocation count
66 EXPECT_EQ(6, packed[ndx++]);
Dmitriy Ivanovf15ceeb2015-04-21 15:03:04 -070067 // base relocation = 0xd1cdfffc -> fc, ff, b7, 8e, 7d/0d (32/64bit)
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -080068 EXPECT_EQ(0xfc, packed[ndx++]);
69 EXPECT_EQ(0xff, packed[ndx++]);
70 EXPECT_EQ(0xb7, packed[ndx++]);
71 EXPECT_EQ(0x8e, packed[ndx++]);
Dmitriy Ivanovf15ceeb2015-04-21 15:03:04 -070072 EXPECT_EQ(is_32 ? 0x7d : 0x0d, packed[ndx++]);
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -080073 // first group
74 EXPECT_EQ(3, packed[ndx++]); // size
75 EXPECT_EQ(3, packed[ndx++]); // flags
76 EXPECT_EQ(4, packed[ndx++]); // r_offset_delta
77 EXPECT_EQ(0x11, packed[ndx++]); // r_info
78 // second group
79 EXPECT_EQ(3, packed[ndx++]); // size
80 EXPECT_EQ(3, packed[ndx++]); // flags
81 EXPECT_EQ(8, packed[ndx++]); // r_offset_delta
82 EXPECT_EQ(0x11, packed[ndx++]); // r_info
83
84 EXPECT_EQ(ndx, packed.size());
Dmitriy Ivanov87a06172015-02-06 10:56:28 -080085}
86
Dmitriy Ivanovf15ceeb2015-04-21 15:03:04 -070087TEST(Packer, PackNoAddend32) {
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -080088 DoPackNoAddend<ELF32_traits>();
Dmitriy Ivanovf15ceeb2015-04-21 15:03:04 -070089}
90
91TEST(Packer, PackNoAddend64) {
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -080092 DoPackNoAddend<ELF64_traits>();
93}
94
95template <typename ELF>
96static void DoUnpackNoAddend() {
97 std::vector<typename ELF::Rela> relocations;
Dmitriy Ivanov87a06172015-02-06 10:56:28 -080098 std::vector<uint8_t> packed;
Dmitriy Ivanovf15ceeb2015-04-21 15:03:04 -070099 bool is_32 = sizeof(typename ELF::Addr) == 4;
Dmitriy Ivanov87a06172015-02-06 10:56:28 -0800100 packed.push_back('A');
101 packed.push_back('P');
Dmitriy Ivanovf15ceeb2015-04-21 15:03:04 -0700102 packed.push_back('S');
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -0800103 packed.push_back('2');
104 // relocation count
Dmitriy Ivanov87a06172015-02-06 10:56:28 -0800105 packed.push_back(6);
Dmitriy Ivanovf15ceeb2015-04-21 15:03:04 -0700106 // base relocation = 0xd1cdfffc -> fc, ff, b7, 8e, 7d/0d (32/64bit)
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -0800107 packed.push_back(0xfc);
108 packed.push_back(0xff);
109 packed.push_back(0xb7);
110 packed.push_back(0x8e);
Dmitriy Ivanovf15ceeb2015-04-21 15:03:04 -0700111 packed.push_back(is_32 ? 0x7d : 0x0d);
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -0800112 // first group
113 packed.push_back(3); // size
114 packed.push_back(3); // flags
115 packed.push_back(4); // r_offset_delta
116 packed.push_back(0x11); // r_info
117 // second group
118 packed.push_back(3); // size
119 packed.push_back(3); // flags
120 packed.push_back(8); // r_offset_delta
121 packed.push_back(0x11); // r_info
122
123 RelocationPacker<ELF> packer;
124 packer.UnpackRelocations(packed, &relocations);
125
126 size_t ndx = 0;
127 EXPECT_EQ(6U, relocations.size());
128 EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0000, 0x11, 0, relocations[ndx++]));
129 EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0004, 0x11, 0, relocations[ndx++]));
130 EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0008, 0x11, 0, relocations[ndx++]));
131
132 EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0010, 0x11, 0, relocations[ndx++]));
133 EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0018, 0x11, 0, relocations[ndx++]));
134 EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0020, 0x11, 0, relocations[ndx++]));
135
136 EXPECT_EQ(ndx, relocations.size());
137}
138
Dmitriy Ivanovf15ceeb2015-04-21 15:03:04 -0700139TEST(Packer, UnpackNoAddend32) {
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -0800140 DoUnpackNoAddend<ELF32_traits>();
Dmitriy Ivanovf15ceeb2015-04-21 15:03:04 -0700141}
142
143TEST(Packer, UnpackNoAddend64) {
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -0800144 DoUnpackNoAddend<ELF64_traits>();
145}
146
147template <typename ELF>
148static void DoPackWithAddend() {
149 std::vector<typename ELF::Rela> relocations;
150
151 // Initial relocation.
152 AddRelocation<ELF>(0xd1ce0000, 0x01, 10024, &relocations);
153 // Two more relocations, 4 byte offset deltas, 12 byte addend deltas.
154 AddRelocation<ELF>(0xd1ce0004, 0x01, 10012, &relocations);
155 AddRelocation<ELF>(0xd1ce0008, 0x01, 10024, &relocations);
156 // Three more relocations, 8 byte deltas, -24 byte addend deltas.
157 AddRelocation<ELF>(0xd1ce0010, 0x01, 10000, &relocations);
158 AddRelocation<ELF>(0xd1ce0018, 0x01, 9976, &relocations);
159 AddRelocation<ELF>(0xd1ce0020, 0x01, 9952, &relocations);
160
161 std::vector<uint8_t> packed;
162
163 RelocationPacker<ELF> packer;
164
165 packed.clear();
166 packer.PackRelocations(relocations, &packed);
167
168 EXPECT_EQ(26U, packed.size());
169 size_t ndx = 0;
170 // Identifier.
171 EXPECT_EQ('A', packed[ndx++]);
172 EXPECT_EQ('P', packed[ndx++]);
173 EXPECT_EQ('S', packed[ndx++]);
174 EXPECT_EQ('2', packed[ndx++]);
175 // Relocation count
176 EXPECT_EQ(6U, packed[ndx++]);
177 // base relocation = 0xd1cdfffc -> fc, ff, b7, 8e, 0d/7d (depending on ELF::Addr)
178 EXPECT_EQ(0xfc, packed[ndx++]);
179 EXPECT_EQ(0xff, packed[ndx++]);
180 EXPECT_EQ(0xb7, packed[ndx++]);
181 EXPECT_EQ(0x8e, packed[ndx++]);
182 if (sizeof(typename ELF::Addr) == 8) {
183 // positive for uint64_t
184 EXPECT_EQ(0x0d, packed[ndx++]);
185 } else {
186 // negative for uint32_t
187 EXPECT_EQ(0x7d, packed[ndx++]);
188 }
189 // group 1
190 EXPECT_EQ(0x03, packed[ndx++]); // size
191 EXPECT_EQ(0x0b, packed[ndx++]); // flags
192 EXPECT_EQ(0x04, packed[ndx++]); // r_offset_delta
193 EXPECT_EQ(0x01, packed[ndx++]); // r_info
194 // group 1 - addend 1: 10024 = 0xa8, 0xce, 0x80
195 EXPECT_EQ(0xa8, packed[ndx++]);
196 EXPECT_EQ(0xce, packed[ndx++]);
197 EXPECT_EQ(0x00, packed[ndx++]);
198 // group 1 - addend 2: -12 = 0x74
199 EXPECT_EQ(0x74, packed[ndx++]);
200 // group 1 - addend 3: +12 = 0x0c
201 EXPECT_EQ(0x0c, packed[ndx++]);
202
203 // group 2
204 EXPECT_EQ(0x03, packed[ndx++]); // size
205 EXPECT_EQ(0x0b, packed[ndx++]); // flags
206 EXPECT_EQ(0x08, packed[ndx++]); // r_offset_delta
207 EXPECT_EQ(0x01, packed[ndx++]); // r_info
208
209 // group 2 - addend 1: -24 = 0x68
210 EXPECT_EQ(0x68, packed[ndx++]);
211 // group 2 - addend 2: -24 = 0x68
212 EXPECT_EQ(0x68, packed[ndx++]);
213 // group 2 - addend 3: -24 = 0x68
214 EXPECT_EQ(0x68, packed[ndx++]);
215
216 EXPECT_EQ(ndx, packed.size());
217}
218
219TEST(Packer, PackWithAddend) {
220 DoPackWithAddend<ELF32_traits>();
221 DoPackWithAddend<ELF64_traits>();
222}
223
224template <typename ELF>
225static void DoUnpackWithAddend() {
226 std::vector<uint8_t> packed;
227 // Identifier.
228 packed.push_back('A');
229 packed.push_back('P');
230 packed.push_back('S');
231 packed.push_back('2');
232 // Relocation count
233 packed.push_back(6U);
234 // base relocation = 0xd1cdfffc -> fc, ff, b7, 8e, 0d
235 packed.push_back(0xfc);
236 packed.push_back(0xff);
237 packed.push_back(0xb7);
238 packed.push_back(0x8e);
239 if (sizeof(typename ELF::Addr) == 8) {
240 // positive for uint64_t
241 packed.push_back(0x0d);
242 } else {
243 // negative for uint32_t
244 packed.push_back(0x7d);
245 }
246 // group 1
247 packed.push_back(0x03); // size
248 packed.push_back(0x0b); // flags
249 packed.push_back(0x04); // r_offset_delta
250 packed.push_back(0x01); // r_info
251 // group 1 - addend 1: 10024 = 0xa8, 0xce, 0x80
252 packed.push_back(0xa8);
253 packed.push_back(0xce);
254 packed.push_back(0x00);
255 // group 1 - addend 2: -12 = 0x74
256 packed.push_back(0x74);
257 // group 1 - addend 3: +12 = 0x0c
258 packed.push_back(0x0c);
259
260 // group 2
261 packed.push_back(0x03); // size
262 packed.push_back(0x0b); // flags
263 packed.push_back(0x08); // r_offset_delta
264 packed.push_back(0x01); // r_info
265
266 // group 2 - addend 1: -24 = 0x68
267 packed.push_back(0x68);
268 // group 2 - addend 2: -24 = 0x68
269 packed.push_back(0x68);
270 // group 2 - addend 3: -24 = 0x68
271 packed.push_back(0x68);
272
273 std::vector<typename ELF::Rela> relocations;
274
275 RelocationPacker<ELF> packer;
Dmitriy Ivanov87a06172015-02-06 10:56:28 -0800276
277 relocations.clear();
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -0800278 packer.UnpackRelocations(packed, &relocations);
Dmitriy Ivanov87a06172015-02-06 10:56:28 -0800279
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -0800280 EXPECT_EQ(6U, relocations.size());
281 size_t ndx = 0;
Dmitriy Ivanov87a06172015-02-06 10:56:28 -0800282 // Initial relocation.
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -0800283 EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0000, 0x01, 10024, relocations[ndx++]));
Dmitriy Ivanov87a06172015-02-06 10:56:28 -0800284 // Two more relocations, 4 byte offset deltas, 12 byte addend deltas.
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -0800285 EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0004, 0x01, 10012, relocations[ndx++]));
286 EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0008, 0x01, 10024, relocations[ndx++]));
Dmitriy Ivanov87a06172015-02-06 10:56:28 -0800287 // Three more relocations, 8 byte offset deltas, -24 byte addend deltas.
Dmitriy Ivanovf8ff6b12015-01-27 19:32:56 -0800288 EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0010, 0x01, 10000, relocations[ndx++]));
289 EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0018, 0x01, 9976, relocations[ndx++]));
290 EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0020, 0x01, 9952, relocations[ndx++]));
291
292 EXPECT_EQ(ndx, relocations.size());
293}
294
295TEST(Packer, UnpackWithAddend) {
296 DoUnpackWithAddend<ELF32_traits>();
297 DoUnpackWithAddend<ELF64_traits>();
Dmitriy Ivanov87a06172015-02-06 10:56:28 -0800298}
299
300} // namespace relocation_packer