Generalize compression tool

 1. One binary for all architectures
 2. Generalize (and slightly improve) compression
 2.1 works on all relocation types (rela?.dyn section only so far)
 2.2 Uses same format to encode ElfW(Rel) as well as ElfW(Rela) tables

Bug: 18051137
Change-Id: I66c95d9076954ca115816fc577d0f5ef274e5e72
diff --git a/tools/relocation_packer/src/packer_unittest.cc b/tools/relocation_packer/src/packer_unittest.cc
index de5be79..8dddd8b 100644
--- a/tools/relocation_packer/src/packer_unittest.cc
+++ b/tools/relocation_packer/src/packer_unittest.cc
@@ -7,244 +7,286 @@
 #include <vector>
 #include "elf.h"
 #include "elf_traits.h"
-#include "testing/gtest/include/gtest/gtest.h"
+#include "gtest/gtest.h"
 
-namespace {
 
-void AddRelocation(ELF::Addr addr, std::vector<ELF::Rel>* relocations) {
-  ELF::Rel relocation;
+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 = ELF_R_INFO(0, ELF::kRelativeRelocationCode);
-  relocations->push_back(relocation);
-}
-
-bool CheckRelocation(ELF::Addr addr, const ELF::Rel& relocation) {
-  return relocation.r_offset == addr &&
-      ELF_R_SYM(relocation.r_info) == 0 &&
-      ELF_R_TYPE(relocation.r_info) == ELF::kRelativeRelocationCode;
-}
-
-void AddRelocation(ELF::Addr addr,
-                   ELF::Sxword addend,
-                   std::vector<ELF::Rela>* relocations) {
-  ELF::Rela relocation;
-  relocation.r_offset = addr;
-  relocation.r_info = ELF_R_INFO(0, ELF::kRelativeRelocationCode);
+  relocation.r_info = info;
   relocation.r_addend = addend;
+
   relocations->push_back(relocation);
 }
 
-bool CheckRelocation(ELF::Addr addr,
-                     ELF::Sxword addend,
-                     const ELF::Rela& 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 &&
-      ELF_R_SYM(relocation.r_info) == 0 &&
-      ELF_R_TYPE(relocation.r_info) == ELF::kRelativeRelocationCode &&
+      relocation.r_info == info &&
       relocation.r_addend == addend;
 }
 
-}  // namespace
-
 namespace relocation_packer {
 
-TEST(Packer, PackRel) {
-  std::vector<ELF::Rel> relocations;
+template <typename ELF>
+static void DoPackNoAddend() {
+  std::vector<typename ELF::Rela> relocations;
   std::vector<uint8_t> packed;
-
-  RelocationPacker packer;
-
   // Initial relocation.
-  AddRelocation(0xd1ce0000, &relocations);
+  AddRelocation<ELF>(0xd1ce0000, 0x11, 0, &relocations);
   // Two more relocations, 4 byte deltas.
-  AddRelocation(0xd1ce0004, &relocations);
-  AddRelocation(0xd1ce0008, &relocations);
+  AddRelocation<ELF>(0xd1ce0004, 0x11, 0, &relocations);
+  AddRelocation<ELF>(0xd1ce0008, 0x11, 0, &relocations);
   // Three more relocations, 8 byte deltas.
-  AddRelocation(0xd1ce0010, &relocations);
-  AddRelocation(0xd1ce0018, &relocations);
-  AddRelocation(0xd1ce0020, &relocations);
+  AddRelocation<ELF>(0xd1ce0010, 0x11, 0, &relocations);
+  AddRelocation<ELF>(0xd1ce0018, 0x11, 0, &relocations);
+  AddRelocation<ELF>(0xd1ce0020, 0x11, 0, &relocations);
+
+  RelocationPacker<ELF> packer;
 
   packed.clear();
-  packer.PackRelativeRelocations(relocations, &packed);
+  packer.PackRelocations(relocations, &packed);
 
-  EXPECT_EQ(16, packed.size());
+  ASSERT_EQ(18U, packed.size());
   // Identifier.
-  EXPECT_EQ('A', packed[0]);
-  EXPECT_EQ('P', packed[1]);
-  EXPECT_EQ('R', packed[2]);
-  EXPECT_EQ('1', packed[3]);
-  // Count-delta pairs count.
-  EXPECT_EQ(2, packed[4]);
-  // 0xd1ce0000
-  EXPECT_EQ(128, packed[5]);
-  EXPECT_EQ(128, packed[6]);
-  EXPECT_EQ(184, packed[7]);
-  EXPECT_EQ(142, packed[8]);
-  EXPECT_EQ(13, packed[9]);
-  // Run of two relocations, 4 byte deltas.
-  EXPECT_EQ(2, packed[10]);
-  EXPECT_EQ(4, packed[11]);
-  // Run of three relocations, 8 byte deltas.
-  EXPECT_EQ(3, packed[12]);
-  EXPECT_EQ(8, packed[13]);
-  // Padding.
-  EXPECT_EQ(0, packed[14]);
-  EXPECT_EQ(0, packed[15]);
+  size_t ndx = 0;
+  EXPECT_EQ('A', packed[ndx++]);
+  EXPECT_EQ('P', packed[ndx++]);
+  EXPECT_EQ('U', packed[ndx++]);
+  EXPECT_EQ('2', packed[ndx++]);
+  // relocation count
+  EXPECT_EQ(6, packed[ndx++]);
+  // base relocation = 0xd1cdfffc -> fc, ff, b7, 8e, 0d
+  EXPECT_EQ(0xfc, packed[ndx++]);
+  EXPECT_EQ(0xff, packed[ndx++]);
+  EXPECT_EQ(0xb7, packed[ndx++]);
+  EXPECT_EQ(0x8e, packed[ndx++]);
+  EXPECT_EQ(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, UnpackRel) {
+TEST(Packer, PackNoAddend) {
+  DoPackNoAddend<ELF32_traits>();
+  DoPackNoAddend<ELF64_traits>();
+}
+
+template <typename ELF>
+static void DoUnpackNoAddend() {
+  std::vector<typename ELF::Rela> relocations;
   std::vector<uint8_t> packed;
-  std::vector<ELF::Rel> relocations;
-
-  RelocationPacker packer;
-
-  // Identifier.
   packed.push_back('A');
   packed.push_back('P');
-  packed.push_back('R');
-  packed.push_back('1');
-  // Count-delta pairs count.
-  packed.push_back(2);
-  // 0xd1ce0000
-  packed.push_back(128);
-  packed.push_back(128);
-  packed.push_back(184);
-  packed.push_back(142);
-  packed.push_back(13);
-  // Run of two relocations, 4 byte deltas.
-  packed.push_back(2);
-  packed.push_back(4);
-  // Run of three relocations, 8 byte deltas.
-  packed.push_back(3);
-  packed.push_back(8);
-  // Padding.
-  packed.push_back(0);
-  packed.push_back(0);
-
-  relocations.clear();
-  packer.UnpackRelativeRelocations(packed, &relocations);
-
-  EXPECT_EQ(6, relocations.size());
-  // Initial relocation.
-  EXPECT_TRUE(CheckRelocation(0xd1ce0000, relocations[0]));
-  // Two relocations, 4 byte deltas.
-  EXPECT_TRUE(CheckRelocation(0xd1ce0004, relocations[1]));
-  EXPECT_TRUE(CheckRelocation(0xd1ce0008, relocations[2]));
-  // Three relocations, 8 byte deltas.
-  EXPECT_TRUE(CheckRelocation(0xd1ce0010, relocations[3]));
-  EXPECT_TRUE(CheckRelocation(0xd1ce0018, relocations[4]));
-  EXPECT_TRUE(CheckRelocation(0xd1ce0020, relocations[5]));
-}
-
-TEST(Packer, PackRela) {
-  std::vector<ELF::Rela> relocations;
-  std::vector<uint8_t> packed;
-
-  RelocationPacker packer;
-
-  // Initial relocation.
-  AddRelocation(0xd1ce0000, 10000, &relocations);
-  // Two more relocations, 4 byte offset deltas, 12 byte addend deltas.
-  AddRelocation(0xd1ce0004, 10012, &relocations);
-  AddRelocation(0xd1ce0008, 10024, &relocations);
-  // Three more relocations, 8 byte deltas, -24 byte addend deltas.
-  AddRelocation(0xd1ce0010, 10000, &relocations);
-  AddRelocation(0xd1ce0018, 9976, &relocations);
-  AddRelocation(0xd1ce0020, 9952, &relocations);
-
-  packed.clear();
-  packer.PackRelativeRelocations(relocations, &packed);
-
-  EXPECT_EQ(24, packed.size());
-  // Identifier.
-  EXPECT_EQ('A', packed[0]);
-  EXPECT_EQ('P', packed[1]);
-  EXPECT_EQ('A', packed[2]);
-  EXPECT_EQ('1', packed[3]);
-  // Delta pairs count.
-  EXPECT_EQ(6, packed[4]);
-  // 0xd1ce0000
-  EXPECT_EQ(128, packed[5]);
-  EXPECT_EQ(128, packed[6]);
-  EXPECT_EQ(184, packed[7]);
-  EXPECT_EQ(142, packed[8]);
-  EXPECT_EQ(13, packed[9]);
-  // 10000
-  EXPECT_EQ(144, packed[10]);
-  EXPECT_EQ(206, packed[11]);
-  EXPECT_EQ(0, packed[12]);
-  // 4, 12
-  EXPECT_EQ(4, packed[13]);
-  EXPECT_EQ(12, packed[14]);
-  // 4, 12
-  EXPECT_EQ(4, packed[15]);
-  EXPECT_EQ(12, packed[16]);
-  // 8, -24
-  EXPECT_EQ(8, packed[17]);
-  EXPECT_EQ(104, packed[18]);
-  // 8, -24
-  EXPECT_EQ(8, packed[19]);
-  EXPECT_EQ(104, packed[20]);
-  // 8, -24
-  EXPECT_EQ(8, packed[21]);
-  EXPECT_EQ(104, packed[22]);
-  // Padding.
-  EXPECT_EQ(0, packed[23]);
-}
-
-TEST(Packer, UnpackRela) {
-  std::vector<uint8_t> packed;
-  std::vector<ELF::Rela> relocations;
-
-  RelocationPacker packer;
-
-  // Identifier.
-  packed.push_back('A');
-  packed.push_back('P');
-  packed.push_back('A');
-  packed.push_back('1');
-  // Delta pairs count.
+  packed.push_back('U');
+  packed.push_back('2');
+  // relocation count
   packed.push_back(6);
-  // 0xd1ce0000
-  packed.push_back(128);
-  packed.push_back(128);
-  packed.push_back(184);
-  packed.push_back(142);
-  packed.push_back(13);
-  // 10000
-  packed.push_back(144);
-  packed.push_back(206);
-  packed.push_back(0);
-  // 4, 12
-  packed.push_back(4);
-  packed.push_back(12);
-  // 4, 12
-  packed.push_back(4);
-  packed.push_back(12);
-  // 8, -24
-  packed.push_back(8);
-  packed.push_back(104);
-  // 8, -24
-  packed.push_back(8);
-  packed.push_back(104);
-  // 8, -24
-  packed.push_back(8);
-  packed.push_back(104);
-  // Padding.
-  packed.push_back(0);
+  // base relocation = 0xd1cdfffc -> fc, ff, b7, 8e, 0d
+  packed.push_back(0xfc);
+  packed.push_back(0xff);
+  packed.push_back(0xb7);
+  packed.push_back(0x8e);
+  packed.push_back(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, UnpackNoAddend) {
+  DoUnpackNoAddend<ELF32_traits>();
+  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.UnpackRelativeRelocations(packed, &relocations);
+  packer.UnpackRelocations(packed, &relocations);
 
-  EXPECT_EQ(6, relocations.size());
+  EXPECT_EQ(6U, relocations.size());
+  size_t ndx = 0;
   // Initial relocation.
-  EXPECT_TRUE(CheckRelocation(0xd1ce0000, 10000, relocations[0]));
+  EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0000, 0x01, 10024, relocations[ndx++]));
   // Two more relocations, 4 byte offset deltas, 12 byte addend deltas.
-  EXPECT_TRUE(CheckRelocation(0xd1ce0004, 10012, relocations[1]));
-  EXPECT_TRUE(CheckRelocation(0xd1ce0008, 10024, relocations[2]));
+  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(0xd1ce0010, 10000, relocations[3]));
-  EXPECT_TRUE(CheckRelocation(0xd1ce0018, 9976, relocations[4]));
-  EXPECT_TRUE(CheckRelocation(0xd1ce0020, 9952, relocations[5]));
+  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