blob: aeb04ef4508a78e93d41ac978fd6498ab0aa541a [file] [log] [blame]
Nick Kledzike34182f2013-11-06 21:36:55 +00001//===- lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h ------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Nick Kledzike34182f2013-11-06 21:36:55 +00006//
7//===----------------------------------------------------------------------===//
8
Pete Cooperd75b7182016-02-08 21:50:45 +00009#ifndef LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
10#define LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
Nick Kledzike34182f2013-11-06 21:36:55 +000011
12#include "MachONormalizedFile.h"
Rui Ueyama3f851702017-10-02 21:00:41 +000013#include "lld/Common/LLVM.h"
Nick Kledzike34182f2013-11-06 21:36:55 +000014#include "lld/Core/Error.h"
Nick Kledzike34182f2013-11-06 21:36:55 +000015#include "llvm/ADT/StringRef.h"
Zachary Turner264b5d92017-06-07 03:48:56 +000016#include "llvm/BinaryFormat/MachO.h"
Nick Kledzike34182f2013-11-06 21:36:55 +000017#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"
Rafael Espindola54427cc2014-06-12 17:15:58 +000022#include <system_error>
Nick Kledzike34182f2013-11-06 21:36:55 +000023
Nick Kledzike34182f2013-11-06 21:36:55 +000024namespace lld {
25namespace mach_o {
26namespace normalized {
27
Pete Cooper41f3e8e2016-02-09 01:38:13 +000028class ByteBuffer {
29public:
30 ByteBuffer() : _ostream(_bytes) { }
31
32 void append_byte(uint8_t b) {
33 _ostream << b;
34 }
35 void append_uleb128(uint64_t value) {
36 llvm::encodeULEB128(value, _ostream);
37 }
38 void append_uleb128Fixed(uint64_t value, unsigned byteCount) {
39 unsigned min = llvm::getULEB128Size(value);
40 assert(min <= byteCount);
41 unsigned pad = byteCount - min;
42 llvm::encodeULEB128(value, _ostream, pad);
43 }
44 void append_sleb128(int64_t value) {
45 llvm::encodeSLEB128(value, _ostream);
46 }
47 void append_string(StringRef str) {
48 _ostream << str;
49 append_byte(0);
50 }
51 void align(unsigned alignment) {
52 while ( (_ostream.tell() % alignment) != 0 )
53 append_byte(0);
54 }
55 size_t size() {
56 return _ostream.tell();
57 }
58 const uint8_t *bytes() {
59 return reinterpret_cast<const uint8_t*>(_ostream.str().data());
60 }
61
62private:
63 SmallVector<char, 128> _bytes;
64 // Stream ivar must be after SmallVector ivar to construct properly.
65 llvm::raw_svector_ostream _ostream;
66};
67
Rui Ueyama25b87a42015-03-02 20:31:43 +000068using namespace llvm::support::endian;
Artyom Skrobov9b3f6472014-06-14 12:14:25 +000069using llvm::sys::getSwappedBytes;
Nick Kledzike34182f2013-11-06 21:36:55 +000070
Tim Northover40d3ad32014-10-27 22:48:35 +000071template<typename T>
72static inline uint16_t read16(const T *loc, bool isBig) {
Benjamin Kramer3ad3f502016-10-20 15:30:02 +000073 assert((uint64_t)loc % alignof(T) == 0 && "invalid pointer alignment");
Rui Ueyamae088a0f2015-02-27 04:21:40 +000074 return isBig ? read16be(loc) : read16le(loc);
Nick Kledzikde0860a2014-07-02 23:52:22 +000075}
Nick Kledzike34182f2013-11-06 21:36:55 +000076
Tim Northover40d3ad32014-10-27 22:48:35 +000077template<typename T>
78static inline uint32_t read32(const T *loc, bool isBig) {
Benjamin Kramer3ad3f502016-10-20 15:30:02 +000079 assert((uint64_t)loc % alignof(T) == 0 && "invalid pointer alignment");
Rui Ueyamae088a0f2015-02-27 04:21:40 +000080 return isBig ? read32be(loc) : read32le(loc);
Nick Kledzike34182f2013-11-06 21:36:55 +000081}
82
Tim Northover40d3ad32014-10-27 22:48:35 +000083template<typename T>
84static inline uint64_t read64(const T *loc, bool isBig) {
Benjamin Kramer3ad3f502016-10-20 15:30:02 +000085 assert((uint64_t)loc % alignof(T) == 0 && "invalid pointer alignment");
Rui Ueyamae088a0f2015-02-27 04:21:40 +000086 return isBig ? read64be(loc) : read64le(loc);
Nick Kledzike34182f2013-11-06 21:36:55 +000087}
88
Tim Northover40d3ad32014-10-27 22:48:35 +000089inline void write16(uint8_t *loc, uint16_t value, bool isBig) {
90 if (isBig)
Rui Ueyamae088a0f2015-02-27 04:21:40 +000091 write16be(loc, value);
Tim Northover40d3ad32014-10-27 22:48:35 +000092 else
Rui Ueyamae088a0f2015-02-27 04:21:40 +000093 write16le(loc, value);
Nick Kledzik2458bec2014-07-16 19:49:02 +000094}
Nick Kledzike34182f2013-11-06 21:36:55 +000095
Tim Northover40d3ad32014-10-27 22:48:35 +000096inline void write32(uint8_t *loc, uint32_t value, bool isBig) {
97 if (isBig)
Rui Ueyamae088a0f2015-02-27 04:21:40 +000098 write32be(loc, value);
Tim Northover40d3ad32014-10-27 22:48:35 +000099 else
Rui Ueyamae088a0f2015-02-27 04:21:40 +0000100 write32le(loc, value);
Nick Kledzik2458bec2014-07-16 19:49:02 +0000101}
102
Tim Northover40d3ad32014-10-27 22:48:35 +0000103inline void write64(uint8_t *loc, uint64_t value, bool isBig) {
104 if (isBig)
Rui Ueyamae088a0f2015-02-27 04:21:40 +0000105 write64be(loc, value);
Tim Northover40d3ad32014-10-27 22:48:35 +0000106 else
Rui Ueyamae088a0f2015-02-27 04:21:40 +0000107 write64le(loc, value);
Nick Kledzik2458bec2014-07-16 19:49:02 +0000108}
Nick Kledzike34182f2013-11-06 21:36:55 +0000109
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000110inline uint32_t
111bitFieldExtract(uint32_t value, bool isBigEndianBigField, uint8_t firstBit,
Nick Kledzike34182f2013-11-06 21:36:55 +0000112 uint8_t bitCount) {
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000113 const uint32_t mask = ((1<<bitCount)-1);
Nick Kledzike34182f2013-11-06 21:36:55 +0000114 const uint8_t shift = isBigEndianBigField ? (32-firstBit-bitCount) : firstBit;
115 return (value >> shift) & mask;
116}
117
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000118inline void
119bitFieldSet(uint32_t &bits, bool isBigEndianBigField, uint32_t newBits,
Nick Kledzike34182f2013-11-06 21:36:55 +0000120 uint8_t firstBit, uint8_t bitCount) {
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000121 const uint32_t mask = ((1<<bitCount)-1);
Nick Kledzike34182f2013-11-06 21:36:55 +0000122 assert((newBits & mask) == newBits);
123 const uint8_t shift = isBigEndianBigField ? (32-firstBit-bitCount) : firstBit;
124 bits &= ~(mask << shift);
125 bits |= (newBits << shift);
126}
127
Tim Northover40d3ad32014-10-27 22:48:35 +0000128inline Relocation unpackRelocation(const llvm::MachO::any_relocation_info &r,
129 bool isBigEndian) {
130 uint32_t r0 = read32(&r.r_word0, isBigEndian);
131 uint32_t r1 = read32(&r.r_word1, isBigEndian);
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000132
Nick Kledzike34182f2013-11-06 21:36:55 +0000133 Relocation result;
134 if (r0 & llvm::MachO::R_SCATTERED) {
135 // scattered relocation record always laid out like big endian bit field
136 result.offset = bitFieldExtract(r0, true, 8, 24);
137 result.scattered = true;
138 result.type = (RelocationInfoType)
139 bitFieldExtract(r0, true, 4, 4);
140 result.length = bitFieldExtract(r0, true, 2, 2);
141 result.pcRel = bitFieldExtract(r0, true, 1, 1);
142 result.isExtern = false;
143 result.value = r1;
144 result.symbol = 0;
145 } else {
146 result.offset = r0;
147 result.scattered = false;
148 result.type = (RelocationInfoType)
149 bitFieldExtract(r1, isBigEndian, 28, 4);
150 result.length = bitFieldExtract(r1, isBigEndian, 25, 2);
151 result.pcRel = bitFieldExtract(r1, isBigEndian, 24, 1);
152 result.isExtern = bitFieldExtract(r1, isBigEndian, 27, 1);
153 result.value = 0;
154 result.symbol = bitFieldExtract(r1, isBigEndian, 0, 24);
155 }
156 return result;
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000157}
Nick Kledzike34182f2013-11-06 21:36:55 +0000158
159
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000160inline llvm::MachO::any_relocation_info
Nick Kledzike34182f2013-11-06 21:36:55 +0000161packRelocation(const Relocation &r, bool swap, bool isBigEndian) {
162 uint32_t r0 = 0;
163 uint32_t r1 = 0;
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000164
Nick Kledzike34182f2013-11-06 21:36:55 +0000165 if (r.scattered) {
166 r1 = r.value;
167 bitFieldSet(r0, true, r.offset, 8, 24);
168 bitFieldSet(r0, true, r.type, 4, 4);
169 bitFieldSet(r0, true, r.length, 2, 2);
170 bitFieldSet(r0, true, r.pcRel, 1, 1);
171 bitFieldSet(r0, true, r.scattered, 0, 1); // R_SCATTERED
172 } else {
173 r0 = r.offset;
174 bitFieldSet(r1, isBigEndian, r.type, 28, 4);
175 bitFieldSet(r1, isBigEndian, r.isExtern, 27, 1);
176 bitFieldSet(r1, isBigEndian, r.length, 25, 2);
177 bitFieldSet(r1, isBigEndian, r.pcRel, 24, 1);
178 bitFieldSet(r1, isBigEndian, r.symbol, 0, 24);
179 }
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000180
Nick Kledzike34182f2013-11-06 21:36:55 +0000181 llvm::MachO::any_relocation_info result;
Artyom Skrobov9b3f6472014-06-14 12:14:25 +0000182 result.r_word0 = swap ? getSwappedBytes(r0) : r0;
183 result.r_word1 = swap ? getSwappedBytes(r1) : r1;
Nick Kledzike34182f2013-11-06 21:36:55 +0000184 return result;
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000185}
Nick Kledzike34182f2013-11-06 21:36:55 +0000186
Tom Stellarda6749132018-09-07 15:51:52 +0000187inline StringRef getString16(const char s[16]) {
Tom Stellard493f3ba2018-09-07 15:42:01 +0000188 // The StringRef(const char *) constructor passes the const char * to
189 // strlen(), so we can't use this constructor here, because if there is no
190 // null terminator in s, then strlen() will read past the end of the array.
191 return StringRef(s, strnlen(s, 16));
Nick Kledzike34182f2013-11-06 21:36:55 +0000192}
193
194inline void setString16(StringRef str, char s[16]) {
195 memset(s, 0, 16);
196 memcpy(s, str.begin(), (str.size() > 16) ? 16: str.size());
197}
198
Nick Kledzikec140832014-06-10 01:50:00 +0000199// Implemented in normalizedToAtoms() and used by normalizedFromAtoms() so
200// that the same table can be used to map mach-o sections to and from
201// DefinedAtom::ContentType.
202void relocatableSectionInfoForContentType(DefinedAtom::ContentType atomType,
203 StringRef &segmentName,
204 StringRef &sectionName,
205 SectionType &sectionType,
Pete Cooperac039792016-01-07 21:07:26 +0000206 SectionAttr &sectionAttrs,
207 bool &relocsToDefinedCanBeImplicit);
Nick Kledzike34182f2013-11-06 21:36:55 +0000208
209} // namespace normalized
210} // namespace mach_o
211} // namespace lld
212
Rui Ueyama014192db2013-11-15 03:09:26 +0000213#endif // LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H