Commit | Line | Data |
---|---|---|
4f787271 DK |
1 | // int_encoding.h -- variable length and unaligned integers -*- C++ -*- |
2 | ||
6f2750fe | 3 | // Copyright (C) 2009-2016 Free Software Foundation, Inc. |
4f787271 DK |
4 | // Written by Doug Kwan <dougkwan@google.com> by refactoring scattered |
5 | // contents from other files in gold. Original code written by Ian | |
6 | // Lance Taylor <iant@google.com> and Caleb Howe <cshowe@google.com>. | |
7 | ||
8 | // This file is part of gold. | |
9 | ||
10 | // This program is free software; you can redistribute it and/or modify | |
11 | // it under the terms of the GNU General Public License as published by | |
12 | // the Free Software Foundation; either version 3 of the License, or | |
13 | // (at your option) any later version. | |
14 | ||
15 | // This program is distributed in the hope that it will be useful, | |
16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | // GNU General Public License for more details. | |
19 | ||
20 | // You should have received a copy of the GNU General Public License | |
21 | // along with this program; if not, write to the Free Software | |
22 | // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, | |
23 | // MA 02110-1301, USA. | |
24 | ||
25 | #ifndef GOLD_INT_ENCODING_H | |
26 | #define GOLD_INT_ENCODING_H | |
27 | ||
28 | #include <vector> | |
29 | #include "elfcpp.h" | |
30 | #include "target.h" | |
31 | #include "parameters.h" | |
32 | ||
33 | namespace gold | |
34 | { | |
35 | ||
36 | // | |
37 | // LEB 128 encoding support. | |
38 | // | |
39 | ||
40 | // Read a ULEB 128 encoded integer from BUFFER. Return the length of the | |
c2c7840a CC |
41 | // encoded integer at the location PLEN. The common case of a single-byte |
42 | // value is handled inline, and multi-byte values are processed by the _x | |
43 | // routine, where BYTE is the first byte of the value. | |
4f787271 DK |
44 | |
45 | uint64_t | |
c2c7840a CC |
46 | read_unsigned_LEB_128_x(const unsigned char* buffer, size_t* plen, |
47 | unsigned char byte); | |
48 | ||
49 | inline uint64_t | |
50 | read_unsigned_LEB_128(const unsigned char* buffer, size_t* plen) | |
51 | { | |
52 | unsigned char byte = *buffer++; | |
53 | ||
54 | if ((byte & 0x80) != 0) | |
55 | return read_unsigned_LEB_128_x(buffer, plen, byte); | |
56 | ||
57 | *plen = 1; | |
58 | return static_cast<uint64_t>(byte); | |
59 | } | |
4f787271 DK |
60 | |
61 | // Read an SLEB 128 encoded integer from BUFFER. Return the length of the | |
c2c7840a CC |
62 | // encoded integer at the location PLEN. The common case of a single-byte |
63 | // value is handled inline, and multi-byte values are processed by the _x | |
64 | // routine, where BYTE is the first byte of the value. | |
4f787271 DK |
65 | |
66 | int64_t | |
c2c7840a CC |
67 | read_signed_LEB_128_x(const unsigned char* buffer, size_t* plen, |
68 | unsigned char byte); | |
69 | ||
70 | inline int64_t | |
71 | read_signed_LEB_128(const unsigned char* buffer, size_t* plen) | |
72 | { | |
73 | unsigned char byte = *buffer++; | |
74 | ||
75 | if ((byte & 0x80) != 0) | |
76 | return read_signed_LEB_128_x(buffer, plen, byte); | |
77 | ||
78 | *plen = 1; | |
79 | if (byte & 0x40) | |
80 | return -(static_cast<int64_t>(1) << 7) | static_cast<int64_t>(byte); | |
81 | return static_cast<int64_t>(byte); | |
82 | } | |
4f787271 DK |
83 | |
84 | // Write a ULEB 128 encoded VALUE to BUFFER. | |
85 | ||
86 | void | |
87 | write_unsigned_LEB_128(std::vector<unsigned char>* buffer, uint64_t value); | |
88 | ||
89 | // Return the ULEB 128 encoded size of VALUE. | |
90 | ||
91 | size_t | |
92 | get_length_as_unsigned_LEB_128(uint64_t value); | |
93 | ||
94 | // | |
95 | // Unaligned integer encoding support. | |
96 | // | |
97 | ||
98 | // Insert VALSIZE-bit integer VALUE into DESTINATION. | |
99 | ||
100 | template <int valsize> | |
101 | void insert_into_vector(std::vector<unsigned char>* destination, | |
102 | typename elfcpp::Valtype_base<valsize>::Valtype value) | |
103 | { | |
104 | unsigned char buffer[valsize / 8]; | |
105 | if (parameters->target().is_big_endian()) | |
106 | elfcpp::Swap_unaligned<valsize, true>::writeval(buffer, value); | |
107 | else | |
108 | elfcpp::Swap_unaligned<valsize, false>::writeval(buffer, value); | |
109 | destination->insert(destination->end(), buffer, buffer + valsize / 8); | |
110 | } | |
111 | ||
41cbeecc ST |
112 | // Read a possibly unaligned integer of SIZE from SOURCE. |
113 | ||
114 | template <int valsize> | |
115 | typename elfcpp::Valtype_base<valsize>::Valtype | |
116 | read_from_pointer(const unsigned char* source) | |
117 | { | |
118 | typename elfcpp::Valtype_base<valsize>::Valtype return_value; | |
119 | if (parameters->target().is_big_endian()) | |
120 | return_value = elfcpp::Swap_unaligned<valsize, true>::readval(source); | |
121 | else | |
122 | return_value = elfcpp::Swap_unaligned<valsize, false>::readval(source); | |
123 | return return_value; | |
124 | } | |
125 | ||
4f787271 DK |
126 | // Read a possibly unaligned integer of SIZE. Update SOURCE after read. |
127 | ||
128 | template <int valsize> | |
129 | typename elfcpp::Valtype_base<valsize>::Valtype | |
130 | read_from_pointer(unsigned char** source) | |
131 | { | |
132 | typename elfcpp::Valtype_base<valsize>::Valtype return_value; | |
133 | if (parameters->target().is_big_endian()) | |
134 | return_value = elfcpp::Swap_unaligned<valsize, true>::readval(*source); | |
135 | else | |
136 | return_value = elfcpp::Swap_unaligned<valsize, false>::readval(*source); | |
137 | *source += valsize / 8; | |
138 | return return_value; | |
139 | } | |
140 | ||
141 | // Same as the above except for use with const unsigned char data. | |
142 | ||
143 | template <int valsize> | |
144 | typename elfcpp::Valtype_base<valsize>::Valtype | |
145 | read_from_pointer(const unsigned char** source) | |
146 | { | |
147 | typename elfcpp::Valtype_base<valsize>::Valtype return_value; | |
148 | if (parameters->target().is_big_endian()) | |
149 | return_value = elfcpp::Swap_unaligned<valsize, true>::readval(*source); | |
150 | else | |
151 | return_value = elfcpp::Swap_unaligned<valsize, false>::readval(*source); | |
152 | *source += valsize / 8; | |
153 | return return_value; | |
154 | } | |
155 | ||
156 | } // End namespace gold. | |
157 | ||
158 | #endif // !defined(GOLD_INT_ENCODING_H) |