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 §ionName, 170 SectionType §ionType, 171 SectionAttr §ionAttrs, 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