175fd0b74Schristos // int_encoding.h -- variable length and unaligned integers -*- C++ -*-
275fd0b74Schristos
3*e992f068Schristos // Copyright (C) 2009-2022 Free Software Foundation, Inc.
475fd0b74Schristos // Written by Doug Kwan <dougkwan@google.com> by refactoring scattered
575fd0b74Schristos // contents from other files in gold. Original code written by Ian
675fd0b74Schristos // Lance Taylor <iant@google.com> and Caleb Howe <cshowe@google.com>.
775fd0b74Schristos
875fd0b74Schristos // This file is part of gold.
975fd0b74Schristos
1075fd0b74Schristos // This program is free software; you can redistribute it and/or modify
1175fd0b74Schristos // it under the terms of the GNU General Public License as published by
1275fd0b74Schristos // the Free Software Foundation; either version 3 of the License, or
1375fd0b74Schristos // (at your option) any later version.
1475fd0b74Schristos
1575fd0b74Schristos // This program is distributed in the hope that it will be useful,
1675fd0b74Schristos // but WITHOUT ANY WARRANTY; without even the implied warranty of
1775fd0b74Schristos // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1875fd0b74Schristos // GNU General Public License for more details.
1975fd0b74Schristos
2075fd0b74Schristos // You should have received a copy of the GNU General Public License
2175fd0b74Schristos // along with this program; if not, write to the Free Software
2275fd0b74Schristos // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
2375fd0b74Schristos // MA 02110-1301, USA.
2475fd0b74Schristos
2575fd0b74Schristos #ifndef GOLD_INT_ENCODING_H
2675fd0b74Schristos #define GOLD_INT_ENCODING_H
2775fd0b74Schristos
2875fd0b74Schristos #include <vector>
2975fd0b74Schristos #include "elfcpp.h"
3075fd0b74Schristos #include "target.h"
3175fd0b74Schristos #include "parameters.h"
3275fd0b74Schristos
3375fd0b74Schristos namespace gold
3475fd0b74Schristos {
3575fd0b74Schristos
3675fd0b74Schristos //
3775fd0b74Schristos // LEB 128 encoding support.
3875fd0b74Schristos //
3975fd0b74Schristos
4075fd0b74Schristos // Read a ULEB 128 encoded integer from BUFFER. Return the length of the
4175fd0b74Schristos // encoded integer at the location PLEN. The common case of a single-byte
4275fd0b74Schristos // value is handled inline, and multi-byte values are processed by the _x
4375fd0b74Schristos // routine, where BYTE is the first byte of the value.
4475fd0b74Schristos
4575fd0b74Schristos uint64_t
4675fd0b74Schristos read_unsigned_LEB_128_x(const unsigned char* buffer, size_t* plen,
4775fd0b74Schristos unsigned char byte);
4875fd0b74Schristos
4975fd0b74Schristos inline uint64_t
read_unsigned_LEB_128(const unsigned char * buffer,size_t * plen)5075fd0b74Schristos read_unsigned_LEB_128(const unsigned char* buffer, size_t* plen)
5175fd0b74Schristos {
5275fd0b74Schristos unsigned char byte = *buffer++;
5375fd0b74Schristos
5475fd0b74Schristos if ((byte & 0x80) != 0)
5575fd0b74Schristos return read_unsigned_LEB_128_x(buffer, plen, byte);
5675fd0b74Schristos
5775fd0b74Schristos *plen = 1;
5875fd0b74Schristos return static_cast<uint64_t>(byte);
5975fd0b74Schristos }
6075fd0b74Schristos
6175fd0b74Schristos // Read an SLEB 128 encoded integer from BUFFER. Return the length of the
6275fd0b74Schristos // encoded integer at the location PLEN. The common case of a single-byte
6375fd0b74Schristos // value is handled inline, and multi-byte values are processed by the _x
6475fd0b74Schristos // routine, where BYTE is the first byte of the value.
6575fd0b74Schristos
6675fd0b74Schristos int64_t
6775fd0b74Schristos read_signed_LEB_128_x(const unsigned char* buffer, size_t* plen,
6875fd0b74Schristos unsigned char byte);
6975fd0b74Schristos
7075fd0b74Schristos inline int64_t
read_signed_LEB_128(const unsigned char * buffer,size_t * plen)7175fd0b74Schristos read_signed_LEB_128(const unsigned char* buffer, size_t* plen)
7275fd0b74Schristos {
7375fd0b74Schristos unsigned char byte = *buffer++;
7475fd0b74Schristos
7575fd0b74Schristos if ((byte & 0x80) != 0)
7675fd0b74Schristos return read_signed_LEB_128_x(buffer, plen, byte);
7775fd0b74Schristos
7875fd0b74Schristos *plen = 1;
7975fd0b74Schristos if (byte & 0x40)
8075fd0b74Schristos return -(static_cast<int64_t>(1) << 7) | static_cast<int64_t>(byte);
8175fd0b74Schristos return static_cast<int64_t>(byte);
8275fd0b74Schristos }
8375fd0b74Schristos
8475fd0b74Schristos // Write a ULEB 128 encoded VALUE to BUFFER.
8575fd0b74Schristos
8675fd0b74Schristos void
8775fd0b74Schristos write_unsigned_LEB_128(std::vector<unsigned char>* buffer, uint64_t value);
8875fd0b74Schristos
8975fd0b74Schristos // Return the ULEB 128 encoded size of VALUE.
9075fd0b74Schristos
9175fd0b74Schristos size_t
9275fd0b74Schristos get_length_as_unsigned_LEB_128(uint64_t value);
9375fd0b74Schristos
9475fd0b74Schristos //
9575fd0b74Schristos // Unaligned integer encoding support.
9675fd0b74Schristos //
9775fd0b74Schristos
9875fd0b74Schristos // Insert VALSIZE-bit integer VALUE into DESTINATION.
9975fd0b74Schristos
10075fd0b74Schristos template <int valsize>
insert_into_vector(std::vector<unsigned char> * destination,typename elfcpp::Valtype_base<valsize>::Valtype value)10175fd0b74Schristos void insert_into_vector(std::vector<unsigned char>* destination,
10275fd0b74Schristos typename elfcpp::Valtype_base<valsize>::Valtype value)
10375fd0b74Schristos {
10475fd0b74Schristos unsigned char buffer[valsize / 8];
10575fd0b74Schristos if (parameters->target().is_big_endian())
10675fd0b74Schristos elfcpp::Swap_unaligned<valsize, true>::writeval(buffer, value);
10775fd0b74Schristos else
10875fd0b74Schristos elfcpp::Swap_unaligned<valsize, false>::writeval(buffer, value);
10975fd0b74Schristos destination->insert(destination->end(), buffer, buffer + valsize / 8);
11075fd0b74Schristos }
11175fd0b74Schristos
11275fd0b74Schristos // Read a possibly unaligned integer of SIZE from SOURCE.
11375fd0b74Schristos
11475fd0b74Schristos template <int valsize>
11575fd0b74Schristos typename elfcpp::Valtype_base<valsize>::Valtype
read_from_pointer(const unsigned char * source)11675fd0b74Schristos read_from_pointer(const unsigned char* source)
11775fd0b74Schristos {
11875fd0b74Schristos typename elfcpp::Valtype_base<valsize>::Valtype return_value;
11975fd0b74Schristos if (parameters->target().is_big_endian())
12075fd0b74Schristos return_value = elfcpp::Swap_unaligned<valsize, true>::readval(source);
12175fd0b74Schristos else
12275fd0b74Schristos return_value = elfcpp::Swap_unaligned<valsize, false>::readval(source);
12375fd0b74Schristos return return_value;
12475fd0b74Schristos }
12575fd0b74Schristos
12675fd0b74Schristos // Read a possibly unaligned integer of SIZE. Update SOURCE after read.
12775fd0b74Schristos
12875fd0b74Schristos template <int valsize>
12975fd0b74Schristos typename elfcpp::Valtype_base<valsize>::Valtype
read_from_pointer(unsigned char ** source)13075fd0b74Schristos read_from_pointer(unsigned char** source)
13175fd0b74Schristos {
13275fd0b74Schristos typename elfcpp::Valtype_base<valsize>::Valtype return_value;
13375fd0b74Schristos if (parameters->target().is_big_endian())
13475fd0b74Schristos return_value = elfcpp::Swap_unaligned<valsize, true>::readval(*source);
13575fd0b74Schristos else
13675fd0b74Schristos return_value = elfcpp::Swap_unaligned<valsize, false>::readval(*source);
13775fd0b74Schristos *source += valsize / 8;
13875fd0b74Schristos return return_value;
13975fd0b74Schristos }
14075fd0b74Schristos
14175fd0b74Schristos // Same as the above except for use with const unsigned char data.
14275fd0b74Schristos
14375fd0b74Schristos template <int valsize>
14475fd0b74Schristos typename elfcpp::Valtype_base<valsize>::Valtype
read_from_pointer(const unsigned char ** source)14575fd0b74Schristos read_from_pointer(const unsigned char** source)
14675fd0b74Schristos {
14775fd0b74Schristos typename elfcpp::Valtype_base<valsize>::Valtype return_value;
14875fd0b74Schristos if (parameters->target().is_big_endian())
14975fd0b74Schristos return_value = elfcpp::Swap_unaligned<valsize, true>::readval(*source);
15075fd0b74Schristos else
15175fd0b74Schristos return_value = elfcpp::Swap_unaligned<valsize, false>::readval(*source);
15275fd0b74Schristos *source += valsize / 8;
15375fd0b74Schristos return return_value;
15475fd0b74Schristos }
15575fd0b74Schristos
15675fd0b74Schristos } // End namespace gold.
15775fd0b74Schristos
15875fd0b74Schristos #endif // !defined(GOLD_INT_ENCODING_H)
159