// 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 #include "debug.h" #include "delta_encoder.h" #include "elf_traits.h" #include "leb128.h" #include "run_length_encoder.h" #include "sleb128.h" namespace relocation_packer { // Pack relative relocations into a run-length encoded packed // representation. void RelocationPacker::PackRelativeRelocations( const std::vector& relocations, std::vector* packed) { // Run-length encode. std::vector packed_words; RelocationRunLengthCodec codec; codec.Encode(relocations, &packed_words); // If insufficient data to run-length encode, do nothing. if (packed_words.empty()) return; // LEB128 encode, with "APR1" prefix. Leb128Encoder encoder; encoder.Enqueue('A'); encoder.Enqueue('P'); encoder.Enqueue('R'); encoder.Enqueue('1'); encoder.EnqueueAll(packed_words); encoder.GetEncoding(packed); // Pad packed to a whole number of words. This padding will decode as // LEB128 zeroes. Run-length decoding ignores it because encoding // embeds the pairs count in the stream itself. while (packed->size() % sizeof(ELF::Word)) packed->push_back(0); } // Unpack relative relocations from a run-length encoded packed // representation. void RelocationPacker::UnpackRelativeRelocations( const std::vector& packed, std::vector* relocations) { // LEB128 decode, after checking and stripping "APR1" prefix. std::vector packed_words; Leb128Decoder decoder(packed); CHECK(decoder.Dequeue() == 'A' && decoder.Dequeue() == 'P' && decoder.Dequeue() == 'R' && decoder.Dequeue() == '1'); decoder.DequeueAll(&packed_words); // Run-length decode. RelocationRunLengthCodec codec; codec.Decode(packed_words, relocations); } // Pack relative relocations with addends into a delta encoded packed // representation. void RelocationPacker::PackRelativeRelocations( const std::vector& relocations, std::vector* packed) { // Delta encode. std::vector packed_words; RelocationDeltaCodec codec; codec.Encode(relocations, &packed_words); // If insufficient data to delta encode, do nothing. if (packed_words.empty()) return; // Signed LEB128 encode, with "APA1" prefix. ASCII does not encode as // itself under signed LEB128, so we have to treat it specially. Sleb128Encoder encoder; encoder.EnqueueAll(packed_words); std::vector encoded; encoder.GetEncoding(&encoded); packed->push_back('A'); packed->push_back('P'); packed->push_back('A'); packed->push_back('1'); packed->insert(packed->end(), encoded.begin(), encoded.end()); // Pad packed to a whole number of words. This padding will decode as // signed LEB128 zeroes. Delta decoding ignores it because encoding // embeds the pairs count in the stream itself. while (packed->size() % sizeof(ELF::Word)) packed->push_back(0); } // Unpack relative relocations with addends from a delta encoded // packed representation. void RelocationPacker::UnpackRelativeRelocations( const std::vector& packed, std::vector* relocations) { // Check "APA1" prefix. CHECK(packed.at(0) == 'A' && packed.at(1) == 'P' && packed.at(2) == 'A' && packed.at(3) == '1'); // Signed LEB128 decode, after stripping "APA1" prefix. std::vector packed_words; std::vector stripped(packed.begin() + 4, packed.end()); Sleb128Decoder decoder(stripped); decoder.DequeueAll(&packed_words); // Delta decode. RelocationDeltaCodec codec; codec.Decode(packed_words, relocations); } } // namespace relocation_packer