// 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