MachONormalizedFileBinaryUtils.h revision 293846
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
11#include "MachONormalizedFile.h"
12#include "lld/Core/Error.h"
13#include "lld/Core/LLVM.h"
14#include "llvm/ADT/StringRef.h"
15#include "llvm/Support/Casting.h"
16#include "llvm/Support/Endian.h"
17#include "llvm/Support/ErrorHandling.h"
18#include "llvm/Support/Host.h"
19#include "llvm/Support/MachO.h"
20#include <system_error>
21
22#ifndef LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
23#define LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
24
25namespace lld {
26namespace mach_o {
27namespace normalized {
28
29using namespace llvm::support::endian;
30using llvm::sys::getSwappedBytes;
31
32template<typename T>
33static inline uint16_t read16(const T *loc, bool isBig) {
34  assert((uint64_t)loc % llvm::alignOf<T>() == 0 &&
35         "invalid pointer alignment");
36  return isBig ? read16be(loc) : read16le(loc);
37}
38
39template<typename T>
40static inline uint32_t read32(const T *loc, bool isBig) {
41  assert((uint64_t)loc % llvm::alignOf<T>() == 0 &&
42         "invalid pointer alignment");
43  return isBig ? read32be(loc) : read32le(loc);
44}
45
46template<typename T>
47static inline uint64_t read64(const T *loc, bool isBig) {
48  assert((uint64_t)loc % llvm::alignOf<T>() == 0 &&
49         "invalid pointer alignment");
50  return isBig ? read64be(loc) : read64le(loc);
51}
52
53inline void write16(uint8_t *loc, uint16_t value, bool isBig) {
54  if (isBig)
55    write16be(loc, value);
56  else
57    write16le(loc, value);
58}
59
60inline void write32(uint8_t *loc, uint32_t value, bool isBig) {
61  if (isBig)
62    write32be(loc, value);
63  else
64    write32le(loc, value);
65}
66
67inline void write64(uint8_t *loc, uint64_t value, bool isBig) {
68  if (isBig)
69    write64be(loc, value);
70  else
71    write64le(loc, value);
72}
73
74inline uint32_t
75bitFieldExtract(uint32_t value, bool isBigEndianBigField, uint8_t firstBit,
76                                                          uint8_t bitCount) {
77  const uint32_t mask = ((1<<bitCount)-1);
78  const uint8_t shift = isBigEndianBigField ? (32-firstBit-bitCount) : firstBit;
79  return (value >> shift) & mask;
80}
81
82inline void
83bitFieldSet(uint32_t &bits, bool isBigEndianBigField, uint32_t newBits,
84                            uint8_t firstBit, uint8_t bitCount) {
85  const uint32_t mask = ((1<<bitCount)-1);
86  assert((newBits & mask) == newBits);
87  const uint8_t shift = isBigEndianBigField ? (32-firstBit-bitCount) : firstBit;
88  bits &= ~(mask << shift);
89  bits |= (newBits << shift);
90}
91
92inline Relocation unpackRelocation(const llvm::MachO::any_relocation_info &r,
93                                   bool isBigEndian) {
94  uint32_t r0 = read32(&r.r_word0, isBigEndian);
95  uint32_t r1 = read32(&r.r_word1, isBigEndian);
96
97  Relocation result;
98  if (r0 & llvm::MachO::R_SCATTERED) {
99    // scattered relocation record always laid out like big endian bit field
100    result.offset     = bitFieldExtract(r0, true, 8, 24);
101    result.scattered  = true;
102    result.type       = (RelocationInfoType)
103                        bitFieldExtract(r0, true, 4, 4);
104    result.length     = bitFieldExtract(r0, true, 2, 2);
105    result.pcRel      = bitFieldExtract(r0, true, 1, 1);
106    result.isExtern   = false;
107    result.value      = r1;
108    result.symbol     = 0;
109  } else {
110    result.offset     = r0;
111    result.scattered  = false;
112    result.type       = (RelocationInfoType)
113                        bitFieldExtract(r1, isBigEndian, 28, 4);
114    result.length     = bitFieldExtract(r1, isBigEndian, 25, 2);
115    result.pcRel      = bitFieldExtract(r1, isBigEndian, 24, 1);
116    result.isExtern   = bitFieldExtract(r1, isBigEndian, 27, 1);
117    result.value      = 0;
118    result.symbol     = bitFieldExtract(r1, isBigEndian, 0, 24);
119  }
120  return result;
121}
122
123
124inline llvm::MachO::any_relocation_info
125packRelocation(const Relocation &r, bool swap, bool isBigEndian) {
126  uint32_t r0 = 0;
127  uint32_t r1 = 0;
128
129  if (r.scattered) {
130    r1 = r.value;
131    bitFieldSet(r0, true, r.offset,    8, 24);
132    bitFieldSet(r0, true, r.type,      4, 4);
133    bitFieldSet(r0, true, r.length,    2, 2);
134    bitFieldSet(r0, true, r.pcRel,     1, 1);
135    bitFieldSet(r0, true, r.scattered, 0, 1); // R_SCATTERED
136  } else {
137    r0 = r.offset;
138    bitFieldSet(r1, isBigEndian, r.type,     28, 4);
139    bitFieldSet(r1, isBigEndian, r.isExtern, 27, 1);
140    bitFieldSet(r1, isBigEndian, r.length,   25, 2);
141    bitFieldSet(r1, isBigEndian, r.pcRel,    24, 1);
142    bitFieldSet(r1, isBigEndian, r.symbol,   0,  24);
143  }
144
145  llvm::MachO::any_relocation_info result;
146  result.r_word0 = swap ? getSwappedBytes(r0) : r0;
147  result.r_word1 = swap ? getSwappedBytes(r1) : r1;
148  return result;
149}
150
151inline StringRef getString16(const char s[16]) {
152  StringRef x = s;
153  if ( x.size() > 16 )
154    return x.substr(0, 16);
155  else
156    return x;
157}
158
159inline void setString16(StringRef str, char s[16]) {
160  memset(s, 0, 16);
161  memcpy(s, str.begin(), (str.size() > 16) ? 16: str.size());
162}
163
164// Implemented in normalizedToAtoms() and used by normalizedFromAtoms() so
165// that the same table can be used to map mach-o sections to and from
166// DefinedAtom::ContentType.
167void relocatableSectionInfoForContentType(DefinedAtom::ContentType atomType,
168                                          StringRef &segmentName,
169                                          StringRef &sectionName,
170                                          SectionType &sectionType,
171                                          SectionAttr &sectionAttrs,
172                                          bool &relocsToDefinedCanBeImplicit);
173
174} // namespace normalized
175} // namespace mach_o
176} // namespace lld
177
178#endif // LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
179