| // 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) |