| // 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. |
| |
| #include "packer.h" |
| |
| #include <vector> |
| #include "elf.h" |
| #include "elf_traits.h" |
| #include "gtest/gtest.h" |
| |
| |
| template <typename ELF> |
| static void AddRelocation(typename ELF::Addr addr, |
| typename ELF::Xword info, |
| typename ELF::Sxword addend, |
| std::vector<typename ELF::Rela>* relocations) { |
| typename ELF::Rela relocation; |
| relocation.r_offset = addr; |
| relocation.r_info = info; |
| relocation.r_addend = addend; |
| |
| relocations->push_back(relocation); |
| } |
| |
| template <typename ELF> |
| static bool CheckRelocation(typename ELF::Addr addr, |
| typename ELF::Xword info, |
| typename ELF::Sxword addend, |
| const typename ELF::Rela& relocation) { |
| return relocation.r_offset == addr && |
| relocation.r_info == info && |
| relocation.r_addend == addend; |
| } |
| |
| namespace relocation_packer { |
| |
| template <typename ELF> |
| static void DoPackNoAddend() { |
| std::vector<typename ELF::Rela> relocations; |
| std::vector<uint8_t> packed; |
| bool is_32 = sizeof(typename ELF::Addr) == 4; |
| // Initial relocation. |
| AddRelocation<ELF>(0xd1ce0000, 0x11, 0, &relocations); |
| // Two more relocations, 4 byte deltas. |
| AddRelocation<ELF>(0xd1ce0004, 0x11, 0, &relocations); |
| AddRelocation<ELF>(0xd1ce0008, 0x11, 0, &relocations); |
| // Three more relocations, 8 byte deltas. |
| AddRelocation<ELF>(0xd1ce0010, 0x11, 0, &relocations); |
| AddRelocation<ELF>(0xd1ce0018, 0x11, 0, &relocations); |
| AddRelocation<ELF>(0xd1ce0020, 0x11, 0, &relocations); |
| |
| RelocationPacker<ELF> packer; |
| |
| packed.clear(); |
| packer.PackRelocations(relocations, &packed); |
| |
| ASSERT_EQ(18U, packed.size()); |
| // Identifier. |
| size_t ndx = 0; |
| EXPECT_EQ('A', packed[ndx++]); |
| EXPECT_EQ('P', packed[ndx++]); |
| EXPECT_EQ('S', packed[ndx++]); |
| EXPECT_EQ('2', packed[ndx++]); |
| // relocation count |
| EXPECT_EQ(6, packed[ndx++]); |
| // base relocation = 0xd1cdfffc -> fc, ff, b7, 8e, 7d/0d (32/64bit) |
| EXPECT_EQ(0xfc, packed[ndx++]); |
| EXPECT_EQ(0xff, packed[ndx++]); |
| EXPECT_EQ(0xb7, packed[ndx++]); |
| EXPECT_EQ(0x8e, packed[ndx++]); |
| EXPECT_EQ(is_32 ? 0x7d : 0x0d, packed[ndx++]); |
| // first group |
| EXPECT_EQ(3, packed[ndx++]); // size |
| EXPECT_EQ(3, packed[ndx++]); // flags |
| EXPECT_EQ(4, packed[ndx++]); // r_offset_delta |
| EXPECT_EQ(0x11, packed[ndx++]); // r_info |
| // second group |
| EXPECT_EQ(3, packed[ndx++]); // size |
| EXPECT_EQ(3, packed[ndx++]); // flags |
| EXPECT_EQ(8, packed[ndx++]); // r_offset_delta |
| EXPECT_EQ(0x11, packed[ndx++]); // r_info |
| |
| EXPECT_EQ(ndx, packed.size()); |
| } |
| |
| TEST(Packer, PackNoAddend32) { |
| DoPackNoAddend<ELF32_traits>(); |
| } |
| |
| TEST(Packer, PackNoAddend64) { |
| DoPackNoAddend<ELF64_traits>(); |
| } |
| |
| template <typename ELF> |
| static void DoUnpackNoAddend() { |
| std::vector<typename ELF::Rela> relocations; |
| std::vector<uint8_t> packed; |
| bool is_32 = sizeof(typename ELF::Addr) == 4; |
| packed.push_back('A'); |
| packed.push_back('P'); |
| packed.push_back('S'); |
| packed.push_back('2'); |
| // relocation count |
| packed.push_back(6); |
| // base relocation = 0xd1cdfffc -> fc, ff, b7, 8e, 7d/0d (32/64bit) |
| packed.push_back(0xfc); |
| packed.push_back(0xff); |
| packed.push_back(0xb7); |
| packed.push_back(0x8e); |
| packed.push_back(is_32 ? 0x7d : 0x0d); |
| // first group |
| packed.push_back(3); // size |
| packed.push_back(3); // flags |
| packed.push_back(4); // r_offset_delta |
| packed.push_back(0x11); // r_info |
| // second group |
| packed.push_back(3); // size |
| packed.push_back(3); // flags |
| packed.push_back(8); // r_offset_delta |
| packed.push_back(0x11); // r_info |
| |
| RelocationPacker<ELF> packer; |
| packer.UnpackRelocations(packed, &relocations); |
| |
| size_t ndx = 0; |
| EXPECT_EQ(6U, relocations.size()); |
| EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0000, 0x11, 0, relocations[ndx++])); |
| EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0004, 0x11, 0, relocations[ndx++])); |
| EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0008, 0x11, 0, relocations[ndx++])); |
| |
| EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0010, 0x11, 0, relocations[ndx++])); |
| EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0018, 0x11, 0, relocations[ndx++])); |
| EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0020, 0x11, 0, relocations[ndx++])); |
| |
| EXPECT_EQ(ndx, relocations.size()); |
| } |
| |
| TEST(Packer, UnpackNoAddend32) { |
| DoUnpackNoAddend<ELF32_traits>(); |
| } |
| |
| TEST(Packer, UnpackNoAddend64) { |
| DoUnpackNoAddend<ELF64_traits>(); |
| } |
| |
| template <typename ELF> |
| static void DoPackWithAddend() { |
| std::vector<typename ELF::Rela> relocations; |
| |
| // Initial relocation. |
| AddRelocation<ELF>(0xd1ce0000, 0x01, 10024, &relocations); |
| // Two more relocations, 4 byte offset deltas, 12 byte addend deltas. |
| AddRelocation<ELF>(0xd1ce0004, 0x01, 10012, &relocations); |
| AddRelocation<ELF>(0xd1ce0008, 0x01, 10024, &relocations); |
| // Three more relocations, 8 byte deltas, -24 byte addend deltas. |
| AddRelocation<ELF>(0xd1ce0010, 0x01, 10000, &relocations); |
| AddRelocation<ELF>(0xd1ce0018, 0x01, 9976, &relocations); |
| AddRelocation<ELF>(0xd1ce0020, 0x01, 9952, &relocations); |
| |
| std::vector<uint8_t> packed; |
| |
| RelocationPacker<ELF> packer; |
| |
| packed.clear(); |
| packer.PackRelocations(relocations, &packed); |
| |
| EXPECT_EQ(26U, packed.size()); |
| size_t ndx = 0; |
| // Identifier. |
| EXPECT_EQ('A', packed[ndx++]); |
| EXPECT_EQ('P', packed[ndx++]); |
| EXPECT_EQ('S', packed[ndx++]); |
| EXPECT_EQ('2', packed[ndx++]); |
| // Relocation count |
| EXPECT_EQ(6U, packed[ndx++]); |
| // base relocation = 0xd1cdfffc -> fc, ff, b7, 8e, 0d/7d (depending on ELF::Addr) |
| EXPECT_EQ(0xfc, packed[ndx++]); |
| EXPECT_EQ(0xff, packed[ndx++]); |
| EXPECT_EQ(0xb7, packed[ndx++]); |
| EXPECT_EQ(0x8e, packed[ndx++]); |
| if (sizeof(typename ELF::Addr) == 8) { |
| // positive for uint64_t |
| EXPECT_EQ(0x0d, packed[ndx++]); |
| } else { |
| // negative for uint32_t |
| EXPECT_EQ(0x7d, packed[ndx++]); |
| } |
| // group 1 |
| EXPECT_EQ(0x03, packed[ndx++]); // size |
| EXPECT_EQ(0x0b, packed[ndx++]); // flags |
| EXPECT_EQ(0x04, packed[ndx++]); // r_offset_delta |
| EXPECT_EQ(0x01, packed[ndx++]); // r_info |
| // group 1 - addend 1: 10024 = 0xa8, 0xce, 0x80 |
| EXPECT_EQ(0xa8, packed[ndx++]); |
| EXPECT_EQ(0xce, packed[ndx++]); |
| EXPECT_EQ(0x00, packed[ndx++]); |
| // group 1 - addend 2: -12 = 0x74 |
| EXPECT_EQ(0x74, packed[ndx++]); |
| // group 1 - addend 3: +12 = 0x0c |
| EXPECT_EQ(0x0c, packed[ndx++]); |
| |
| // group 2 |
| EXPECT_EQ(0x03, packed[ndx++]); // size |
| EXPECT_EQ(0x0b, packed[ndx++]); // flags |
| EXPECT_EQ(0x08, packed[ndx++]); // r_offset_delta |
| EXPECT_EQ(0x01, packed[ndx++]); // r_info |
| |
| // group 2 - addend 1: -24 = 0x68 |
| EXPECT_EQ(0x68, packed[ndx++]); |
| // group 2 - addend 2: -24 = 0x68 |
| EXPECT_EQ(0x68, packed[ndx++]); |
| // group 2 - addend 3: -24 = 0x68 |
| EXPECT_EQ(0x68, packed[ndx++]); |
| |
| EXPECT_EQ(ndx, packed.size()); |
| } |
| |
| TEST(Packer, PackWithAddend) { |
| DoPackWithAddend<ELF32_traits>(); |
| DoPackWithAddend<ELF64_traits>(); |
| } |
| |
| template <typename ELF> |
| static void DoUnpackWithAddend() { |
| std::vector<uint8_t> packed; |
| // Identifier. |
| packed.push_back('A'); |
| packed.push_back('P'); |
| packed.push_back('S'); |
| packed.push_back('2'); |
| // Relocation count |
| packed.push_back(6U); |
| // base relocation = 0xd1cdfffc -> fc, ff, b7, 8e, 0d |
| packed.push_back(0xfc); |
| packed.push_back(0xff); |
| packed.push_back(0xb7); |
| packed.push_back(0x8e); |
| if (sizeof(typename ELF::Addr) == 8) { |
| // positive for uint64_t |
| packed.push_back(0x0d); |
| } else { |
| // negative for uint32_t |
| packed.push_back(0x7d); |
| } |
| // group 1 |
| packed.push_back(0x03); // size |
| packed.push_back(0x0b); // flags |
| packed.push_back(0x04); // r_offset_delta |
| packed.push_back(0x01); // r_info |
| // group 1 - addend 1: 10024 = 0xa8, 0xce, 0x80 |
| packed.push_back(0xa8); |
| packed.push_back(0xce); |
| packed.push_back(0x00); |
| // group 1 - addend 2: -12 = 0x74 |
| packed.push_back(0x74); |
| // group 1 - addend 3: +12 = 0x0c |
| packed.push_back(0x0c); |
| |
| // group 2 |
| packed.push_back(0x03); // size |
| packed.push_back(0x0b); // flags |
| packed.push_back(0x08); // r_offset_delta |
| packed.push_back(0x01); // r_info |
| |
| // group 2 - addend 1: -24 = 0x68 |
| packed.push_back(0x68); |
| // group 2 - addend 2: -24 = 0x68 |
| packed.push_back(0x68); |
| // group 2 - addend 3: -24 = 0x68 |
| packed.push_back(0x68); |
| |
| std::vector<typename ELF::Rela> relocations; |
| |
| RelocationPacker<ELF> packer; |
| |
| relocations.clear(); |
| packer.UnpackRelocations(packed, &relocations); |
| |
| EXPECT_EQ(6U, relocations.size()); |
| size_t ndx = 0; |
| // Initial relocation. |
| EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0000, 0x01, 10024, relocations[ndx++])); |
| // Two more relocations, 4 byte offset deltas, 12 byte addend deltas. |
| EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0004, 0x01, 10012, relocations[ndx++])); |
| EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0008, 0x01, 10024, relocations[ndx++])); |
| // Three more relocations, 8 byte offset deltas, -24 byte addend deltas. |
| EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0010, 0x01, 10000, relocations[ndx++])); |
| EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0018, 0x01, 9976, relocations[ndx++])); |
| EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0020, 0x01, 9952, relocations[ndx++])); |
| |
| EXPECT_EQ(ndx, relocations.size()); |
| } |
| |
| TEST(Packer, UnpackWithAddend) { |
| DoUnpackWithAddend<ELF32_traits>(); |
| DoUnpackWithAddend<ELF64_traits>(); |
| } |
| |
| } // namespace relocation_packer |