1 //===- lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h ------------===//
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #ifndef LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
11 #define LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
13 #include "MachONormalizedFile.h"
14 #include "lld/Core/Error.h"
15 #include "lld/Core/LLVM.h"
16 #include "llvm/ADT/StringRef.h"
17 #include "llvm/Support/Casting.h"
18 #include "llvm/Support/Endian.h"
19 #include "llvm/Support/ErrorHandling.h"
20 #include "llvm/Support/Host.h"
21 #include "llvm/Support/LEB128.h"
22 #include "llvm/Support/MachO.h"
23 #include <system_error>
27 namespace normalized {
31 ByteBuffer() : _ostream(_bytes) { }
33 void append_byte(uint8_t b) {
36 void append_uleb128(uint64_t value) {
37 llvm::encodeULEB128(value, _ostream);
39 void append_uleb128Fixed(uint64_t value, unsigned byteCount) {
40 unsigned min = llvm::getULEB128Size(value);
41 assert(min <= byteCount);
42 unsigned pad = byteCount - min;
43 llvm::encodeULEB128(value, _ostream, pad);
45 void append_sleb128(int64_t value) {
46 llvm::encodeSLEB128(value, _ostream);
48 void append_string(StringRef str) {
52 void align(unsigned alignment) {
53 while ( (_ostream.tell() % alignment) != 0 )
57 return _ostream.tell();
59 const uint8_t *bytes() {
60 return reinterpret_cast<const uint8_t*>(_ostream.str().data());
64 SmallVector<char, 128> _bytes;
65 // Stream ivar must be after SmallVector ivar to construct properly.
66 llvm::raw_svector_ostream _ostream;
69 using namespace llvm::support::endian;
70 using llvm::sys::getSwappedBytes;
73 static inline uint16_t read16(const T *loc, bool isBig) {
74 assert((uint64_t)loc % alignof(T) == 0 && "invalid pointer alignment");
75 return isBig ? read16be(loc) : read16le(loc);
79 static inline uint32_t read32(const T *loc, bool isBig) {
80 assert((uint64_t)loc % alignof(T) == 0 && "invalid pointer alignment");
81 return isBig ? read32be(loc) : read32le(loc);
85 static inline uint64_t read64(const T *loc, bool isBig) {
86 assert((uint64_t)loc % alignof(T) == 0 && "invalid pointer alignment");
87 return isBig ? read64be(loc) : read64le(loc);
90 inline void write16(uint8_t *loc, uint16_t value, bool isBig) {
92 write16be(loc, value);
94 write16le(loc, value);
97 inline void write32(uint8_t *loc, uint32_t value, bool isBig) {
99 write32be(loc, value);
101 write32le(loc, value);
104 inline void write64(uint8_t *loc, uint64_t value, bool isBig) {
106 write64be(loc, value);
108 write64le(loc, value);
112 bitFieldExtract(uint32_t value, bool isBigEndianBigField, uint8_t firstBit,
114 const uint32_t mask = ((1<<bitCount)-1);
115 const uint8_t shift = isBigEndianBigField ? (32-firstBit-bitCount) : firstBit;
116 return (value >> shift) & mask;
120 bitFieldSet(uint32_t &bits, bool isBigEndianBigField, uint32_t newBits,
121 uint8_t firstBit, uint8_t bitCount) {
122 const uint32_t mask = ((1<<bitCount)-1);
123 assert((newBits & mask) == newBits);
124 const uint8_t shift = isBigEndianBigField ? (32-firstBit-bitCount) : firstBit;
125 bits &= ~(mask << shift);
126 bits |= (newBits << shift);
129 inline Relocation unpackRelocation(const llvm::MachO::any_relocation_info &r,
131 uint32_t r0 = read32(&r.r_word0, isBigEndian);
132 uint32_t r1 = read32(&r.r_word1, isBigEndian);
135 if (r0 & llvm::MachO::R_SCATTERED) {
136 // scattered relocation record always laid out like big endian bit field
137 result.offset = bitFieldExtract(r0, true, 8, 24);
138 result.scattered = true;
139 result.type = (RelocationInfoType)
140 bitFieldExtract(r0, true, 4, 4);
141 result.length = bitFieldExtract(r0, true, 2, 2);
142 result.pcRel = bitFieldExtract(r0, true, 1, 1);
143 result.isExtern = false;
148 result.scattered = false;
149 result.type = (RelocationInfoType)
150 bitFieldExtract(r1, isBigEndian, 28, 4);
151 result.length = bitFieldExtract(r1, isBigEndian, 25, 2);
152 result.pcRel = bitFieldExtract(r1, isBigEndian, 24, 1);
153 result.isExtern = bitFieldExtract(r1, isBigEndian, 27, 1);
155 result.symbol = bitFieldExtract(r1, isBigEndian, 0, 24);
161 inline llvm::MachO::any_relocation_info
162 packRelocation(const Relocation &r, bool swap, bool isBigEndian) {
168 bitFieldSet(r0, true, r.offset, 8, 24);
169 bitFieldSet(r0, true, r.type, 4, 4);
170 bitFieldSet(r0, true, r.length, 2, 2);
171 bitFieldSet(r0, true, r.pcRel, 1, 1);
172 bitFieldSet(r0, true, r.scattered, 0, 1); // R_SCATTERED
175 bitFieldSet(r1, isBigEndian, r.type, 28, 4);
176 bitFieldSet(r1, isBigEndian, r.isExtern, 27, 1);
177 bitFieldSet(r1, isBigEndian, r.length, 25, 2);
178 bitFieldSet(r1, isBigEndian, r.pcRel, 24, 1);
179 bitFieldSet(r1, isBigEndian, r.symbol, 0, 24);
182 llvm::MachO::any_relocation_info result;
183 result.r_word0 = swap ? getSwappedBytes(r0) : r0;
184 result.r_word1 = swap ? getSwappedBytes(r1) : r1;
188 inline StringRef getString16(const char s[16]) {
191 return x.substr(0, 16);
196 inline void setString16(StringRef str, char s[16]) {
198 memcpy(s, str.begin(), (str.size() > 16) ? 16: str.size());
201 // Implemented in normalizedToAtoms() and used by normalizedFromAtoms() so
202 // that the same table can be used to map mach-o sections to and from
203 // DefinedAtom::ContentType.
204 void relocatableSectionInfoForContentType(DefinedAtom::ContentType atomType,
205 StringRef &segmentName,
206 StringRef §ionName,
207 SectionType §ionType,
208 SectionAttr §ionAttrs,
209 bool &relocsToDefinedCanBeImplicit);
211 } // namespace normalized
212 } // namespace mach_o
215 #endif // LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H