]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h
Bring lld (release_39 branch, r279477) to contrib
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lld / lib / ReaderWriter / MachO / MachONormalizedFileBinaryUtils.h
1 //===- lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h ------------===//
2 //
3 //                             The LLVM Linker
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #ifndef LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
11 #define LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
12
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>
24
25 namespace lld {
26 namespace mach_o {
27 namespace normalized {
28
29 class ByteBuffer {
30 public:
31   ByteBuffer() : _ostream(_bytes) { }
32
33   void append_byte(uint8_t b) {
34     _ostream << b;
35   }
36   void append_uleb128(uint64_t value) {
37     llvm::encodeULEB128(value, _ostream);
38   }
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);
44   }
45   void append_sleb128(int64_t value) {
46     llvm::encodeSLEB128(value, _ostream);
47   }
48   void append_string(StringRef str) {
49     _ostream << str;
50     append_byte(0);
51   }
52   void align(unsigned alignment) {
53     while ( (_ostream.tell() % alignment) != 0 )
54       append_byte(0);
55   }
56   size_t size() {
57     return _ostream.tell();
58   }
59   const uint8_t *bytes() {
60     return reinterpret_cast<const uint8_t*>(_ostream.str().data());
61   }
62
63 private:
64   SmallVector<char, 128>        _bytes;
65   // Stream ivar must be after SmallVector ivar to construct properly.
66   llvm::raw_svector_ostream     _ostream;
67 };
68
69 using namespace llvm::support::endian;
70 using llvm::sys::getSwappedBytes;
71
72 template<typename T>
73 static inline uint16_t read16(const T *loc, bool isBig) {
74   assert((uint64_t)loc % llvm::alignOf<T>() == 0 &&
75          "invalid pointer alignment");
76   return isBig ? read16be(loc) : read16le(loc);
77 }
78
79 template<typename T>
80 static inline uint32_t read32(const T *loc, bool isBig) {
81   assert((uint64_t)loc % llvm::alignOf<T>() == 0 &&
82          "invalid pointer alignment");
83   return isBig ? read32be(loc) : read32le(loc);
84 }
85
86 template<typename T>
87 static inline uint64_t read64(const T *loc, bool isBig) {
88   assert((uint64_t)loc % llvm::alignOf<T>() == 0 &&
89          "invalid pointer alignment");
90   return isBig ? read64be(loc) : read64le(loc);
91 }
92
93 inline void write16(uint8_t *loc, uint16_t value, bool isBig) {
94   if (isBig)
95     write16be(loc, value);
96   else
97     write16le(loc, value);
98 }
99
100 inline void write32(uint8_t *loc, uint32_t value, bool isBig) {
101   if (isBig)
102     write32be(loc, value);
103   else
104     write32le(loc, value);
105 }
106
107 inline void write64(uint8_t *loc, uint64_t value, bool isBig) {
108   if (isBig)
109     write64be(loc, value);
110   else
111     write64le(loc, value);
112 }
113
114 inline uint32_t
115 bitFieldExtract(uint32_t value, bool isBigEndianBigField, uint8_t firstBit,
116                                                           uint8_t bitCount) {
117   const uint32_t mask = ((1<<bitCount)-1);
118   const uint8_t shift = isBigEndianBigField ? (32-firstBit-bitCount) : firstBit;
119   return (value >> shift) & mask;
120 }
121
122 inline void
123 bitFieldSet(uint32_t &bits, bool isBigEndianBigField, uint32_t newBits,
124                             uint8_t firstBit, uint8_t bitCount) {
125   const uint32_t mask = ((1<<bitCount)-1);
126   assert((newBits & mask) == newBits);
127   const uint8_t shift = isBigEndianBigField ? (32-firstBit-bitCount) : firstBit;
128   bits &= ~(mask << shift);
129   bits |= (newBits << shift);
130 }
131
132 inline Relocation unpackRelocation(const llvm::MachO::any_relocation_info &r,
133                                    bool isBigEndian) {
134   uint32_t r0 = read32(&r.r_word0, isBigEndian);
135   uint32_t r1 = read32(&r.r_word1, isBigEndian);
136
137   Relocation result;
138   if (r0 & llvm::MachO::R_SCATTERED) {
139     // scattered relocation record always laid out like big endian bit field
140     result.offset     = bitFieldExtract(r0, true, 8, 24);
141     result.scattered  = true;
142     result.type       = (RelocationInfoType)
143                         bitFieldExtract(r0, true, 4, 4);
144     result.length     = bitFieldExtract(r0, true, 2, 2);
145     result.pcRel      = bitFieldExtract(r0, true, 1, 1);
146     result.isExtern   = false;
147     result.value      = r1;
148     result.symbol     = 0;
149   } else {
150     result.offset     = r0;
151     result.scattered  = false;
152     result.type       = (RelocationInfoType)
153                         bitFieldExtract(r1, isBigEndian, 28, 4);
154     result.length     = bitFieldExtract(r1, isBigEndian, 25, 2);
155     result.pcRel      = bitFieldExtract(r1, isBigEndian, 24, 1);
156     result.isExtern   = bitFieldExtract(r1, isBigEndian, 27, 1);
157     result.value      = 0;
158     result.symbol     = bitFieldExtract(r1, isBigEndian, 0, 24);
159   }
160   return result;
161 }
162
163
164 inline llvm::MachO::any_relocation_info
165 packRelocation(const Relocation &r, bool swap, bool isBigEndian) {
166   uint32_t r0 = 0;
167   uint32_t r1 = 0;
168
169   if (r.scattered) {
170     r1 = r.value;
171     bitFieldSet(r0, true, r.offset,    8, 24);
172     bitFieldSet(r0, true, r.type,      4, 4);
173     bitFieldSet(r0, true, r.length,    2, 2);
174     bitFieldSet(r0, true, r.pcRel,     1, 1);
175     bitFieldSet(r0, true, r.scattered, 0, 1); // R_SCATTERED
176   } else {
177     r0 = r.offset;
178     bitFieldSet(r1, isBigEndian, r.type,     28, 4);
179     bitFieldSet(r1, isBigEndian, r.isExtern, 27, 1);
180     bitFieldSet(r1, isBigEndian, r.length,   25, 2);
181     bitFieldSet(r1, isBigEndian, r.pcRel,    24, 1);
182     bitFieldSet(r1, isBigEndian, r.symbol,   0,  24);
183   }
184
185   llvm::MachO::any_relocation_info result;
186   result.r_word0 = swap ? getSwappedBytes(r0) : r0;
187   result.r_word1 = swap ? getSwappedBytes(r1) : r1;
188   return result;
189 }
190
191 inline StringRef getString16(const char s[16]) {
192   StringRef x = s;
193   if ( x.size() > 16 )
194     return x.substr(0, 16);
195   else
196     return x;
197 }
198
199 inline void setString16(StringRef str, char s[16]) {
200   memset(s, 0, 16);
201   memcpy(s, str.begin(), (str.size() > 16) ? 16: str.size());
202 }
203
204 // Implemented in normalizedToAtoms() and used by normalizedFromAtoms() so
205 // that the same table can be used to map mach-o sections to and from
206 // DefinedAtom::ContentType.
207 void relocatableSectionInfoForContentType(DefinedAtom::ContentType atomType,
208                                           StringRef &segmentName,
209                                           StringRef &sectionName,
210                                           SectionType &sectionType,
211                                           SectionAttr &sectionAttrs,
212                                           bool &relocsToDefinedCanBeImplicit);
213
214 } // namespace normalized
215 } // namespace mach_o
216 } // namespace lld
217
218 #endif // LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H