packer.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "packer.h"
6
7#include <vector>
8
9#include "debug.h"
10#include "delta_encoder.h"
11#include "elf_traits.h"
12#include "leb128.h"
13#include "run_length_encoder.h"
14#include "sleb128.h"
15
16namespace relocation_packer {
17
18// Pack relative relocations into a run-length encoded packed
19// representation.
20void RelocationPacker::PackRelativeRelocations(
21    const std::vector<ELF::Rel>& relocations,
22    std::vector<uint8_t>* packed) {
23  // Run-length encode.
24  std::vector<ELF::Xword> packed_words;
25  RelocationRunLengthCodec codec;
26  codec.Encode(relocations, &packed_words);
27
28  // If insufficient data to run-length encode, do nothing.
29  if (packed_words.empty())
30    return;
31
32  // LEB128 encode, with "APR1" prefix.
33  Leb128Encoder encoder;
34  encoder.Enqueue('A');
35  encoder.Enqueue('P');
36  encoder.Enqueue('R');
37  encoder.Enqueue('1');
38  encoder.EnqueueAll(packed_words);
39
40  encoder.GetEncoding(packed);
41
42  // Pad packed to a whole number of words.  This padding will decode as
43  // LEB128 zeroes.  Run-length decoding ignores it because encoding
44  // embeds the pairs count in the stream itself.
45  while (packed->size() % sizeof(ELF::Word))
46    packed->push_back(0);
47}
48
49// Unpack relative relocations from a run-length encoded packed
50// representation.
51void RelocationPacker::UnpackRelativeRelocations(
52    const std::vector<uint8_t>& packed,
53    std::vector<ELF::Rel>* relocations) {
54  // LEB128 decode, after checking and stripping "APR1" prefix.
55  std::vector<ELF::Xword> packed_words;
56  Leb128Decoder decoder(packed);
57  CHECK(decoder.Dequeue() == 'A' &&
58        decoder.Dequeue() == 'P' &&
59        decoder.Dequeue() == 'R' &&
60        decoder.Dequeue() == '1');
61  decoder.DequeueAll(&packed_words);
62
63  // Run-length decode.
64  RelocationRunLengthCodec codec;
65  codec.Decode(packed_words, relocations);
66}
67
68// Pack relative relocations with addends into a delta encoded packed
69// representation.
70void RelocationPacker::PackRelativeRelocations(
71    const std::vector<ELF::Rela>& relocations,
72    std::vector<uint8_t>* packed) {
73  // Delta encode.
74  std::vector<ELF::Sxword> packed_words;
75  RelocationDeltaCodec codec;
76  codec.Encode(relocations, &packed_words);
77
78  // If insufficient data to delta encode, do nothing.
79  if (packed_words.empty())
80    return;
81
82  // Signed LEB128 encode, with "APA1" prefix.  ASCII does not encode as
83  // itself under signed LEB128, so we have to treat it specially.
84  Sleb128Encoder encoder;
85  encoder.EnqueueAll(packed_words);
86  std::vector<uint8_t> encoded;
87  encoder.GetEncoding(&encoded);
88
89  packed->push_back('A');
90  packed->push_back('P');
91  packed->push_back('A');
92  packed->push_back('1');
93  packed->insert(packed->end(), encoded.begin(), encoded.end());
94
95  // Pad packed to a whole number of words.  This padding will decode as
96  // signed LEB128 zeroes.  Delta decoding ignores it because encoding
97  // embeds the pairs count in the stream itself.
98  while (packed->size() % sizeof(ELF::Word))
99    packed->push_back(0);
100}
101
102// Unpack relative relocations with addends from a delta encoded
103// packed representation.
104void RelocationPacker::UnpackRelativeRelocations(
105    const std::vector<uint8_t>& packed,
106    std::vector<ELF::Rela>* relocations) {
107  // Check "APA1" prefix.
108  CHECK(packed.at(0) == 'A' &&
109        packed.at(1) == 'P' &&
110        packed.at(2) == 'A' &&
111        packed.at(3) == '1');
112
113  // Signed LEB128 decode, after stripping "APA1" prefix.
114  std::vector<ELF::Sxword> packed_words;
115  std::vector<uint8_t> stripped(packed.begin() + 4, packed.end());
116  Sleb128Decoder decoder(stripped);
117  decoder.DequeueAll(&packed_words);
118
119  // Delta decode.
120  RelocationDeltaCodec codec;
121  codec.Decode(packed_words, relocations);
122}
123
124}  // namespace relocation_packer
125