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 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
|
//===- lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h ------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
#define LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
#include "MachONormalizedFile.h"
#include "lld/Common/LLVM.h"
#include "lld/Core/Error.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/MachO.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/LEB128.h"
#include <system_error>
namespace lld {
namespace mach_o {
namespace normalized {
class ByteBuffer {
public:
ByteBuffer() : _ostream(_bytes) { }
void append_byte(uint8_t b) {
_ostream << b;
}
void append_uleb128(uint64_t value) {
llvm::encodeULEB128(value, _ostream);
}
void append_uleb128Fixed(uint64_t value, unsigned byteCount) {
unsigned min = llvm::getULEB128Size(value);
assert(min <= byteCount);
unsigned pad = byteCount - min;
llvm::encodeULEB128(value, _ostream, pad);
}
void append_sleb128(int64_t value) {
llvm::encodeSLEB128(value, _ostream);
}
void append_string(StringRef str) {
_ostream << str;
append_byte(0);
}
void align(unsigned alignment) {
while ( (_ostream.tell() % alignment) != 0 )
append_byte(0);
}
size_t size() {
return _ostream.tell();
}
const uint8_t *bytes() {
return reinterpret_cast<const uint8_t*>(_ostream.str().data());
}
private:
SmallVector<char, 128> _bytes;
// Stream ivar must be after SmallVector ivar to construct properly.
llvm::raw_svector_ostream _ostream;
};
using namespace llvm::support::endian;
using llvm::sys::getSwappedBytes;
template<typename T>
static inline uint16_t read16(const T *loc, bool isBig) {
assert((uint64_t)loc % alignof(T) == 0 && "invalid pointer alignment");
return isBig ? read16be(loc) : read16le(loc);
}
template<typename T>
static inline uint32_t read32(const T *loc, bool isBig) {
assert((uint64_t)loc % alignof(T) == 0 && "invalid pointer alignment");
return isBig ? read32be(loc) : read32le(loc);
}
template<typename T>
static inline uint64_t read64(const T *loc, bool isBig) {
assert((uint64_t)loc % alignof(T) == 0 && "invalid pointer alignment");
return isBig ? read64be(loc) : read64le(loc);
}
inline void write16(uint8_t *loc, uint16_t value, bool isBig) {
if (isBig)
write16be(loc, value);
else
write16le(loc, value);
}
inline void write32(uint8_t *loc, uint32_t value, bool isBig) {
if (isBig)
write32be(loc, value);
else
write32le(loc, value);
}
inline void write64(uint8_t *loc, uint64_t value, bool isBig) {
if (isBig)
write64be(loc, value);
else
write64le(loc, value);
}
inline uint32_t
bitFieldExtract(uint32_t value, bool isBigEndianBigField, uint8_t firstBit,
uint8_t bitCount) {
const uint32_t mask = ((1<<bitCount)-1);
const uint8_t shift = isBigEndianBigField ? (32-firstBit-bitCount) : firstBit;
return (value >> shift) & mask;
}
inline void
bitFieldSet(uint32_t &bits, bool isBigEndianBigField, uint32_t newBits,
uint8_t firstBit, uint8_t bitCount) {
const uint32_t mask = ((1<<bitCount)-1);
assert((newBits & mask) == newBits);
const uint8_t shift = isBigEndianBigField ? (32-firstBit-bitCount) : firstBit;
bits &= ~(mask << shift);
bits |= (newBits << shift);
}
inline Relocation unpackRelocation(const llvm::MachO::any_relocation_info &r,
bool isBigEndian) {
uint32_t r0 = read32(&r.r_word0, isBigEndian);
uint32_t r1 = read32(&r.r_word1, isBigEndian);
Relocation result;
if (r0 & llvm::MachO::R_SCATTERED) {
// scattered relocation record always laid out like big endian bit field
result.offset = bitFieldExtract(r0, true, 8, 24);
result.scattered = true;
result.type = (RelocationInfoType)
bitFieldExtract(r0, true, 4, 4);
result.length = bitFieldExtract(r0, true, 2, 2);
result.pcRel = bitFieldExtract(r0, true, 1, 1);
result.isExtern = false;
result.value = r1;
result.symbol = 0;
} else {
result.offset = r0;
result.scattered = false;
result.type = (RelocationInfoType)
bitFieldExtract(r1, isBigEndian, 28, 4);
result.length = bitFieldExtract(r1, isBigEndian, 25, 2);
result.pcRel = bitFieldExtract(r1, isBigEndian, 24, 1);
result.isExtern = bitFieldExtract(r1, isBigEndian, 27, 1);
result.value = 0;
result.symbol = bitFieldExtract(r1, isBigEndian, 0, 24);
}
return result;
}
inline llvm::MachO::any_relocation_info
packRelocation(const Relocation &r, bool swap, bool isBigEndian) {
uint32_t r0 = 0;
uint32_t r1 = 0;
if (r.scattered) {
r1 = r.value;
bitFieldSet(r0, true, r.offset, 8, 24);
bitFieldSet(r0, true, r.type, 4, 4);
bitFieldSet(r0, true, r.length, 2, 2);
bitFieldSet(r0, true, r.pcRel, 1, 1);
bitFieldSet(r0, true, r.scattered, 0, 1); // R_SCATTERED
} else {
r0 = r.offset;
bitFieldSet(r1, isBigEndian, r.type, 28, 4);
bitFieldSet(r1, isBigEndian, r.isExtern, 27, 1);
bitFieldSet(r1, isBigEndian, r.length, 25, 2);
bitFieldSet(r1, isBigEndian, r.pcRel, 24, 1);
bitFieldSet(r1, isBigEndian, r.symbol, 0, 24);
}
llvm::MachO::any_relocation_info result;
result.r_word0 = swap ? getSwappedBytes(r0) : r0;
result.r_word1 = swap ? getSwappedBytes(r1) : r1;
return result;
}
inline StringRef getString16(const char s[16]) {
// The StringRef(const char *) constructor passes the const char * to
// strlen(), so we can't use this constructor here, because if there is no
// null terminator in s, then strlen() will read past the end of the array.
return StringRef(s, strnlen(s, 16));
}
inline void setString16(StringRef str, char s[16]) {
memset(s, 0, 16);
memcpy(s, str.begin(), (str.size() > 16) ? 16: str.size());
}
// Implemented in normalizedToAtoms() and used by normalizedFromAtoms() so
// that the same table can be used to map mach-o sections to and from
// DefinedAtom::ContentType.
void relocatableSectionInfoForContentType(DefinedAtom::ContentType atomType,
StringRef &segmentName,
StringRef §ionName,
SectionType §ionType,
SectionAttr §ionAttrs,
bool &relocsToDefinedCanBeImplicit);
} // namespace normalized
} // namespace mach_o
} // namespace lld
#endif // LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
|