blob: edaae1a114f2169384ac1e6755c632360b5f0827 [file] [log] [blame]
Nick Kledzike34182f2013-11-06 21:36:55 +00001//===- 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"
Nick Kledzike34182f2013-11-06 21:36:55 +000012#include "lld/Core/Error.h"
13#include "lld/Core/LLVM.h"
Nick Kledzike34182f2013-11-06 21:36:55 +000014#include "llvm/ADT/StringRef.h"
15#include "llvm/Support/Casting.h"
Tim Northover40d3ad32014-10-27 22:48:35 +000016#include "llvm/Support/Endian.h"
Nick Kledzike34182f2013-11-06 21:36:55 +000017#include "llvm/Support/ErrorHandling.h"
18#include "llvm/Support/Host.h"
19#include "llvm/Support/MachO.h"
Rafael Espindola54427cc2014-06-12 17:15:58 +000020#include <system_error>
Nick Kledzike34182f2013-11-06 21:36:55 +000021
Rui Ueyama014192db2013-11-15 03:09:26 +000022#ifndef LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
23#define LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
Nick Kledzike34182f2013-11-06 21:36:55 +000024
25namespace lld {
26namespace mach_o {
27namespace normalized {
28
Artyom Skrobov9b3f6472014-06-14 12:14:25 +000029using llvm::sys::getSwappedBytes;
Nick Kledzike34182f2013-11-06 21:36:55 +000030
Tim Northover40d3ad32014-10-27 22:48:35 +000031 using llvm::support::ubig16_t;
32 using llvm::support::ubig32_t;
33 using llvm::support::ubig64_t;
34
35 using llvm::support::ulittle16_t;
36 using llvm::support::ulittle32_t;
37 using llvm::support::ulittle64_t;
38
39template<typename T>
40static inline uint16_t read16(const T *loc, bool isBig) {
41 assert((uint64_t)loc % llvm::alignOf<T>() == 0 &&
42 "invalid pointer alignment");
43 return isBig ? *(ubig16_t *)loc : *(ulittle16_t *)loc;
Nick Kledzikde0860a2014-07-02 23:52:22 +000044}
Nick Kledzike34182f2013-11-06 21:36:55 +000045
Tim Northover40d3ad32014-10-27 22:48:35 +000046template<typename T>
47static inline uint32_t read32(const T *loc, bool isBig) {
48 assert((uint64_t)loc % llvm::alignOf<T>() == 0 &&
49 "invalid pointer alignment");
50 return isBig ? *(ubig32_t *)loc : *(ulittle32_t *)loc;
Nick Kledzike34182f2013-11-06 21:36:55 +000051}
52
Tim Northover40d3ad32014-10-27 22:48:35 +000053template<typename T>
54static inline uint64_t read64(const T *loc, bool isBig) {
55 assert((uint64_t)loc % llvm::alignOf<T>() == 0 &&
56 "invalid pointer alignment");
57 return isBig ? *(ubig64_t *)loc : *(ulittle64_t *)loc;
Nick Kledzike34182f2013-11-06 21:36:55 +000058}
59
Tim Northover40d3ad32014-10-27 22:48:35 +000060inline void write16(uint8_t *loc, uint16_t value, bool isBig) {
61 if (isBig)
62 *(ubig16_t *)loc = value;
63 else
64 *(ulittle16_t *)loc = value;
Nick Kledzik2458bec2014-07-16 19:49:02 +000065}
Nick Kledzike34182f2013-11-06 21:36:55 +000066
Tim Northover40d3ad32014-10-27 22:48:35 +000067inline void write32(uint8_t *loc, uint32_t value, bool isBig) {
68 if (isBig)
69 *(ubig32_t *)loc = value;
70 else
71 *(ulittle32_t *)loc = value;
Nick Kledzik2458bec2014-07-16 19:49:02 +000072}
73
Tim Northover40d3ad32014-10-27 22:48:35 +000074inline void write64(uint8_t *loc, uint64_t value, bool isBig) {
75 if (isBig)
76 *(ubig64_t *)loc = value;
77 else
78 *(ulittle64_t *)loc = value;
Nick Kledzik2458bec2014-07-16 19:49:02 +000079}
Nick Kledzike34182f2013-11-06 21:36:55 +000080
Shankar Easwaran3d8de472014-01-27 03:09:26 +000081inline uint32_t
82bitFieldExtract(uint32_t value, bool isBigEndianBigField, uint8_t firstBit,
Nick Kledzike34182f2013-11-06 21:36:55 +000083 uint8_t bitCount) {
Shankar Easwaran3d8de472014-01-27 03:09:26 +000084 const uint32_t mask = ((1<<bitCount)-1);
Nick Kledzike34182f2013-11-06 21:36:55 +000085 const uint8_t shift = isBigEndianBigField ? (32-firstBit-bitCount) : firstBit;
86 return (value >> shift) & mask;
87}
88
Shankar Easwaran3d8de472014-01-27 03:09:26 +000089inline void
90bitFieldSet(uint32_t &bits, bool isBigEndianBigField, uint32_t newBits,
Nick Kledzike34182f2013-11-06 21:36:55 +000091 uint8_t firstBit, uint8_t bitCount) {
Shankar Easwaran3d8de472014-01-27 03:09:26 +000092 const uint32_t mask = ((1<<bitCount)-1);
Nick Kledzike34182f2013-11-06 21:36:55 +000093 assert((newBits & mask) == newBits);
94 const uint8_t shift = isBigEndianBigField ? (32-firstBit-bitCount) : firstBit;
95 bits &= ~(mask << shift);
96 bits |= (newBits << shift);
97}
98
Tim Northover40d3ad32014-10-27 22:48:35 +000099inline Relocation unpackRelocation(const llvm::MachO::any_relocation_info &r,
100 bool isBigEndian) {
101 uint32_t r0 = read32(&r.r_word0, isBigEndian);
102 uint32_t r1 = read32(&r.r_word1, isBigEndian);
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000103
Nick Kledzike34182f2013-11-06 21:36:55 +0000104 Relocation result;
105 if (r0 & llvm::MachO::R_SCATTERED) {
106 // scattered relocation record always laid out like big endian bit field
107 result.offset = bitFieldExtract(r0, true, 8, 24);
108 result.scattered = true;
109 result.type = (RelocationInfoType)
110 bitFieldExtract(r0, true, 4, 4);
111 result.length = bitFieldExtract(r0, true, 2, 2);
112 result.pcRel = bitFieldExtract(r0, true, 1, 1);
113 result.isExtern = false;
114 result.value = r1;
115 result.symbol = 0;
116 } else {
117 result.offset = r0;
118 result.scattered = false;
119 result.type = (RelocationInfoType)
120 bitFieldExtract(r1, isBigEndian, 28, 4);
121 result.length = bitFieldExtract(r1, isBigEndian, 25, 2);
122 result.pcRel = bitFieldExtract(r1, isBigEndian, 24, 1);
123 result.isExtern = bitFieldExtract(r1, isBigEndian, 27, 1);
124 result.value = 0;
125 result.symbol = bitFieldExtract(r1, isBigEndian, 0, 24);
126 }
127 return result;
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000128}
Nick Kledzike34182f2013-11-06 21:36:55 +0000129
130
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000131inline llvm::MachO::any_relocation_info
Nick Kledzike34182f2013-11-06 21:36:55 +0000132packRelocation(const Relocation &r, bool swap, bool isBigEndian) {
133 uint32_t r0 = 0;
134 uint32_t r1 = 0;
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000135
Nick Kledzike34182f2013-11-06 21:36:55 +0000136 if (r.scattered) {
137 r1 = r.value;
138 bitFieldSet(r0, true, r.offset, 8, 24);
139 bitFieldSet(r0, true, r.type, 4, 4);
140 bitFieldSet(r0, true, r.length, 2, 2);
141 bitFieldSet(r0, true, r.pcRel, 1, 1);
142 bitFieldSet(r0, true, r.scattered, 0, 1); // R_SCATTERED
143 } else {
144 r0 = r.offset;
145 bitFieldSet(r1, isBigEndian, r.type, 28, 4);
146 bitFieldSet(r1, isBigEndian, r.isExtern, 27, 1);
147 bitFieldSet(r1, isBigEndian, r.length, 25, 2);
148 bitFieldSet(r1, isBigEndian, r.pcRel, 24, 1);
149 bitFieldSet(r1, isBigEndian, r.symbol, 0, 24);
150 }
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000151
Nick Kledzike34182f2013-11-06 21:36:55 +0000152 llvm::MachO::any_relocation_info result;
Artyom Skrobov9b3f6472014-06-14 12:14:25 +0000153 result.r_word0 = swap ? getSwappedBytes(r0) : r0;
154 result.r_word1 = swap ? getSwappedBytes(r1) : r1;
Nick Kledzike34182f2013-11-06 21:36:55 +0000155 return result;
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000156}
Nick Kledzike34182f2013-11-06 21:36:55 +0000157
158inline StringRef getString16(const char s[16]) {
159 StringRef x = s;
160 if ( x.size() > 16 )
161 return x.substr(0, 16);
162 else
163 return x;
164}
165
166inline void setString16(StringRef str, char s[16]) {
167 memset(s, 0, 16);
168 memcpy(s, str.begin(), (str.size() > 16) ? 16: str.size());
169}
170
Nick Kledzikec140832014-06-10 01:50:00 +0000171// Implemented in normalizedToAtoms() and used by normalizedFromAtoms() so
172// that the same table can be used to map mach-o sections to and from
173// DefinedAtom::ContentType.
174void relocatableSectionInfoForContentType(DefinedAtom::ContentType atomType,
175 StringRef &segmentName,
176 StringRef &sectionName,
177 SectionType &sectionType,
178 SectionAttr &sectionAttrs);
Nick Kledzike34182f2013-11-06 21:36:55 +0000179
180} // namespace normalized
181} // namespace mach_o
182} // namespace lld
183
Rui Ueyama014192db2013-11-15 03:09:26 +0000184#endif // LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H