diff options
author | Dmitriy Ivanov <dimitry@google.com> | 2015-04-21 15:03:04 -0700 |
---|---|---|
committer | Dmitriy Ivanov <dimitry@google.com> | 2015-04-22 12:58:38 -0700 |
commit | f15ceeb7841ef97c24a0b7708732756d433c5d0d (patch) | |
tree | b7888d48605d20313d6d417109da27043afc7995 /tools/relocation_packer | |
parent | 913fe559f69395aaf160653c1d3994df3272810b (diff) | |
download | bionic-f15ceeb7841ef97c24a0b7708732756d433c5d0d.zip bionic-f15ceeb7841ef97c24a0b7708732756d433c5d0d.tar.gz bionic-f15ceeb7841ef97c24a0b7708732756d433c5d0d.tar.bz2 |
Always use signed leb128 encoding
According to runs on /system/lib there using
unsigned leb128 does not save us any additional
space. In order to keep packing as simple as
possible switch to using signed leb128 for
everything.
Bug: http://b/18051137
Change-Id: I1a47cb9eb2175895b3c3f7c13b4c6b1060de86c0
Diffstat (limited to 'tools/relocation_packer')
-rw-r--r-- | tools/relocation_packer/Android.mk | 2 | ||||
-rw-r--r-- | tools/relocation_packer/src/elf_file.cc | 16 | ||||
-rw-r--r-- | tools/relocation_packer/src/elf_file.h | 5 | ||||
-rw-r--r-- | tools/relocation_packer/src/elf_file_unittest.cc | 10 | ||||
-rw-r--r-- | tools/relocation_packer/src/leb128.cc | 87 | ||||
-rw-r--r-- | tools/relocation_packer/src/leb128.h | 75 | ||||
-rw-r--r-- | tools/relocation_packer/src/leb128_unittest.cc | 111 | ||||
-rw-r--r-- | tools/relocation_packer/src/packer.cc | 37 | ||||
-rw-r--r-- | tools/relocation_packer/src/packer_unittest.cc | 24 | ||||
-rwxr-xr-x | tools/relocation_packer/test_data/elf_file_unittest_relocs_arm32_packed.so | bin | 89114 -> 89114 bytes | |||
-rwxr-xr-x | tools/relocation_packer/test_data/elf_file_unittest_relocs_arm64_packed.so | bin | 113651 -> 113651 bytes |
11 files changed, 50 insertions, 317 deletions
diff --git a/tools/relocation_packer/Android.mk b/tools/relocation_packer/Android.mk index eabe0da..75dba71 100644 --- a/tools/relocation_packer/Android.mk +++ b/tools/relocation_packer/Android.mk @@ -26,7 +26,6 @@ LOCAL_SRC_FILES := \ src/debug.cc \ src/delta_encoder.cc \ src/elf_file.cc \ - src/leb128.cc \ src/packer.cc \ src/sleb128.cc \ @@ -67,7 +66,6 @@ LOCAL_SRC_FILES := \ src/debug_unittest.cc \ src/delta_encoder_unittest.cc \ src/elf_file_unittest.cc \ - src/leb128_unittest.cc \ src/sleb128_unittest.cc \ src/packer_unittest.cc \ diff --git a/tools/relocation_packer/src/elf_file.cc b/tools/relocation_packer/src/elf_file.cc index 6843f5b..11af9ed 100644 --- a/tools/relocation_packer/src/elf_file.cc +++ b/tools/relocation_packer/src/elf_file.cc @@ -190,6 +190,7 @@ bool ElfFile<ELF>::Load() { // these; both is unsupported. bool has_rel_relocations = false; bool has_rela_relocations = false; + bool has_android_relocations = false; Elf_Scn* section = NULL; while ((section = elf_nextscn(elf, section)) != nullptr) { @@ -209,6 +210,11 @@ bool ElfFile<ELF>::Load() { if ((name == ".rel.dyn" || name == ".rela.dyn") && section_header->sh_size > 0) { found_relocations_section = section; + + // Note if relocation section is already packed + has_android_relocations = + section_header->sh_type == SHT_ANDROID_REL || + section_header->sh_type == SHT_ANDROID_RELA; } if (section_header->sh_offset == dynamic_program_header->p_offset) { @@ -250,6 +256,7 @@ bool ElfFile<ELF>::Load() { relocations_section_ = found_relocations_section; dynamic_section_ = found_dynamic_section; relocations_type_ = has_rel_relocations ? REL : RELA; + has_android_relocations_ = has_android_relocations; return true; } @@ -610,10 +617,15 @@ template <typename ELF> bool ElfFile<ELF>::PackTypedRelocations(std::vector<typename ELF::Rela>* relocations) { typedef typename ELF::Rela Rela; + if (has_android_relocations_) { + LOG(ERROR) << "Relocation table is already packed"; + return false; + } + // If no relocations then we have nothing packable. Perhaps // the shared object has already been packed? if (relocations->empty()) { - LOG(ERROR) << "No relocations found (already packed?)"; + LOG(ERROR) << "No relocations found"; return false; } @@ -737,7 +749,7 @@ bool ElfFile<ELF>::UnpackRelocations() { packed.size() > 3 && packed[0] == 'A' && packed[1] == 'P' && - (packed[2] == 'U' || packed[2] == 'S') && + packed[2] == 'S' && packed[3] == '2') { LOG(INFO) << "Relocations : " << (relocations_type_ == REL ? "REL" : "RELA"); } else { diff --git a/tools/relocation_packer/src/elf_file.h b/tools/relocation_packer/src/elf_file.h index a749d50..d6acc76 100644 --- a/tools/relocation_packer/src/elf_file.h +++ b/tools/relocation_packer/src/elf_file.h @@ -36,7 +36,7 @@ class ElfFile { explicit ElfFile(int fd) : fd_(fd), is_padding_relocations_(false), elf_(NULL), relocations_section_(NULL), dynamic_section_(NULL), - relocations_type_(NONE) {} + relocations_type_(NONE), has_android_relocations_(false) {} ~ElfFile() {} // Set padding mode. When padding, PackRelocations() will not shrink @@ -111,6 +111,9 @@ class ElfFile { // Relocation type found, assigned by Load(). relocations_type_t relocations_type_; + + // Elf-file has android relocations section + bool has_android_relocations_; }; } // namespace relocation_packer diff --git a/tools/relocation_packer/src/elf_file_unittest.cc b/tools/relocation_packer/src/elf_file_unittest.cc index 434f101..5271eef 100644 --- a/tools/relocation_packer/src/elf_file_unittest.cc +++ b/tools/relocation_packer/src/elf_file_unittest.cc @@ -175,13 +175,19 @@ static void RunPackRelocationsTestFor(const std::string& arch) { namespace relocation_packer { -TEST(ElfFile, PackRelocations) { +TEST(ElfFile, PackRelocationsArm32) { RunPackRelocationsTestFor("arm32"); +} + +TEST(ElfFile, PackRelocationsArm64) { RunPackRelocationsTestFor("arm64"); } -TEST(ElfFile, UnpackRelocations) { +TEST(ElfFile, UnpackRelocationsArm32) { RunUnpackRelocationsTestFor("arm32"); +} + +TEST(ElfFile, UnpackRelocationsArm64) { RunUnpackRelocationsTestFor("arm64"); } diff --git a/tools/relocation_packer/src/leb128.cc b/tools/relocation_packer/src/leb128.cc deleted file mode 100644 index 101c557..0000000 --- a/tools/relocation_packer/src/leb128.cc +++ /dev/null @@ -1,87 +0,0 @@ -// 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 "leb128.h" - -#include <stdint.h> -#include <vector> - -#include "elf_traits.h" - -namespace relocation_packer { - -// Empty constructor and destructor to silence chromium-style. -template <typename uint_t> -Leb128Encoder<uint_t>::Leb128Encoder() { } - -template <typename uint_t> -Leb128Encoder<uint_t>::~Leb128Encoder() { } - -// Add a single value to the encoding. Values are encoded with variable -// length. The least significant 7 bits of each byte hold 7 bits of data, -// and the most significant bit is set on each byte except the last. -template <typename uint_t> -void Leb128Encoder<uint_t>::Enqueue(uint_t value) { - uint_t uvalue = static_cast<uint_t>(value); - do { - const uint8_t byte = uvalue & 127; - uvalue >>= 7; - encoding_.push_back((uvalue ? 128 : 0) | byte); - } while (uvalue); -} - -// Add a vector of values to the encoding. -template <typename uint_t> -void Leb128Encoder<uint_t>::EnqueueAll(const std::vector<uint_t>& values) { - for (size_t i = 0; i < values.size(); ++i) { - Enqueue(values[i]); - } -} - -// Create a new decoder for the given encoded stream. -template <typename uint_t> -Leb128Decoder<uint_t>::Leb128Decoder(const std::vector<uint8_t>& encoding, size_t start_with) { - encoding_ = encoding; - cursor_ = start_with; -} - -// Empty destructor to silence chromium-style. -template <typename uint_t> -Leb128Decoder<uint_t>::~Leb128Decoder() { } - -// Decode and retrieve a single value from the encoding. Read forwards until -// a byte without its most significant bit is found, then read the 7 bit -// fields of the bytes spanned to re-form the value. -template <typename uint_t> -uint_t Leb128Decoder<uint_t>::Dequeue() { - uint_t value = 0; - - size_t shift = 0; - uint8_t byte; - - // Loop until we reach a byte with its high order bit clear. - do { - byte = encoding_[cursor_++]; - value |= static_cast<uint_t>(byte & 127) << shift; - shift += 7; - } while (byte & 128); - - return value; -} - -// Decode and retrieve all remaining values from the encoding. -template <typename uint_t> -void Leb128Decoder<uint_t>::DequeueAll(std::vector<uint_t>* values) { - while (cursor_ < encoding_.size()) { - values->push_back(Dequeue()); - } -} - -template class Leb128Encoder<uint32_t>; -template class Leb128Encoder<uint64_t>; - -template class Leb128Decoder<uint32_t>; -template class Leb128Decoder<uint64_t>; - -} // namespace relocation_packer diff --git a/tools/relocation_packer/src/leb128.h b/tools/relocation_packer/src/leb128.h deleted file mode 100644 index 67fc4b8..0000000 --- a/tools/relocation_packer/src/leb128.h +++ /dev/null @@ -1,75 +0,0 @@ -// 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. - -// LEB128 encoder and decoder for packed relative relocations. -// -// Packed relocations consist of a large number of relatively small -// integer values. Encoding these as LEB128 saves space. -// -// For more on LEB128 see http://en.wikipedia.org/wiki/LEB128. - -#ifndef TOOLS_RELOCATION_PACKER_SRC_LEB128_H_ -#define TOOLS_RELOCATION_PACKER_SRC_LEB128_H_ - -#include <stdint.h> -#include <vector> - -#include "elf_traits.h" - -namespace relocation_packer { - -// Encode packed words as a LEB128 byte stream. -template <typename uint_t> -class Leb128Encoder { - public: - // Explicit (but empty) constructor and destructor, for chromium-style. - Leb128Encoder(); - ~Leb128Encoder(); - - // Add a value to the encoding stream. - // |value| is the unsigned int to add. - void Enqueue(uint_t value); - - // Add a vector of values to the encoding stream. - // |values| is the vector of unsigned ints to add. - void EnqueueAll(const std::vector<uint_t>& values); - - // Retrieve the encoded representation of the values. - // |encoding| is the returned vector of encoded data. - void GetEncoding(std::vector<uint8_t>* encoding) { *encoding = encoding_; } - - private: - // Growable vector holding the encoded LEB128 stream. - std::vector<uint8_t> encoding_; -}; - -// Decode a LEB128 byte stream to produce packed words. -template <typename uint_t> -class Leb128Decoder { - public: - // Create a new decoder for the given encoded stream. - // |encoding| is the vector of encoded data. - explicit Leb128Decoder(const std::vector<uint8_t>& encoding, size_t start_with); - - // Explicit (but empty) destructor, for chromium-style. - ~Leb128Decoder(); - - // Retrieve the next value from the encoded stream. - uint_t Dequeue(); - - // Retrieve all remaining values from the encoded stream. - // |values| is the vector of decoded data. - void DequeueAll(std::vector<uint_t>* values); - - private: - // Encoded LEB128 stream. - std::vector<uint8_t> encoding_; - - // Cursor indicating the current stream retrieval point. - size_t cursor_; -}; - -} // namespace relocation_packer - -#endif // TOOLS_RELOCATION_PACKER_SRC_LEB128_H_ diff --git a/tools/relocation_packer/src/leb128_unittest.cc b/tools/relocation_packer/src/leb128_unittest.cc deleted file mode 100644 index 8a7028c..0000000 --- a/tools/relocation_packer/src/leb128_unittest.cc +++ /dev/null @@ -1,111 +0,0 @@ -// 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 "leb128.h" - -#include <vector> -#include "gtest/gtest.h" - -namespace relocation_packer { - -TEST(Leb128, Encoder64) { - std::vector<uint64_t> values; - values.push_back(624485); - values.push_back(0); - values.push_back(1); - values.push_back(127); - values.push_back(128); - - Leb128Encoder<uint64_t> encoder; - encoder.EnqueueAll(values); - - encoder.Enqueue(4294967295); - encoder.Enqueue(18446744073709551615ul); - - std::vector<uint8_t> encoding; - encoder.GetEncoding(&encoding); - - EXPECT_EQ(23U, encoding.size()); - // 624485 - EXPECT_EQ(0xe5, encoding[0]); - EXPECT_EQ(0x8e, encoding[1]); - EXPECT_EQ(0x26, encoding[2]); - // 0 - EXPECT_EQ(0x00, encoding[3]); - // 1 - EXPECT_EQ(0x01, encoding[4]); - // 127 - EXPECT_EQ(0x7f, encoding[5]); - // 128 - EXPECT_EQ(0x80, encoding[6]); - EXPECT_EQ(0x01, encoding[7]); - // 4294967295 - EXPECT_EQ(0xff, encoding[8]); - EXPECT_EQ(0xff, encoding[9]); - EXPECT_EQ(0xff, encoding[10]); - EXPECT_EQ(0xff, encoding[11]); - EXPECT_EQ(0x0f, encoding[12]); - // 18446744073709551615 - EXPECT_EQ(0xff, encoding[13]); - EXPECT_EQ(0xff, encoding[14]); - EXPECT_EQ(0xff, encoding[15]); - EXPECT_EQ(0xff, encoding[16]); - EXPECT_EQ(0xff, encoding[17]); - EXPECT_EQ(0xff, encoding[18]); - EXPECT_EQ(0xff, encoding[19]); - EXPECT_EQ(0xff, encoding[20]); - EXPECT_EQ(0xff, encoding[21]); - EXPECT_EQ(0x01, encoding[22]); -} - -TEST(Leb128, Decoder64) { - std::vector<uint8_t> encoding; - // 624485 - encoding.push_back(0xe5); - encoding.push_back(0x8e); - encoding.push_back(0x26); - // 0 - encoding.push_back(0x00); - // 1 - encoding.push_back(0x01); - // 127 - encoding.push_back(0x7f); - // 128 - encoding.push_back(0x80); - encoding.push_back(0x01); - // 4294967295 - encoding.push_back(0xff); - encoding.push_back(0xff); - encoding.push_back(0xff); - encoding.push_back(0xff); - encoding.push_back(0x0f); - // 18446744073709551615 - encoding.push_back(0xff); - encoding.push_back(0xff); - encoding.push_back(0xff); - encoding.push_back(0xff); - encoding.push_back(0xff); - encoding.push_back(0xff); - encoding.push_back(0xff); - encoding.push_back(0xff); - encoding.push_back(0xff); - encoding.push_back(0x01); - - Leb128Decoder<uint64_t> decoder(encoding, 0); - - EXPECT_EQ(624485U, decoder.Dequeue()); - - std::vector<uint64_t> dequeued; - decoder.DequeueAll(&dequeued); - - EXPECT_EQ(6U, dequeued.size()); - EXPECT_EQ(0U, dequeued[0]); - EXPECT_EQ(1U, dequeued[1]); - EXPECT_EQ(127U, dequeued[2]); - EXPECT_EQ(128U, dequeued[3]); - EXPECT_EQ(4294967295U, dequeued[4]); - EXPECT_EQ(18446744073709551615UL, dequeued[5]); -} - -} // namespace relocation_packer diff --git a/tools/relocation_packer/src/packer.cc b/tools/relocation_packer/src/packer.cc index 8e30612..433611f 100644 --- a/tools/relocation_packer/src/packer.cc +++ b/tools/relocation_packer/src/packer.cc @@ -9,7 +9,6 @@ #include "debug.h" #include "delta_encoder.h" #include "elf_traits.h" -#include "leb128.h" #include "sleb128.h" namespace relocation_packer { @@ -28,32 +27,17 @@ void RelocationPacker<ELF>::PackRelocations(const std::vector<typename ELF::Rela return; Sleb128Encoder<typename ELF::Addr> sleb128_encoder; - Leb128Encoder<typename ELF::Addr> leb128_encoder; - std::vector<uint8_t> leb128_packed; std::vector<uint8_t> sleb128_packed; - leb128_encoder.EnqueueAll(packed_words); - leb128_encoder.GetEncoding(&leb128_packed); - sleb128_encoder.EnqueueAll(packed_words); sleb128_encoder.GetEncoding(&sleb128_packed); - // TODO (simonb): Estimate savings on current android system image and consider using - // one encoder for all packed relocations to reduce complexity. - if (leb128_packed.size() <= sleb128_packed.size()) { - packed->push_back('A'); - packed->push_back('P'); - packed->push_back('U'); - packed->push_back('2'); - packed->insert(packed->end(), leb128_packed.begin(), leb128_packed.end()); - } else { - packed->push_back('A'); - packed->push_back('P'); - packed->push_back('S'); - packed->push_back('2'); - packed->insert(packed->end(), sleb128_packed.begin(), sleb128_packed.end()); - } + packed->push_back('A'); + packed->push_back('P'); + packed->push_back('S'); + packed->push_back('2'); + packed->insert(packed->end(), sleb128_packed.begin(), sleb128_packed.end()); } // Unpack relative relocations from a run-length encoded packed @@ -67,16 +51,11 @@ void RelocationPacker<ELF>::UnpackRelocations( CHECK(packed.size() > 4 && packed[0] == 'A' && packed[1] == 'P' && - (packed[2] == 'U' || packed[2] == 'S') && + packed[2] == 'S' && packed[3] == '2'); - if (packed[2] == 'U') { - Leb128Decoder<typename ELF::Addr> decoder(packed, 4); - decoder.DequeueAll(&packed_words); - } else { - Sleb128Decoder<typename ELF::Addr> decoder(packed, 4); - decoder.DequeueAll(&packed_words); - } + Sleb128Decoder<typename ELF::Addr> decoder(packed, 4); + decoder.DequeueAll(&packed_words); RelocationDeltaCodec<ELF> codec; codec.Decode(packed_words, relocations); diff --git a/tools/relocation_packer/src/packer_unittest.cc b/tools/relocation_packer/src/packer_unittest.cc index 8dddd8b..424b92c 100644 --- a/tools/relocation_packer/src/packer_unittest.cc +++ b/tools/relocation_packer/src/packer_unittest.cc @@ -39,6 +39,7 @@ 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. @@ -59,16 +60,16 @@ static void DoPackNoAddend() { size_t ndx = 0; EXPECT_EQ('A', packed[ndx++]); EXPECT_EQ('P', packed[ndx++]); - EXPECT_EQ('U', 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, 0d + // 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(0x0d, packed[ndx++]); + EXPECT_EQ(is_32 ? 0x7d : 0x0d, packed[ndx++]); // first group EXPECT_EQ(3, packed[ndx++]); // size EXPECT_EQ(3, packed[ndx++]); // flags @@ -83,8 +84,11 @@ static void DoPackNoAddend() { EXPECT_EQ(ndx, packed.size()); } -TEST(Packer, PackNoAddend) { +TEST(Packer, PackNoAddend32) { DoPackNoAddend<ELF32_traits>(); +} + +TEST(Packer, PackNoAddend64) { DoPackNoAddend<ELF64_traits>(); } @@ -92,18 +96,19 @@ 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('U'); + packed.push_back('S'); packed.push_back('2'); // relocation count packed.push_back(6); - // base relocation = 0xd1cdfffc -> fc, ff, b7, 8e, 0d + // 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(0x0d); + packed.push_back(is_32 ? 0x7d : 0x0d); // first group packed.push_back(3); // size packed.push_back(3); // flags @@ -131,8 +136,11 @@ static void DoUnpackNoAddend() { EXPECT_EQ(ndx, relocations.size()); } -TEST(Packer, UnpackNoAddend) { +TEST(Packer, UnpackNoAddend32) { DoUnpackNoAddend<ELF32_traits>(); +} + +TEST(Packer, UnpackNoAddend64) { DoUnpackNoAddend<ELF64_traits>(); } diff --git a/tools/relocation_packer/test_data/elf_file_unittest_relocs_arm32_packed.so b/tools/relocation_packer/test_data/elf_file_unittest_relocs_arm32_packed.so Binary files differindex d97ef82..6ac2eef 100755 --- a/tools/relocation_packer/test_data/elf_file_unittest_relocs_arm32_packed.so +++ b/tools/relocation_packer/test_data/elf_file_unittest_relocs_arm32_packed.so diff --git a/tools/relocation_packer/test_data/elf_file_unittest_relocs_arm64_packed.so b/tools/relocation_packer/test_data/elf_file_unittest_relocs_arm64_packed.so Binary files differindex e44e459..a2b0039 100755 --- a/tools/relocation_packer/test_data/elf_file_unittest_relocs_arm64_packed.so +++ b/tools/relocation_packer/test_data/elf_file_unittest_relocs_arm64_packed.so |