aboutsummaryrefslogtreecommitdiff
blob: 1a1855bf5adcdf7a0ccd3f9b27cd4292e2a924c7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// int_encoding.h -- variable length and unaligned integers -*- C++ -*-

// Copyright (C) 2009-2024 Free Software Foundation, Inc.
// Written by Doug Kwan <dougkwan@google.com> by refactoring scattered
// contents from other files in gold.  Original code written by Ian
// Lance Taylor <iant@google.com> and Caleb Howe  <cshowe@google.com>.

// This file is part of gold.

// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
// MA 02110-1301, USA.

#ifndef GOLD_INT_ENCODING_H
#define GOLD_INT_ENCODING_H

#include <vector>
#include "elfcpp.h"
#include "target.h"
#include "parameters.h"

namespace gold
{

//
// LEB 128 encoding support.
//

// Read a ULEB 128 encoded integer from BUFFER.  Return the length of the
// encoded integer at the location PLEN.  The common case of a single-byte
// value is handled inline, and multi-byte values are processed by the _x
// routine, where BYTE is the first byte of the value.

uint64_t
read_unsigned_LEB_128_x(const unsigned char* buffer, size_t* plen,
			unsigned char byte);

inline uint64_t
read_unsigned_LEB_128(const unsigned char* buffer, size_t* plen)
{
  unsigned char byte = *buffer++;

  if ((byte & 0x80) != 0)
    return read_unsigned_LEB_128_x(buffer, plen, byte);

  *plen = 1;
  return static_cast<uint64_t>(byte);
}

// Read an SLEB 128 encoded integer from BUFFER.  Return the length of the
// encoded integer at the location PLEN.  The common case of a single-byte
// value is handled inline, and multi-byte values are processed by the _x
// routine, where BYTE is the first byte of the value.

int64_t
read_signed_LEB_128_x(const unsigned char* buffer, size_t* plen,
		      unsigned char byte);

inline int64_t
read_signed_LEB_128(const unsigned char* buffer, size_t* plen)
{
  unsigned char byte = *buffer++;

  if ((byte & 0x80) != 0)
    return read_signed_LEB_128_x(buffer, plen, byte);

  *plen = 1;
  if (byte & 0x40)
    return -(static_cast<int64_t>(1) << 7) | static_cast<int64_t>(byte);
  return static_cast<int64_t>(byte);
}

// Write a ULEB 128 encoded VALUE to BUFFER.

void
write_unsigned_LEB_128(std::vector<unsigned char>* buffer, uint64_t value);

// Return the ULEB 128 encoded size of VALUE.

size_t
get_length_as_unsigned_LEB_128(uint64_t value);

//
// Unaligned integer encoding support.
//

// Insert VALSIZE-bit integer VALUE into DESTINATION.

template <int valsize>
void insert_into_vector(std::vector<unsigned char>* destination,
                        typename elfcpp::Valtype_base<valsize>::Valtype value)
{
  unsigned char buffer[valsize / 8];
  if (parameters->target().is_big_endian())
    elfcpp::Swap_unaligned<valsize, true>::writeval(buffer, value);
  else
    elfcpp::Swap_unaligned<valsize, false>::writeval(buffer, value);
  destination->insert(destination->end(), buffer, buffer + valsize / 8);
}

// Read a possibly unaligned integer of SIZE from SOURCE.

template <int valsize>
typename elfcpp::Valtype_base<valsize>::Valtype
read_from_pointer(const unsigned char* source)
{
  typename elfcpp::Valtype_base<valsize>::Valtype return_value;
  if (parameters->target().is_big_endian())
    return_value = elfcpp::Swap_unaligned<valsize, true>::readval(source);
  else
    return_value = elfcpp::Swap_unaligned<valsize, false>::readval(source);
  return return_value;
}

// Read a possibly unaligned integer of SIZE.  Update SOURCE after read.

template <int valsize>
typename elfcpp::Valtype_base<valsize>::Valtype
read_from_pointer(unsigned char** source)
{
  typename elfcpp::Valtype_base<valsize>::Valtype return_value;
  if (parameters->target().is_big_endian())
    return_value = elfcpp::Swap_unaligned<valsize, true>::readval(*source);
  else
    return_value = elfcpp::Swap_unaligned<valsize, false>::readval(*source);
  *source += valsize / 8;
  return return_value;
}

// Same as the above except for use with const unsigned char data.

template <int valsize>
typename elfcpp::Valtype_base<valsize>::Valtype
read_from_pointer(const unsigned char** source)
{
  typename elfcpp::Valtype_base<valsize>::Valtype return_value;
  if (parameters->target().is_big_endian())
    return_value = elfcpp::Swap_unaligned<valsize, true>::readval(*source);
  else
    return_value = elfcpp::Swap_unaligned<valsize, false>::readval(*source);
  *source += valsize / 8;
  return return_value;
}

} // End namespace gold.

#endif // !defined(GOLD_INT_ENCODING_H)