1 //===- MachOReader.cpp ------------------------------------------*- C++ -*-===// 2 // 3 // 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 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "MachOReader.h" 10 #include "Object.h" 11 #include "llvm/BinaryFormat/MachO.h" 12 #include "llvm/Object/MachO.h" 13 #include "llvm/Support/Errc.h" 14 #include <memory> 15 16 using namespace llvm; 17 using namespace llvm::objcopy; 18 using namespace llvm::objcopy::macho; 19 20 void MachOReader::readHeader(Object &O) const { 21 O.Header.Magic = MachOObj.getHeader().magic; 22 O.Header.CPUType = MachOObj.getHeader().cputype; 23 O.Header.CPUSubType = MachOObj.getHeader().cpusubtype; 24 O.Header.FileType = MachOObj.getHeader().filetype; 25 O.Header.NCmds = MachOObj.getHeader().ncmds; 26 O.Header.SizeOfCmds = MachOObj.getHeader().sizeofcmds; 27 O.Header.Flags = MachOObj.getHeader().flags; 28 } 29 30 template <typename SectionType> 31 static Section constructSectionCommon(const SectionType &Sec, uint32_t Index) { 32 StringRef SegName(Sec.segname, strnlen(Sec.segname, sizeof(Sec.segname))); 33 StringRef SectName(Sec.sectname, strnlen(Sec.sectname, sizeof(Sec.sectname))); 34 Section S(SegName, SectName); 35 S.Index = Index; 36 S.Addr = Sec.addr; 37 S.Size = Sec.size; 38 S.OriginalOffset = Sec.offset; 39 S.Align = Sec.align; 40 S.RelOff = Sec.reloff; 41 S.NReloc = Sec.nreloc; 42 S.Flags = Sec.flags; 43 S.Reserved1 = Sec.reserved1; 44 S.Reserved2 = Sec.reserved2; 45 S.Reserved3 = 0; 46 return S; 47 } 48 49 Section constructSection(const MachO::section &Sec, uint32_t Index) { 50 return constructSectionCommon(Sec, Index); 51 } 52 53 Section constructSection(const MachO::section_64 &Sec, uint32_t Index) { 54 Section S = constructSectionCommon(Sec, Index); 55 S.Reserved3 = Sec.reserved3; 56 return S; 57 } 58 59 template <typename SectionType, typename SegmentType> 60 Expected<std::vector<std::unique_ptr<Section>>> static extractSections( 61 const object::MachOObjectFile::LoadCommandInfo &LoadCmd, 62 const object::MachOObjectFile &MachOObj, uint32_t &NextSectionIndex) { 63 std::vector<std::unique_ptr<Section>> Sections; 64 for (auto Curr = reinterpret_cast<const SectionType *>(LoadCmd.Ptr + 65 sizeof(SegmentType)), 66 End = reinterpret_cast<const SectionType *>(LoadCmd.Ptr + 67 LoadCmd.C.cmdsize); 68 Curr < End; ++Curr) { 69 SectionType Sec; 70 memcpy((void *)&Sec, Curr, sizeof(SectionType)); 71 72 if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) 73 MachO::swapStruct(Sec); 74 75 Sections.push_back( 76 std::make_unique<Section>(constructSection(Sec, NextSectionIndex))); 77 78 Section &S = *Sections.back(); 79 80 Expected<object::SectionRef> SecRef = 81 MachOObj.getSection(NextSectionIndex++); 82 if (!SecRef) 83 return SecRef.takeError(); 84 85 Expected<ArrayRef<uint8_t>> Data = 86 MachOObj.getSectionContents(SecRef->getRawDataRefImpl()); 87 if (!Data) 88 return Data.takeError(); 89 90 S.Content = 91 StringRef(reinterpret_cast<const char *>(Data->data()), Data->size()); 92 93 const uint32_t CPUType = MachOObj.getHeader().cputype; 94 S.Relocations.reserve(S.NReloc); 95 for (auto RI = MachOObj.section_rel_begin(SecRef->getRawDataRefImpl()), 96 RE = MachOObj.section_rel_end(SecRef->getRawDataRefImpl()); 97 RI != RE; ++RI) { 98 RelocationInfo R; 99 R.Symbol = nullptr; // We'll fill this field later. 100 R.Info = MachOObj.getRelocation(RI->getRawDataRefImpl()); 101 R.Scattered = MachOObj.isRelocationScattered(R.Info); 102 unsigned Type = MachOObj.getAnyRelocationType(R.Info); 103 // TODO Support CPU_TYPE_ARM. 104 R.IsAddend = !R.Scattered && (CPUType == MachO::CPU_TYPE_ARM64 && 105 Type == MachO::ARM64_RELOC_ADDEND); 106 R.Extern = !R.Scattered && MachOObj.getPlainRelocationExternal(R.Info); 107 S.Relocations.push_back(R); 108 } 109 110 assert(S.NReloc == S.Relocations.size() && 111 "Incorrect number of relocations"); 112 } 113 return std::move(Sections); 114 } 115 116 Error MachOReader::readLoadCommands(Object &O) const { 117 // For MachO sections indices start from 1. 118 uint32_t NextSectionIndex = 1; 119 for (auto LoadCmd : MachOObj.load_commands()) { 120 LoadCommand LC; 121 switch (LoadCmd.C.cmd) { 122 case MachO::LC_CODE_SIGNATURE: 123 O.CodeSignatureCommandIndex = O.LoadCommands.size(); 124 break; 125 case MachO::LC_SEGMENT: 126 if (Expected<std::vector<std::unique_ptr<Section>>> Sections = 127 extractSections<MachO::section, MachO::segment_command>( 128 LoadCmd, MachOObj, NextSectionIndex)) 129 LC.Sections = std::move(*Sections); 130 else 131 return Sections.takeError(); 132 break; 133 case MachO::LC_SEGMENT_64: 134 if (Expected<std::vector<std::unique_ptr<Section>>> Sections = 135 extractSections<MachO::section_64, MachO::segment_command_64>( 136 LoadCmd, MachOObj, NextSectionIndex)) 137 LC.Sections = std::move(*Sections); 138 else 139 return Sections.takeError(); 140 break; 141 case MachO::LC_SYMTAB: 142 O.SymTabCommandIndex = O.LoadCommands.size(); 143 break; 144 case MachO::LC_DYSYMTAB: 145 O.DySymTabCommandIndex = O.LoadCommands.size(); 146 break; 147 case MachO::LC_DYLD_INFO: 148 case MachO::LC_DYLD_INFO_ONLY: 149 O.DyLdInfoCommandIndex = O.LoadCommands.size(); 150 break; 151 case MachO::LC_DATA_IN_CODE: 152 O.DataInCodeCommandIndex = O.LoadCommands.size(); 153 break; 154 case MachO::LC_LINKER_OPTIMIZATION_HINT: 155 O.LinkerOptimizationHintCommandIndex = O.LoadCommands.size(); 156 break; 157 case MachO::LC_FUNCTION_STARTS: 158 O.FunctionStartsCommandIndex = O.LoadCommands.size(); 159 break; 160 } 161 #define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \ 162 case MachO::LCName: \ 163 memcpy((void *)&(LC.MachOLoadCommand.LCStruct##_data), LoadCmd.Ptr, \ 164 sizeof(MachO::LCStruct)); \ 165 if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) \ 166 MachO::swapStruct(LC.MachOLoadCommand.LCStruct##_data); \ 167 if (LoadCmd.C.cmdsize > sizeof(MachO::LCStruct)) \ 168 LC.Payload = ArrayRef<uint8_t>( \ 169 reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) + \ 170 sizeof(MachO::LCStruct), \ 171 LoadCmd.C.cmdsize - sizeof(MachO::LCStruct)); \ 172 break; 173 174 switch (LoadCmd.C.cmd) { 175 default: 176 memcpy((void *)&(LC.MachOLoadCommand.load_command_data), LoadCmd.Ptr, 177 sizeof(MachO::load_command)); 178 if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) 179 MachO::swapStruct(LC.MachOLoadCommand.load_command_data); 180 if (LoadCmd.C.cmdsize > sizeof(MachO::load_command)) 181 LC.Payload = ArrayRef<uint8_t>( 182 reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) + 183 sizeof(MachO::load_command), 184 LoadCmd.C.cmdsize - sizeof(MachO::load_command)); 185 break; 186 #include "llvm/BinaryFormat/MachO.def" 187 } 188 O.LoadCommands.push_back(std::move(LC)); 189 } 190 return Error::success(); 191 } 192 193 template <typename nlist_t> 194 SymbolEntry constructSymbolEntry(StringRef StrTable, const nlist_t &nlist) { 195 assert(nlist.n_strx < StrTable.size() && 196 "n_strx exceeds the size of the string table"); 197 SymbolEntry SE; 198 SE.Name = StringRef(StrTable.data() + nlist.n_strx).str(); 199 SE.n_type = nlist.n_type; 200 SE.n_sect = nlist.n_sect; 201 SE.n_desc = nlist.n_desc; 202 SE.n_value = nlist.n_value; 203 return SE; 204 } 205 206 void MachOReader::readSymbolTable(Object &O) const { 207 StringRef StrTable = MachOObj.getStringTableData(); 208 for (auto Symbol : MachOObj.symbols()) { 209 SymbolEntry SE = 210 (MachOObj.is64Bit() 211 ? constructSymbolEntry(StrTable, MachOObj.getSymbol64TableEntry( 212 Symbol.getRawDataRefImpl())) 213 : constructSymbolEntry(StrTable, MachOObj.getSymbolTableEntry( 214 Symbol.getRawDataRefImpl()))); 215 216 O.SymTable.Symbols.push_back(std::make_unique<SymbolEntry>(SE)); 217 } 218 } 219 220 void MachOReader::setSymbolInRelocationInfo(Object &O) const { 221 std::vector<const Section *> Sections; 222 for (auto &LC : O.LoadCommands) 223 for (std::unique_ptr<Section> &Sec : LC.Sections) 224 Sections.push_back(Sec.get()); 225 226 for (LoadCommand &LC : O.LoadCommands) 227 for (std::unique_ptr<Section> &Sec : LC.Sections) 228 for (auto &Reloc : Sec->Relocations) 229 if (!Reloc.Scattered && !Reloc.IsAddend) { 230 const uint32_t SymbolNum = 231 Reloc.getPlainRelocationSymbolNum(MachOObj.isLittleEndian()); 232 if (Reloc.Extern) { 233 Reloc.Symbol = O.SymTable.getSymbolByIndex(SymbolNum); 234 } else { 235 // FIXME: Refactor error handling in MachOReader and report an error 236 // if we encounter an invalid relocation. 237 assert(SymbolNum >= 1 && SymbolNum <= Sections.size() && 238 "Invalid section index."); 239 Reloc.Sec = Sections[SymbolNum - 1]; 240 } 241 } 242 } 243 244 void MachOReader::readRebaseInfo(Object &O) const { 245 O.Rebases.Opcodes = MachOObj.getDyldInfoRebaseOpcodes(); 246 } 247 248 void MachOReader::readBindInfo(Object &O) const { 249 O.Binds.Opcodes = MachOObj.getDyldInfoBindOpcodes(); 250 } 251 252 void MachOReader::readWeakBindInfo(Object &O) const { 253 O.WeakBinds.Opcodes = MachOObj.getDyldInfoWeakBindOpcodes(); 254 } 255 256 void MachOReader::readLazyBindInfo(Object &O) const { 257 O.LazyBinds.Opcodes = MachOObj.getDyldInfoLazyBindOpcodes(); 258 } 259 260 void MachOReader::readExportInfo(Object &O) const { 261 O.Exports.Trie = MachOObj.getDyldInfoExportsTrie(); 262 } 263 264 void MachOReader::readLinkData(Object &O, Optional<size_t> LCIndex, 265 LinkData &LD) const { 266 if (!LCIndex) 267 return; 268 const MachO::linkedit_data_command &LC = 269 O.LoadCommands[*LCIndex].MachOLoadCommand.linkedit_data_command_data; 270 LD.Data = 271 arrayRefFromStringRef(MachOObj.getData().substr(LC.dataoff, LC.datasize)); 272 } 273 274 void MachOReader::readCodeSignature(Object &O) const { 275 return readLinkData(O, O.CodeSignatureCommandIndex, O.CodeSignature); 276 } 277 278 void MachOReader::readDataInCodeData(Object &O) const { 279 return readLinkData(O, O.DataInCodeCommandIndex, O.DataInCode); 280 } 281 282 void MachOReader::readLinkerOptimizationHint(Object &O) const { 283 return readLinkData(O, O.LinkerOptimizationHintCommandIndex, 284 O.LinkerOptimizationHint); 285 } 286 287 void MachOReader::readFunctionStartsData(Object &O) const { 288 return readLinkData(O, O.FunctionStartsCommandIndex, O.FunctionStarts); 289 } 290 291 void MachOReader::readIndirectSymbolTable(Object &O) const { 292 MachO::dysymtab_command DySymTab = MachOObj.getDysymtabLoadCommand(); 293 constexpr uint32_t AbsOrLocalMask = 294 MachO::INDIRECT_SYMBOL_LOCAL | MachO::INDIRECT_SYMBOL_ABS; 295 for (uint32_t i = 0; i < DySymTab.nindirectsyms; ++i) { 296 uint32_t Index = MachOObj.getIndirectSymbolTableEntry(DySymTab, i); 297 if ((Index & AbsOrLocalMask) != 0) 298 O.IndirectSymTable.Symbols.emplace_back(Index, None); 299 else 300 O.IndirectSymTable.Symbols.emplace_back( 301 Index, O.SymTable.getSymbolByIndex(Index)); 302 } 303 } 304 305 void MachOReader::readSwiftVersion(Object &O) const { 306 struct ObjCImageInfo { 307 uint32_t Version; 308 uint32_t Flags; 309 } ImageInfo; 310 311 for (const LoadCommand &LC : O.LoadCommands) 312 for (const std::unique_ptr<Section> &Sec : LC.Sections) 313 if (Sec->Sectname == "__objc_imageinfo" && 314 (Sec->Segname == "__DATA" || Sec->Segname == "__DATA_CONST" || 315 Sec->Segname == "__DATA_DIRTY") && 316 Sec->Content.size() >= sizeof(ObjCImageInfo)) { 317 memcpy(&ImageInfo, Sec->Content.data(), sizeof(ObjCImageInfo)); 318 if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) { 319 sys::swapByteOrder(ImageInfo.Version); 320 sys::swapByteOrder(ImageInfo.Flags); 321 } 322 O.SwiftVersion = (ImageInfo.Flags >> 8) & 0xff; 323 return; 324 } 325 } 326 327 Expected<std::unique_ptr<Object>> MachOReader::create() const { 328 auto Obj = std::make_unique<Object>(); 329 readHeader(*Obj); 330 if (Error E = readLoadCommands(*Obj)) 331 return std::move(E); 332 readSymbolTable(*Obj); 333 setSymbolInRelocationInfo(*Obj); 334 readRebaseInfo(*Obj); 335 readBindInfo(*Obj); 336 readWeakBindInfo(*Obj); 337 readLazyBindInfo(*Obj); 338 readExportInfo(*Obj); 339 readCodeSignature(*Obj); 340 readDataInCodeData(*Obj); 341 readLinkerOptimizationHint(*Obj); 342 readFunctionStartsData(*Obj); 343 readIndirectSymbolTable(*Obj); 344 readSwiftVersion(*Obj); 345 return std::move(Obj); 346 } 347