blob: 86823efa33c94c0798ee82713a9d4a55b06c29e1 [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
Pete Cooperd75b7182016-02-08 21:50:45 +000010#ifndef LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
11#define LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
Nick Kledzike34182f2013-11-06 21:36:55 +000012
13#include "MachONormalizedFile.h"
Nick Kledzike34182f2013-11-06 21:36:55 +000014#include "lld/Core/Error.h"
15#include "lld/Core/LLVM.h"
Nick Kledzike34182f2013-11-06 21:36:55 +000016#include "llvm/ADT/StringRef.h"
17#include "llvm/Support/Casting.h"
Rui Ueyama25b87a42015-03-02 20:31:43 +000018#include "llvm/Support/Endian.h"
Nick Kledzike34182f2013-11-06 21:36:55 +000019#include "llvm/Support/ErrorHandling.h"
20#include "llvm/Support/Host.h"
Pete Cooper41f3e8e2016-02-09 01:38:13 +000021#include "llvm/Support/LEB128.h"
Nick Kledzike34182f2013-11-06 21:36:55 +000022#include "llvm/Support/MachO.h"
Rafael Espindola54427cc2014-06-12 17:15:58 +000023#include <system_error>
Nick Kledzike34182f2013-11-06 21:36:55 +000024
Nick Kledzike34182f2013-11-06 21:36:55 +000025namespace lld {
26namespace mach_o {
27namespace normalized {
28
Pete Cooper41f3e8e2016-02-09 01:38:13 +000029class ByteBuffer {
30public:
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
63private:
64 SmallVector<char, 128> _bytes;
65 // Stream ivar must be after SmallVector ivar to construct properly.
66 llvm::raw_svector_ostream _ostream;
67};
68
Rui Ueyama25b87a42015-03-02 20:31:43 +000069using namespace llvm::support::endian;
Artyom Skrobov9b3f6472014-06-14 12:14:25 +000070using llvm::sys::getSwappedBytes;
Nick Kledzike34182f2013-11-06 21:36:55 +000071
Tim Northover40d3ad32014-10-27 22:48:35 +000072template<typename T>
73static inline uint16_t read16(const T *loc, bool isBig) {
74 assert((uint64_t)loc % llvm::alignOf<T>() == 0 &&
75 "invalid pointer alignment");
Rui Ueyamae088a0f2015-02-27 04:21:40 +000076 return isBig ? read16be(loc) : read16le(loc);
Nick Kledzikde0860a2014-07-02 23:52:22 +000077}
Nick Kledzike34182f2013-11-06 21:36:55 +000078
Tim Northover40d3ad32014-10-27 22:48:35 +000079template<typename T>
80static inline uint32_t read32(const T *loc, bool isBig) {
81 assert((uint64_t)loc % llvm::alignOf<T>() == 0 &&
82 "invalid pointer alignment");
Rui Ueyamae088a0f2015-02-27 04:21:40 +000083 return isBig ? read32be(loc) : read32le(loc);
Nick Kledzike34182f2013-11-06 21:36:55 +000084}
85
Tim Northover40d3ad32014-10-27 22:48:35 +000086template<typename T>
87static inline uint64_t read64(const T *loc, bool isBig) {
88 assert((uint64_t)loc % llvm::alignOf<T>() == 0 &&
89 "invalid pointer alignment");
Rui Ueyamae088a0f2015-02-27 04:21:40 +000090 return isBig ? read64be(loc) : read64le(loc);
Nick Kledzike34182f2013-11-06 21:36:55 +000091}
92
Tim Northover40d3ad32014-10-27 22:48:35 +000093inline void write16(uint8_t *loc, uint16_t value, bool isBig) {
94 if (isBig)
Rui Ueyamae088a0f2015-02-27 04:21:40 +000095 write16be(loc, value);
Tim Northover40d3ad32014-10-27 22:48:35 +000096 else
Rui Ueyamae088a0f2015-02-27 04:21:40 +000097 write16le(loc, value);
Nick Kledzik2458bec2014-07-16 19:49:02 +000098}
Nick Kledzike34182f2013-11-06 21:36:55 +000099
Tim Northover40d3ad32014-10-27 22:48:35 +0000100inline void write32(uint8_t *loc, uint32_t value, bool isBig) {
101 if (isBig)
Rui Ueyamae088a0f2015-02-27 04:21:40 +0000102 write32be(loc, value);
Tim Northover40d3ad32014-10-27 22:48:35 +0000103 else
Rui Ueyamae088a0f2015-02-27 04:21:40 +0000104 write32le(loc, value);
Nick Kledzik2458bec2014-07-16 19:49:02 +0000105}
106
Tim Northover40d3ad32014-10-27 22:48:35 +0000107inline void write64(uint8_t *loc, uint64_t value, bool isBig) {
108 if (isBig)
Rui Ueyamae088a0f2015-02-27 04:21:40 +0000109 write64be(loc, value);
Tim Northover40d3ad32014-10-27 22:48:35 +0000110 else
Rui Ueyamae088a0f2015-02-27 04:21:40 +0000111 write64le(loc, value);
Nick Kledzik2458bec2014-07-16 19:49:02 +0000112}
Nick Kledzike34182f2013-11-06 21:36:55 +0000113
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000114inline uint32_t
115bitFieldExtract(uint32_t value, bool isBigEndianBigField, uint8_t firstBit,
Nick Kledzike34182f2013-11-06 21:36:55 +0000116 uint8_t bitCount) {
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000117 const uint32_t mask = ((1<<bitCount)-1);
Nick Kledzike34182f2013-11-06 21:36:55 +0000118 const uint8_t shift = isBigEndianBigField ? (32-firstBit-bitCount) : firstBit;
119 return (value >> shift) & mask;
120}
121
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000122inline void
123bitFieldSet(uint32_t &bits, bool isBigEndianBigField, uint32_t newBits,
Nick Kledzike34182f2013-11-06 21:36:55 +0000124 uint8_t firstBit, uint8_t bitCount) {
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000125 const uint32_t mask = ((1<<bitCount)-1);
Nick Kledzike34182f2013-11-06 21:36:55 +0000126 assert((newBits & mask) == newBits);
127 const uint8_t shift = isBigEndianBigField ? (32-firstBit-bitCount) : firstBit;
128 bits &= ~(mask << shift);
129 bits |= (newBits << shift);
130}
131
Tim Northover40d3ad32014-10-27 22:48:35 +0000132inline 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);
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000136
Nick Kledzike34182f2013-11-06 21:36:55 +0000137 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;
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000161}
Nick Kledzike34182f2013-11-06 21:36:55 +0000162
163
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000164inline llvm::MachO::any_relocation_info
Nick Kledzike34182f2013-11-06 21:36:55 +0000165packRelocation(const Relocation &r, bool swap, bool isBigEndian) {
166 uint32_t r0 = 0;
167 uint32_t r1 = 0;
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000168
Nick Kledzike34182f2013-11-06 21:36:55 +0000169 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 }
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000184
Nick Kledzike34182f2013-11-06 21:36:55 +0000185 llvm::MachO::any_relocation_info result;
Artyom Skrobov9b3f6472014-06-14 12:14:25 +0000186 result.r_word0 = swap ? getSwappedBytes(r0) : r0;
187 result.r_word1 = swap ? getSwappedBytes(r1) : r1;
Nick Kledzike34182f2013-11-06 21:36:55 +0000188 return result;
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000189}
Nick Kledzike34182f2013-11-06 21:36:55 +0000190
191inline 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
199inline 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
Nick Kledzikec140832014-06-10 01:50:00 +0000204// 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.
207void relocatableSectionInfoForContentType(DefinedAtom::ContentType atomType,
208 StringRef &segmentName,
209 StringRef &sectionName,
210 SectionType &sectionType,
Pete Cooperac039792016-01-07 21:07:26 +0000211 SectionAttr &sectionAttrs,
212 bool &relocsToDefinedCanBeImplicit);
Nick Kledzike34182f2013-11-06 21:36:55 +0000213
214} // namespace normalized
215} // namespace mach_o
216} // namespace lld
217
Rui Ueyama014192db2013-11-15 03:09:26 +0000218#endif // LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H