1 // int_encoding.h -- variable length and unaligned integers -*- C++ -*- 2 3 // Copyright (C) 2009-2014 Free Software Foundation, Inc. 4 // Written by Doug Kwan <dougkwan (at) google.com> by refactoring scattered 5 // contents from other files in gold. Original code written by Ian 6 // Lance Taylor <iant (at) google.com> and Caleb Howe <cshowe (at) 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 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. 44 45 uint64_t 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 } 60 61 // Read an SLEB 128 encoded integer from BUFFER. Return the length of the 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. 65 66 int64_t 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 } 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 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 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) 159