| Chris Bieneman | b83c187 | 2016-05-11 22:07:48 +0000 | [diff] [blame] | 1 | //===- yaml2macho - Convert YAML to a Mach object file --------------------===// | 
|  | 2 | // | 
| Chandler Carruth | 2946cd7 | 2019-01-19 08:50:56 +0000 | [diff] [blame] | 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 | 
| Chris Bieneman | b83c187 | 2016-05-11 22:07:48 +0000 | [diff] [blame] | 6 | // | 
|  | 7 | //===----------------------------------------------------------------------===// | 
|  | 8 | /// | 
|  | 9 | /// \file | 
| Adrian Prantl | 5f8f34e4 | 2018-05-01 15:54:18 +0000 | [diff] [blame] | 10 | /// The Mach component of yaml2obj. | 
| Chris Bieneman | b83c187 | 2016-05-11 22:07:48 +0000 | [diff] [blame] | 11 | /// | 
|  | 12 | //===----------------------------------------------------------------------===// | 
|  | 13 |  | 
| Zachary Turner | 264b5d9 | 2017-06-07 03:48:56 +0000 | [diff] [blame] | 14 | #include "llvm/BinaryFormat/MachO.h" | 
| Chris Bieneman | 07088c1 | 2017-01-12 21:35:21 +0000 | [diff] [blame] | 15 | #include "llvm/ObjectYAML/DWARFEmitter.h" | 
| Zachary Turner | 264b5d9 | 2017-06-07 03:48:56 +0000 | [diff] [blame] | 16 | #include "llvm/ObjectYAML/ObjectYAML.h" | 
| Alex Brachet | c22d966 | 2019-08-07 02:44:49 +0000 | [diff] [blame] | 17 | #include "llvm/ObjectYAML/yaml2obj.h" | 
| Chris Bieneman | a23b26f | 2016-05-12 17:44:48 +0000 | [diff] [blame] | 18 | #include "llvm/Support/Error.h" | 
| Chris Bieneman | e8e7555 | 2016-05-25 17:09:07 +0000 | [diff] [blame] | 19 | #include "llvm/Support/LEB128.h" | 
| Chris Bieneman | a23b26f | 2016-05-12 17:44:48 +0000 | [diff] [blame] | 20 | #include "llvm/Support/YAMLTraits.h" | 
| Chris Bieneman | b83c187 | 2016-05-11 22:07:48 +0000 | [diff] [blame] | 21 | #include "llvm/Support/raw_ostream.h" | 
|  | 22 |  | 
| Chris Bieneman | e8e7555 | 2016-05-25 17:09:07 +0000 | [diff] [blame] | 23 | #include "llvm/Support/Format.h" | 
|  | 24 |  | 
| Chris Bieneman | b83c187 | 2016-05-11 22:07:48 +0000 | [diff] [blame] | 25 | using namespace llvm; | 
|  | 26 |  | 
| Chris Bieneman | a23b26f | 2016-05-12 17:44:48 +0000 | [diff] [blame] | 27 | namespace { | 
|  | 28 |  | 
|  | 29 | class MachOWriter { | 
|  | 30 | public: | 
| Chris Bieneman | e18fee2 | 2016-05-20 22:31:50 +0000 | [diff] [blame] | 31 | MachOWriter(MachOYAML::Object &Obj) : Obj(Obj), is64Bit(true), fileStart(0) { | 
| Chris Bieneman | a23b26f | 2016-05-12 17:44:48 +0000 | [diff] [blame] | 32 | is64Bit = Obj.Header.magic == MachO::MH_MAGIC_64 || | 
|  | 33 | Obj.Header.magic == MachO::MH_CIGAM_64; | 
| Chris Bieneman | 468208a | 2016-06-06 21:18:43 +0000 | [diff] [blame] | 34 | memset(reinterpret_cast<void *>(&Header), 0, sizeof(MachO::mach_header_64)); | 
| Chris Bieneman | a23b26f | 2016-05-12 17:44:48 +0000 | [diff] [blame] | 35 | } | 
|  | 36 |  | 
|  | 37 | Error writeMachO(raw_ostream &OS); | 
|  | 38 |  | 
|  | 39 | private: | 
|  | 40 | Error writeHeader(raw_ostream &OS); | 
| Chris Bieneman | 8b5906e | 2016-05-13 17:41:41 +0000 | [diff] [blame] | 41 | Error writeLoadCommands(raw_ostream &OS); | 
| Chris Bieneman | e18fee2 | 2016-05-20 22:31:50 +0000 | [diff] [blame] | 42 | Error writeSectionData(raw_ostream &OS); | 
| Chris Bieneman | e8e7555 | 2016-05-25 17:09:07 +0000 | [diff] [blame] | 43 | Error writeLinkEditData(raw_ostream &OS); | 
| Chris Bieneman | 55de3a2 | 2016-12-22 21:58:03 +0000 | [diff] [blame] | 44 |  | 
| Chris Bieneman | 4c42377 | 2016-06-03 16:58:05 +0000 | [diff] [blame] | 45 | void writeBindOpcodes(raw_ostream &OS, | 
| Chris Bieneman | 659b35a | 2016-05-26 20:50:05 +0000 | [diff] [blame] | 46 | std::vector<MachOYAML::BindOpcode> &BindOpcodes); | 
| Chris Bieneman | 4c42377 | 2016-06-03 16:58:05 +0000 | [diff] [blame] | 47 | // LinkEdit writers | 
|  | 48 | Error writeRebaseOpcodes(raw_ostream &OS); | 
|  | 49 | Error writeBasicBindOpcodes(raw_ostream &OS); | 
|  | 50 | Error writeWeakBindOpcodes(raw_ostream &OS); | 
|  | 51 | Error writeLazyBindOpcodes(raw_ostream &OS); | 
|  | 52 | Error writeNameList(raw_ostream &OS); | 
|  | 53 | Error writeStringTable(raw_ostream &OS); | 
| Chris Bieneman | 6852775 | 2016-05-31 17:26:36 +0000 | [diff] [blame] | 54 | Error writeExportTrie(raw_ostream &OS); | 
| Chris Bieneman | e8e7555 | 2016-05-25 17:09:07 +0000 | [diff] [blame] | 55 |  | 
| Chris Bieneman | 6852775 | 2016-05-31 17:26:36 +0000 | [diff] [blame] | 56 | void dumpExportEntry(raw_ostream &OS, MachOYAML::ExportEntry &Entry); | 
| Chris Bieneman | e8e7555 | 2016-05-25 17:09:07 +0000 | [diff] [blame] | 57 | void ZeroToOffset(raw_ostream &OS, size_t offset); | 
| Chris Bieneman | a23b26f | 2016-05-12 17:44:48 +0000 | [diff] [blame] | 58 |  | 
| Chris Bieneman | 8b5906e | 2016-05-13 17:41:41 +0000 | [diff] [blame] | 59 | MachOYAML::Object &Obj; | 
| Chris Bieneman | a23b26f | 2016-05-12 17:44:48 +0000 | [diff] [blame] | 60 | bool is64Bit; | 
| Chris Bieneman | e18fee2 | 2016-05-20 22:31:50 +0000 | [diff] [blame] | 61 | uint64_t fileStart; | 
| Chris Bieneman | a23b26f | 2016-05-12 17:44:48 +0000 | [diff] [blame] | 62 |  | 
| Chris Bieneman | 468208a | 2016-06-06 21:18:43 +0000 | [diff] [blame] | 63 | MachO::mach_header_64 Header; | 
| Chris Bieneman | a23b26f | 2016-05-12 17:44:48 +0000 | [diff] [blame] | 64 | }; | 
|  | 65 |  | 
|  | 66 | Error MachOWriter::writeMachO(raw_ostream &OS) { | 
| Chris Bieneman | e18fee2 | 2016-05-20 22:31:50 +0000 | [diff] [blame] | 67 | fileStart = OS.tell(); | 
| Chris Bieneman | a23b26f | 2016-05-12 17:44:48 +0000 | [diff] [blame] | 68 | if (auto Err = writeHeader(OS)) | 
|  | 69 | return Err; | 
| Chris Bieneman | 8b5906e | 2016-05-13 17:41:41 +0000 | [diff] [blame] | 70 | if (auto Err = writeLoadCommands(OS)) | 
|  | 71 | return Err; | 
| Chris Bieneman | e18fee2 | 2016-05-20 22:31:50 +0000 | [diff] [blame] | 72 | if (auto Err = writeSectionData(OS)) | 
|  | 73 | return Err; | 
| Chris Bieneman | a23b26f | 2016-05-12 17:44:48 +0000 | [diff] [blame] | 74 | return Error::success(); | 
|  | 75 | } | 
|  | 76 |  | 
|  | 77 | Error MachOWriter::writeHeader(raw_ostream &OS) { | 
|  | 78 | Header.magic = Obj.Header.magic; | 
|  | 79 | Header.cputype = Obj.Header.cputype; | 
|  | 80 | Header.cpusubtype = Obj.Header.cpusubtype; | 
|  | 81 | Header.filetype = Obj.Header.filetype; | 
|  | 82 | Header.ncmds = Obj.Header.ncmds; | 
|  | 83 | Header.sizeofcmds = Obj.Header.sizeofcmds; | 
|  | 84 | Header.flags = Obj.Header.flags; | 
| Chris Bieneman | 468208a | 2016-06-06 21:18:43 +0000 | [diff] [blame] | 85 | Header.reserved = Obj.Header.reserved; | 
| Chris Bieneman | a23b26f | 2016-05-12 17:44:48 +0000 | [diff] [blame] | 86 |  | 
| Chris Bieneman | 55de3a2 | 2016-12-22 21:58:03 +0000 | [diff] [blame] | 87 | if (Obj.IsLittleEndian != sys::IsLittleEndianHost) | 
|  | 88 | MachO::swapStruct(Header); | 
|  | 89 |  | 
| Chris Bieneman | 468208a | 2016-06-06 21:18:43 +0000 | [diff] [blame] | 90 | auto header_size = | 
|  | 91 | is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header); | 
|  | 92 | OS.write((const char *)&Header, header_size); | 
| Chris Bieneman | a23b26f | 2016-05-12 17:44:48 +0000 | [diff] [blame] | 93 |  | 
|  | 94 | return Error::success(); | 
|  | 95 | } | 
|  | 96 |  | 
| Chris Bieneman | 2de17d4 | 2016-05-18 16:17:23 +0000 | [diff] [blame] | 97 | template <typename SectionType> | 
|  | 98 | SectionType constructSection(MachOYAML::Section Sec) { | 
|  | 99 | SectionType TempSec; | 
|  | 100 | memcpy(reinterpret_cast<void *>(&TempSec.sectname[0]), &Sec.sectname[0], 16); | 
|  | 101 | memcpy(reinterpret_cast<void *>(&TempSec.segname[0]), &Sec.segname[0], 16); | 
|  | 102 | TempSec.addr = Sec.addr; | 
|  | 103 | TempSec.size = Sec.size; | 
|  | 104 | TempSec.offset = Sec.offset; | 
|  | 105 | TempSec.align = Sec.align; | 
|  | 106 | TempSec.reloff = Sec.reloff; | 
|  | 107 | TempSec.nreloc = Sec.nreloc; | 
|  | 108 | TempSec.flags = Sec.flags; | 
|  | 109 | TempSec.reserved1 = Sec.reserved1; | 
|  | 110 | TempSec.reserved2 = Sec.reserved2; | 
|  | 111 | return TempSec; | 
|  | 112 | } | 
|  | 113 |  | 
| Chris Bieneman | 9f243e9 | 2016-05-19 20:54:43 +0000 | [diff] [blame] | 114 | template <typename StructType> | 
| Chris Bieneman | 55de3a2 | 2016-12-22 21:58:03 +0000 | [diff] [blame] | 115 | size_t writeLoadCommandData(MachOYAML::LoadCommand &LC, raw_ostream &OS, | 
|  | 116 | bool IsLittleEndian) { | 
| Chris Bieneman | 9f243e9 | 2016-05-19 20:54:43 +0000 | [diff] [blame] | 117 | return 0; | 
|  | 118 | } | 
|  | 119 |  | 
|  | 120 | template <> | 
|  | 121 | size_t writeLoadCommandData<MachO::segment_command>(MachOYAML::LoadCommand &LC, | 
| Chris Bieneman | 55de3a2 | 2016-12-22 21:58:03 +0000 | [diff] [blame] | 122 | raw_ostream &OS, | 
|  | 123 | bool IsLittleEndian) { | 
| Chris Bieneman | 9f243e9 | 2016-05-19 20:54:43 +0000 | [diff] [blame] | 124 | size_t BytesWritten = 0; | 
| Benjamin Kramer | 4fed928 | 2016-05-27 12:30:51 +0000 | [diff] [blame] | 125 | for (const auto &Sec : LC.Sections) { | 
| Chris Bieneman | 9f243e9 | 2016-05-19 20:54:43 +0000 | [diff] [blame] | 126 | auto TempSec = constructSection<MachO::section>(Sec); | 
| Chris Bieneman | 55de3a2 | 2016-12-22 21:58:03 +0000 | [diff] [blame] | 127 | if (IsLittleEndian != sys::IsLittleEndianHost) | 
|  | 128 | MachO::swapStruct(TempSec); | 
| Chris Bieneman | 9f243e9 | 2016-05-19 20:54:43 +0000 | [diff] [blame] | 129 | OS.write(reinterpret_cast<const char *>(&(TempSec)), | 
|  | 130 | sizeof(MachO::section)); | 
|  | 131 | BytesWritten += sizeof(MachO::section); | 
|  | 132 | } | 
|  | 133 | return BytesWritten; | 
|  | 134 | } | 
|  | 135 |  | 
|  | 136 | template <> | 
| Chris Bieneman | 55de3a2 | 2016-12-22 21:58:03 +0000 | [diff] [blame] | 137 | size_t writeLoadCommandData<MachO::segment_command_64>( | 
|  | 138 | MachOYAML::LoadCommand &LC, raw_ostream &OS, bool IsLittleEndian) { | 
| Chris Bieneman | 9f243e9 | 2016-05-19 20:54:43 +0000 | [diff] [blame] | 139 | size_t BytesWritten = 0; | 
| Benjamin Kramer | 4fed928 | 2016-05-27 12:30:51 +0000 | [diff] [blame] | 140 | for (const auto &Sec : LC.Sections) { | 
| Chris Bieneman | 9f243e9 | 2016-05-19 20:54:43 +0000 | [diff] [blame] | 141 | auto TempSec = constructSection<MachO::section_64>(Sec); | 
|  | 142 | TempSec.reserved3 = Sec.reserved3; | 
| Chris Bieneman | 55de3a2 | 2016-12-22 21:58:03 +0000 | [diff] [blame] | 143 | if (IsLittleEndian != sys::IsLittleEndianHost) | 
|  | 144 | MachO::swapStruct(TempSec); | 
| Chris Bieneman | 9f243e9 | 2016-05-19 20:54:43 +0000 | [diff] [blame] | 145 | OS.write(reinterpret_cast<const char *>(&(TempSec)), | 
|  | 146 | sizeof(MachO::section_64)); | 
|  | 147 | BytesWritten += sizeof(MachO::section_64); | 
|  | 148 | } | 
|  | 149 | return BytesWritten; | 
|  | 150 | } | 
|  | 151 |  | 
|  | 152 | size_t writePayloadString(MachOYAML::LoadCommand &LC, raw_ostream &OS) { | 
|  | 153 | size_t BytesWritten = 0; | 
|  | 154 | if (!LC.PayloadString.empty()) { | 
|  | 155 | OS.write(LC.PayloadString.c_str(), LC.PayloadString.length()); | 
|  | 156 | BytesWritten = LC.PayloadString.length(); | 
|  | 157 | } | 
|  | 158 | return BytesWritten; | 
|  | 159 | } | 
|  | 160 |  | 
|  | 161 | template <> | 
|  | 162 | size_t writeLoadCommandData<MachO::dylib_command>(MachOYAML::LoadCommand &LC, | 
| Chris Bieneman | 55de3a2 | 2016-12-22 21:58:03 +0000 | [diff] [blame] | 163 | raw_ostream &OS, | 
|  | 164 | bool IsLittleEndian) { | 
| Chris Bieneman | 9f243e9 | 2016-05-19 20:54:43 +0000 | [diff] [blame] | 165 | return writePayloadString(LC, OS); | 
|  | 166 | } | 
|  | 167 |  | 
|  | 168 | template <> | 
|  | 169 | size_t writeLoadCommandData<MachO::dylinker_command>(MachOYAML::LoadCommand &LC, | 
| Chris Bieneman | 55de3a2 | 2016-12-22 21:58:03 +0000 | [diff] [blame] | 170 | raw_ostream &OS, | 
|  | 171 | bool IsLittleEndian) { | 
| Chris Bieneman | 9f243e9 | 2016-05-19 20:54:43 +0000 | [diff] [blame] | 172 | return writePayloadString(LC, OS); | 
|  | 173 | } | 
|  | 174 |  | 
| Chris Bieneman | 6852775 | 2016-05-31 17:26:36 +0000 | [diff] [blame] | 175 | template <> | 
|  | 176 | size_t writeLoadCommandData<MachO::rpath_command>(MachOYAML::LoadCommand &LC, | 
| Chris Bieneman | 55de3a2 | 2016-12-22 21:58:03 +0000 | [diff] [blame] | 177 | raw_ostream &OS, | 
|  | 178 | bool IsLittleEndian) { | 
| Chris Bieneman | 6852775 | 2016-05-31 17:26:36 +0000 | [diff] [blame] | 179 | return writePayloadString(LC, OS); | 
|  | 180 | } | 
|  | 181 |  | 
| Steven Wu | 5b54a42 | 2017-01-23 20:07:55 +0000 | [diff] [blame] | 182 | template <> | 
|  | 183 | size_t writeLoadCommandData<MachO::build_version_command>( | 
|  | 184 | MachOYAML::LoadCommand &LC, raw_ostream &OS, bool IsLittleEndian) { | 
|  | 185 | size_t BytesWritten = 0; | 
|  | 186 | for (const auto &T : LC.Tools) { | 
|  | 187 | struct MachO::build_tool_version tool = T; | 
|  | 188 | if (IsLittleEndian != sys::IsLittleEndianHost) | 
|  | 189 | MachO::swapStruct(tool); | 
|  | 190 | OS.write(reinterpret_cast<const char *>(&tool), | 
|  | 191 | sizeof(MachO::build_tool_version)); | 
|  | 192 | BytesWritten += sizeof(MachO::build_tool_version); | 
|  | 193 | } | 
|  | 194 | return BytesWritten; | 
|  | 195 | } | 
|  | 196 |  | 
| Chris Bieneman | e18fee2 | 2016-05-20 22:31:50 +0000 | [diff] [blame] | 197 | void ZeroFillBytes(raw_ostream &OS, size_t Size) { | 
|  | 198 | std::vector<uint8_t> FillData; | 
|  | 199 | FillData.insert(FillData.begin(), Size, 0); | 
|  | 200 | OS.write(reinterpret_cast<char *>(FillData.data()), Size); | 
|  | 201 | } | 
|  | 202 |  | 
|  | 203 | void Fill(raw_ostream &OS, size_t Size, uint32_t Data) { | 
|  | 204 | std::vector<uint32_t> FillData; | 
|  | 205 | FillData.insert(FillData.begin(), (Size / 4) + 1, Data); | 
|  | 206 | OS.write(reinterpret_cast<char *>(FillData.data()), Size); | 
|  | 207 | } | 
|  | 208 |  | 
| Chris Bieneman | e8e7555 | 2016-05-25 17:09:07 +0000 | [diff] [blame] | 209 | void MachOWriter::ZeroToOffset(raw_ostream &OS, size_t Offset) { | 
|  | 210 | auto currOffset = OS.tell() - fileStart; | 
|  | 211 | if (currOffset < Offset) | 
|  | 212 | ZeroFillBytes(OS, Offset - currOffset); | 
|  | 213 | } | 
|  | 214 |  | 
| Chris Bieneman | 8b5906e | 2016-05-13 17:41:41 +0000 | [diff] [blame] | 215 | Error MachOWriter::writeLoadCommands(raw_ostream &OS) { | 
|  | 216 | for (auto &LC : Obj.LoadCommands) { | 
| Chris Bieneman | 3f2eb83 | 2016-05-17 19:44:06 +0000 | [diff] [blame] | 217 | size_t BytesWritten = 0; | 
| Chris Bieneman | 55de3a2 | 2016-12-22 21:58:03 +0000 | [diff] [blame] | 218 | llvm::MachO::macho_load_command Data = LC.Data; | 
|  | 219 |  | 
| Chris Bieneman | 3f2eb83 | 2016-05-17 19:44:06 +0000 | [diff] [blame] | 220 | #define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct)                         \ | 
|  | 221 | case MachO::LCName:                                                          \ | 
| Chris Bieneman | 55de3a2 | 2016-12-22 21:58:03 +0000 | [diff] [blame] | 222 | if (Obj.IsLittleEndian != sys::IsLittleEndianHost)                         \ | 
|  | 223 | MachO::swapStruct(Data.LCStruct##_data);                                 \ | 
|  | 224 | OS.write(reinterpret_cast<const char *>(&(Data.LCStruct##_data)),          \ | 
| Chris Bieneman | 3f2eb83 | 2016-05-17 19:44:06 +0000 | [diff] [blame] | 225 | sizeof(MachO::LCStruct));                                         \ | 
|  | 226 | BytesWritten = sizeof(MachO::LCStruct);                                    \ | 
| Chris Bieneman | 55de3a2 | 2016-12-22 21:58:03 +0000 | [diff] [blame] | 227 | BytesWritten +=                                                            \ | 
|  | 228 | writeLoadCommandData<MachO::LCStruct>(LC, OS, Obj.IsLittleEndian);     \ | 
| Chris Bieneman | 3f2eb83 | 2016-05-17 19:44:06 +0000 | [diff] [blame] | 229 | break; | 
|  | 230 |  | 
|  | 231 | switch (LC.Data.load_command_data.cmd) { | 
|  | 232 | default: | 
| Chris Bieneman | 55de3a2 | 2016-12-22 21:58:03 +0000 | [diff] [blame] | 233 | if (Obj.IsLittleEndian != sys::IsLittleEndianHost) | 
|  | 234 | MachO::swapStruct(Data.load_command_data); | 
|  | 235 | OS.write(reinterpret_cast<const char *>(&(Data.load_command_data)), | 
| Chris Bieneman | 3f2eb83 | 2016-05-17 19:44:06 +0000 | [diff] [blame] | 236 | sizeof(MachO::load_command)); | 
|  | 237 | BytesWritten = sizeof(MachO::load_command); | 
| Chris Bieneman | 55de3a2 | 2016-12-22 21:58:03 +0000 | [diff] [blame] | 238 | BytesWritten += | 
|  | 239 | writeLoadCommandData<MachO::load_command>(LC, OS, Obj.IsLittleEndian); | 
| Chris Bieneman | 3f2eb83 | 2016-05-17 19:44:06 +0000 | [diff] [blame] | 240 | break; | 
| Zachary Turner | 264b5d9 | 2017-06-07 03:48:56 +0000 | [diff] [blame] | 241 | #include "llvm/BinaryFormat/MachO.def" | 
| Chris Bieneman | 3f2eb83 | 2016-05-17 19:44:06 +0000 | [diff] [blame] | 242 | } | 
|  | 243 |  | 
| Chris Bieneman | 9f243e9 | 2016-05-19 20:54:43 +0000 | [diff] [blame] | 244 | if (LC.PayloadBytes.size() > 0) { | 
|  | 245 | OS.write(reinterpret_cast<const char *>(LC.PayloadBytes.data()), | 
|  | 246 | LC.PayloadBytes.size()); | 
|  | 247 | BytesWritten += LC.PayloadBytes.size(); | 
| Chris Bieneman | 2de17d4 | 2016-05-18 16:17:23 +0000 | [diff] [blame] | 248 | } | 
|  | 249 |  | 
| Chris Bieneman | 9f243e9 | 2016-05-19 20:54:43 +0000 | [diff] [blame] | 250 | if (LC.ZeroPadBytes > 0) { | 
| Chris Bieneman | e18fee2 | 2016-05-20 22:31:50 +0000 | [diff] [blame] | 251 | ZeroFillBytes(OS, LC.ZeroPadBytes); | 
| Chris Bieneman | 9f243e9 | 2016-05-19 20:54:43 +0000 | [diff] [blame] | 252 | BytesWritten += LC.ZeroPadBytes; | 
|  | 253 | } | 
|  | 254 |  | 
| Chris Bieneman | 1abf005 | 2016-05-19 23:26:31 +0000 | [diff] [blame] | 255 | // Fill remaining bytes with 0. This will only get hit in partially | 
|  | 256 | // specified test cases. | 
| Chris Bieneman | 9f243e9 | 2016-05-19 20:54:43 +0000 | [diff] [blame] | 257 | auto BytesRemaining = LC.Data.load_command_data.cmdsize - BytesWritten; | 
| Chris Bieneman | 3f2eb83 | 2016-05-17 19:44:06 +0000 | [diff] [blame] | 258 | if (BytesRemaining > 0) { | 
| Chris Bieneman | e18fee2 | 2016-05-20 22:31:50 +0000 | [diff] [blame] | 259 | ZeroFillBytes(OS, BytesRemaining); | 
|  | 260 | } | 
|  | 261 | } | 
|  | 262 | return Error::success(); | 
|  | 263 | } | 
|  | 264 |  | 
|  | 265 | Error MachOWriter::writeSectionData(raw_ostream &OS) { | 
| Chris Bieneman | 55de3a2 | 2016-12-22 21:58:03 +0000 | [diff] [blame] | 266 | bool FoundLinkEditSeg = false; | 
| Chris Bieneman | e18fee2 | 2016-05-20 22:31:50 +0000 | [diff] [blame] | 267 | for (auto &LC : Obj.LoadCommands) { | 
|  | 268 | switch (LC.Data.load_command_data.cmd) { | 
|  | 269 | case MachO::LC_SEGMENT: | 
|  | 270 | case MachO::LC_SEGMENT_64: | 
|  | 271 | uint64_t segOff = is64Bit ? LC.Data.segment_command_64_data.fileoff | 
|  | 272 | : LC.Data.segment_command_data.fileoff; | 
| Alex Brachet | c22d966 | 2019-08-07 02:44:49 +0000 | [diff] [blame] | 273 | if (0 == | 
|  | 274 | strncmp(&LC.Data.segment_command_data.segname[0], "__LINKEDIT", 16)) { | 
| Chris Bieneman | 55de3a2 | 2016-12-22 21:58:03 +0000 | [diff] [blame] | 275 | FoundLinkEditSeg = true; | 
| Chris Bieneman | e8e7555 | 2016-05-25 17:09:07 +0000 | [diff] [blame] | 276 | if (auto Err = writeLinkEditData(OS)) | 
|  | 277 | return Err; | 
| Chris Bieneman | 55de3a2 | 2016-12-22 21:58:03 +0000 | [diff] [blame] | 278 | } | 
|  | 279 | for (auto &Sec : LC.Sections) { | 
|  | 280 | ZeroToOffset(OS, Sec.offset); | 
| Chris Bieneman | e18fee2 | 2016-05-20 22:31:50 +0000 | [diff] [blame] | 281 | // Zero Fill any data between the end of the last thing we wrote and the | 
|  | 282 | // start of this section. | 
| Chris Bieneman | 55de3a2 | 2016-12-22 21:58:03 +0000 | [diff] [blame] | 283 | assert((OS.tell() - fileStart <= Sec.offset || | 
|  | 284 | Sec.offset == (uint32_t)0) && | 
|  | 285 | "Wrote too much data somewhere, section offsets don't line up."); | 
|  | 286 | if (0 == strncmp(&Sec.segname[0], "__DWARF", 16)) { | 
|  | 287 | if (0 == strncmp(&Sec.sectname[0], "__debug_str", 16)) { | 
| Chris Bieneman | 07088c1 | 2017-01-12 21:35:21 +0000 | [diff] [blame] | 288 | DWARFYAML::EmitDebugStr(OS, Obj.DWARF); | 
| Chris Bieneman | 55de3a2 | 2016-12-22 21:58:03 +0000 | [diff] [blame] | 289 | } else if (0 == strncmp(&Sec.sectname[0], "__debug_abbrev", 16)) { | 
| Chris Bieneman | 07088c1 | 2017-01-12 21:35:21 +0000 | [diff] [blame] | 290 | DWARFYAML::EmitDebugAbbrev(OS, Obj.DWARF); | 
| Chris Bieneman | 55de3a2 | 2016-12-22 21:58:03 +0000 | [diff] [blame] | 291 | } else if (0 == strncmp(&Sec.sectname[0], "__debug_aranges", 16)) { | 
| Chris Bieneman | 07088c1 | 2017-01-12 21:35:21 +0000 | [diff] [blame] | 292 | DWARFYAML::EmitDebugAranges(OS, Obj.DWARF); | 
| Chris Bieneman | 55de3a2 | 2016-12-22 21:58:03 +0000 | [diff] [blame] | 293 | } else if (0 == strncmp(&Sec.sectname[0], "__debug_pubnames", 16)) { | 
| Chris Bieneman | 07088c1 | 2017-01-12 21:35:21 +0000 | [diff] [blame] | 294 | DWARFYAML::EmitPubSection(OS, Obj.DWARF.PubNames, | 
|  | 295 | Obj.IsLittleEndian); | 
| Chris Bieneman | 55de3a2 | 2016-12-22 21:58:03 +0000 | [diff] [blame] | 296 | } else if (0 == strncmp(&Sec.sectname[0], "__debug_pubtypes", 16)) { | 
| Chris Bieneman | 07088c1 | 2017-01-12 21:35:21 +0000 | [diff] [blame] | 297 | DWARFYAML::EmitPubSection(OS, Obj.DWARF.PubTypes, | 
|  | 298 | Obj.IsLittleEndian); | 
| Chris Bieneman | e0e451d | 2016-12-22 22:44:27 +0000 | [diff] [blame] | 299 | } else if (0 == strncmp(&Sec.sectname[0], "__debug_info", 16)) { | 
| Chris Bieneman | 07088c1 | 2017-01-12 21:35:21 +0000 | [diff] [blame] | 300 | DWARFYAML::EmitDebugInfo(OS, Obj.DWARF); | 
| Chris Bieneman | 1b7200d | 2017-01-10 06:22:49 +0000 | [diff] [blame] | 301 | } else if (0 == strncmp(&Sec.sectname[0], "__debug_line", 16)) { | 
| Chris Bieneman | 07088c1 | 2017-01-12 21:35:21 +0000 | [diff] [blame] | 302 | DWARFYAML::EmitDebugLine(OS, Obj.DWARF); | 
| Chris Bieneman | e8e7555 | 2016-05-25 17:09:07 +0000 | [diff] [blame] | 303 | } | 
| Seiya Nuta | 4f15732 | 2019-06-17 02:07:20 +0000 | [diff] [blame] | 304 |  | 
|  | 305 | continue; | 
| Chris Bieneman | e8e7555 | 2016-05-25 17:09:07 +0000 | [diff] [blame] | 306 | } | 
| Seiya Nuta | 4f15732 | 2019-06-17 02:07:20 +0000 | [diff] [blame] | 307 |  | 
|  | 308 | // Skip if it's a virtual section. | 
| Seiya Nuta | 5223774 | 2019-08-20 08:49:07 +0000 | [diff] [blame] | 309 | if (MachO::isVirtualSection(Sec.flags & MachO::SECTION_TYPE)) | 
| Seiya Nuta | 4f15732 | 2019-06-17 02:07:20 +0000 | [diff] [blame] | 310 | continue; | 
|  | 311 |  | 
| Seiya Nuta | 5223774 | 2019-08-20 08:49:07 +0000 | [diff] [blame] | 312 | if (Sec.content) { | 
|  | 313 | yaml::BinaryRef Content = *Sec.content; | 
|  | 314 | Content.writeAsBinary(OS); | 
|  | 315 | ZeroFillBytes(OS, Sec.size - Content.binary_size()); | 
|  | 316 | } else { | 
|  | 317 | // Fill section data with 0xDEADBEEF. | 
|  | 318 | Fill(OS, Sec.size, 0xDEADBEEFu); | 
|  | 319 | } | 
| Chris Bieneman | e18fee2 | 2016-05-20 22:31:50 +0000 | [diff] [blame] | 320 | } | 
|  | 321 | uint64_t segSize = is64Bit ? LC.Data.segment_command_64_data.filesize | 
|  | 322 | : LC.Data.segment_command_data.filesize; | 
| Chris Bieneman | e8e7555 | 2016-05-25 17:09:07 +0000 | [diff] [blame] | 323 | ZeroToOffset(OS, segOff + segSize); | 
| Chris Bieneman | e18fee2 | 2016-05-20 22:31:50 +0000 | [diff] [blame] | 324 | break; | 
| Chris Bieneman | 8b5906e | 2016-05-13 17:41:41 +0000 | [diff] [blame] | 325 | } | 
|  | 326 | } | 
| Chris Bieneman | 55de3a2 | 2016-12-22 21:58:03 +0000 | [diff] [blame] | 327 | // Old PPC Object Files didn't have __LINKEDIT segments, the data was just | 
|  | 328 | // stuck at the end of the file. | 
|  | 329 | if (!FoundLinkEditSeg) { | 
|  | 330 | if (auto Err = writeLinkEditData(OS)) | 
|  | 331 | return Err; | 
|  | 332 | } | 
| Chris Bieneman | 8b5906e | 2016-05-13 17:41:41 +0000 | [diff] [blame] | 333 | return Error::success(); | 
|  | 334 | } | 
|  | 335 |  | 
| Chris Bieneman | 659b35a | 2016-05-26 20:50:05 +0000 | [diff] [blame] | 336 | void MachOWriter::writeBindOpcodes( | 
| Chris Bieneman | 4c42377 | 2016-06-03 16:58:05 +0000 | [diff] [blame] | 337 | raw_ostream &OS, std::vector<MachOYAML::BindOpcode> &BindOpcodes) { | 
| Chris Bieneman | 659b35a | 2016-05-26 20:50:05 +0000 | [diff] [blame] | 338 |  | 
|  | 339 | for (auto Opcode : BindOpcodes) { | 
|  | 340 | uint8_t OpByte = Opcode.Opcode | Opcode.Imm; | 
|  | 341 | OS.write(reinterpret_cast<char *>(&OpByte), 1); | 
|  | 342 | for (auto Data : Opcode.ULEBExtraData) { | 
|  | 343 | encodeULEB128(Data, OS); | 
|  | 344 | } | 
|  | 345 | for (auto Data : Opcode.SLEBExtraData) { | 
|  | 346 | encodeSLEB128(Data, OS); | 
|  | 347 | } | 
|  | 348 | if (!Opcode.Symbol.empty()) { | 
|  | 349 | OS.write(Opcode.Symbol.data(), Opcode.Symbol.size()); | 
| Chris Bieneman | 6852775 | 2016-05-31 17:26:36 +0000 | [diff] [blame] | 350 | OS.write('\0'); | 
| Chris Bieneman | 659b35a | 2016-05-26 20:50:05 +0000 | [diff] [blame] | 351 | } | 
|  | 352 | } | 
|  | 353 | } | 
|  | 354 |  | 
| Chris Bieneman | 07bb3c8 | 2016-06-02 22:54:06 +0000 | [diff] [blame] | 355 | void MachOWriter::dumpExportEntry(raw_ostream &OS, | 
|  | 356 | MachOYAML::ExportEntry &Entry) { | 
| Chris Bieneman | 6852775 | 2016-05-31 17:26:36 +0000 | [diff] [blame] | 357 | encodeSLEB128(Entry.TerminalSize, OS); | 
|  | 358 | if (Entry.TerminalSize > 0) { | 
|  | 359 | encodeSLEB128(Entry.Flags, OS); | 
| Chris Bieneman | 07bb3c8 | 2016-06-02 22:54:06 +0000 | [diff] [blame] | 360 | if (Entry.Flags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT) { | 
| Chris Bieneman | 6852775 | 2016-05-31 17:26:36 +0000 | [diff] [blame] | 361 | encodeSLEB128(Entry.Other, OS); | 
|  | 362 | OS << Entry.ImportName; | 
|  | 363 | OS.write('\0'); | 
| Chris Bieneman | 07bb3c8 | 2016-06-02 22:54:06 +0000 | [diff] [blame] | 364 | } else { | 
| Chris Bieneman | 6852775 | 2016-05-31 17:26:36 +0000 | [diff] [blame] | 365 | encodeSLEB128(Entry.Address, OS); | 
|  | 366 | if (Entry.Flags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) | 
|  | 367 | encodeSLEB128(Entry.Other, OS); | 
|  | 368 | } | 
|  | 369 | } | 
|  | 370 | OS.write(static_cast<uint8_t>(Entry.Children.size())); | 
| Chris Bieneman | 07bb3c8 | 2016-06-02 22:54:06 +0000 | [diff] [blame] | 371 | for (auto EE : Entry.Children) { | 
| Chris Bieneman | 6852775 | 2016-05-31 17:26:36 +0000 | [diff] [blame] | 372 | OS << EE.Name; | 
|  | 373 | OS.write('\0'); | 
|  | 374 | encodeSLEB128(EE.NodeOffset, OS); | 
|  | 375 | } | 
|  | 376 | for (auto EE : Entry.Children) | 
|  | 377 | dumpExportEntry(OS, EE); | 
|  | 378 | } | 
|  | 379 |  | 
|  | 380 | Error MachOWriter::writeExportTrie(raw_ostream &OS) { | 
|  | 381 | dumpExportEntry(OS, Obj.LinkEdit.ExportTrie); | 
|  | 382 | return Error::success(); | 
|  | 383 | } | 
|  | 384 |  | 
| Chris Bieneman | 07bb3c8 | 2016-06-02 22:54:06 +0000 | [diff] [blame] | 385 | template <typename NListType> | 
| Chris Bieneman | 55de3a2 | 2016-12-22 21:58:03 +0000 | [diff] [blame] | 386 | void writeNListEntry(MachOYAML::NListEntry &NLE, raw_ostream &OS, | 
|  | 387 | bool IsLittleEndian) { | 
| Chris Bieneman | 07bb3c8 | 2016-06-02 22:54:06 +0000 | [diff] [blame] | 388 | NListType ListEntry; | 
|  | 389 | ListEntry.n_strx = NLE.n_strx; | 
|  | 390 | ListEntry.n_type = NLE.n_type; | 
|  | 391 | ListEntry.n_sect = NLE.n_sect; | 
|  | 392 | ListEntry.n_desc = NLE.n_desc; | 
|  | 393 | ListEntry.n_value = NLE.n_value; | 
| Chris Bieneman | 55de3a2 | 2016-12-22 21:58:03 +0000 | [diff] [blame] | 394 |  | 
| Chris Bieneman | e477fb9 | 2016-12-22 22:16:04 +0000 | [diff] [blame] | 395 | if (IsLittleEndian != sys::IsLittleEndianHost) | 
| Chris Bieneman | 55de3a2 | 2016-12-22 21:58:03 +0000 | [diff] [blame] | 396 | MachO::swapStruct(ListEntry); | 
| Chris Bieneman | 07bb3c8 | 2016-06-02 22:54:06 +0000 | [diff] [blame] | 397 | OS.write(reinterpret_cast<const char *>(&ListEntry), sizeof(NListType)); | 
|  | 398 | } | 
|  | 399 |  | 
| Chris Bieneman | e8e7555 | 2016-05-25 17:09:07 +0000 | [diff] [blame] | 400 | Error MachOWriter::writeLinkEditData(raw_ostream &OS) { | 
| Chris Bieneman | 4c42377 | 2016-06-03 16:58:05 +0000 | [diff] [blame] | 401 | typedef Error (MachOWriter::*writeHandler)(raw_ostream &); | 
|  | 402 | typedef std::pair<uint64_t, writeHandler> writeOperation; | 
|  | 403 | std::vector<writeOperation> WriteQueue; | 
|  | 404 |  | 
| Chris Bieneman | e8e7555 | 2016-05-25 17:09:07 +0000 | [diff] [blame] | 405 | MachO::dyld_info_command *DyldInfoOnlyCmd = 0; | 
|  | 406 | MachO::symtab_command *SymtabCmd = 0; | 
|  | 407 | for (auto &LC : Obj.LoadCommands) { | 
|  | 408 | switch (LC.Data.load_command_data.cmd) { | 
|  | 409 | case MachO::LC_SYMTAB: | 
|  | 410 | SymtabCmd = &LC.Data.symtab_command_data; | 
| Chris Bieneman | 4c42377 | 2016-06-03 16:58:05 +0000 | [diff] [blame] | 411 | WriteQueue.push_back( | 
|  | 412 | std::make_pair(SymtabCmd->symoff, &MachOWriter::writeNameList)); | 
|  | 413 | WriteQueue.push_back( | 
|  | 414 | std::make_pair(SymtabCmd->stroff, &MachOWriter::writeStringTable)); | 
| Chris Bieneman | e8e7555 | 2016-05-25 17:09:07 +0000 | [diff] [blame] | 415 | break; | 
|  | 416 | case MachO::LC_DYLD_INFO_ONLY: | 
|  | 417 | DyldInfoOnlyCmd = &LC.Data.dyld_info_command_data; | 
| Chris Bieneman | 4c42377 | 2016-06-03 16:58:05 +0000 | [diff] [blame] | 418 | WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->rebase_off, | 
|  | 419 | &MachOWriter::writeRebaseOpcodes)); | 
|  | 420 | WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->bind_off, | 
|  | 421 | &MachOWriter::writeBasicBindOpcodes)); | 
|  | 422 | WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->weak_bind_off, | 
|  | 423 | &MachOWriter::writeWeakBindOpcodes)); | 
|  | 424 | WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->lazy_bind_off, | 
|  | 425 | &MachOWriter::writeLazyBindOpcodes)); | 
|  | 426 | WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->export_off, | 
|  | 427 | &MachOWriter::writeExportTrie)); | 
| Chris Bieneman | e8e7555 | 2016-05-25 17:09:07 +0000 | [diff] [blame] | 428 | break; | 
|  | 429 | } | 
|  | 430 | } | 
|  | 431 |  | 
| Fangrui Song | 0cac726 | 2018-09-27 02:13:45 +0000 | [diff] [blame] | 432 | llvm::sort(WriteQueue, [](const writeOperation &a, const writeOperation &b) { | 
|  | 433 | return a.first < b.first; | 
|  | 434 | }); | 
| Chris Bieneman | 4c42377 | 2016-06-03 16:58:05 +0000 | [diff] [blame] | 435 |  | 
|  | 436 | for (auto writeOp : WriteQueue) { | 
|  | 437 | ZeroToOffset(OS, writeOp.first); | 
|  | 438 | if (auto Err = (this->*writeOp.second)(OS)) | 
|  | 439 | return Err; | 
|  | 440 | } | 
|  | 441 |  | 
|  | 442 | return Error::success(); | 
|  | 443 | } | 
|  | 444 |  | 
|  | 445 | Error MachOWriter::writeRebaseOpcodes(raw_ostream &OS) { | 
|  | 446 | MachOYAML::LinkEditData &LinkEdit = Obj.LinkEdit; | 
| Chris Bieneman | e8e7555 | 2016-05-25 17:09:07 +0000 | [diff] [blame] | 447 |  | 
|  | 448 | for (auto Opcode : LinkEdit.RebaseOpcodes) { | 
|  | 449 | uint8_t OpByte = Opcode.Opcode | Opcode.Imm; | 
|  | 450 | OS.write(reinterpret_cast<char *>(&OpByte), 1); | 
|  | 451 | for (auto Data : Opcode.ExtraData) { | 
|  | 452 | encodeULEB128(Data, OS); | 
|  | 453 | } | 
|  | 454 | } | 
| Chris Bieneman | 4c42377 | 2016-06-03 16:58:05 +0000 | [diff] [blame] | 455 | return Error::success(); | 
|  | 456 | } | 
| Chris Bieneman | e8e7555 | 2016-05-25 17:09:07 +0000 | [diff] [blame] | 457 |  | 
| Chris Bieneman | 4c42377 | 2016-06-03 16:58:05 +0000 | [diff] [blame] | 458 | Error MachOWriter::writeBasicBindOpcodes(raw_ostream &OS) { | 
|  | 459 | writeBindOpcodes(OS, Obj.LinkEdit.BindOpcodes); | 
|  | 460 | return Error::success(); | 
|  | 461 | } | 
| Chris Bieneman | 524243d | 2016-05-26 20:06:14 +0000 | [diff] [blame] | 462 |  | 
| Chris Bieneman | 4c42377 | 2016-06-03 16:58:05 +0000 | [diff] [blame] | 463 | Error MachOWriter::writeWeakBindOpcodes(raw_ostream &OS) { | 
|  | 464 | writeBindOpcodes(OS, Obj.LinkEdit.WeakBindOpcodes); | 
|  | 465 | return Error::success(); | 
|  | 466 | } | 
| Chris Bieneman | 6852775 | 2016-05-31 17:26:36 +0000 | [diff] [blame] | 467 |  | 
| Chris Bieneman | 4c42377 | 2016-06-03 16:58:05 +0000 | [diff] [blame] | 468 | Error MachOWriter::writeLazyBindOpcodes(raw_ostream &OS) { | 
|  | 469 | writeBindOpcodes(OS, Obj.LinkEdit.LazyBindOpcodes); | 
|  | 470 | return Error::success(); | 
|  | 471 | } | 
|  | 472 |  | 
|  | 473 | Error MachOWriter::writeNameList(raw_ostream &OS) { | 
|  | 474 | for (auto NLE : Obj.LinkEdit.NameList) { | 
| Chris Bieneman | 07bb3c8 | 2016-06-02 22:54:06 +0000 | [diff] [blame] | 475 | if (is64Bit) | 
| Chris Bieneman | 55de3a2 | 2016-12-22 21:58:03 +0000 | [diff] [blame] | 476 | writeNListEntry<MachO::nlist_64>(NLE, OS, Obj.IsLittleEndian); | 
| Chris Bieneman | 07bb3c8 | 2016-06-02 22:54:06 +0000 | [diff] [blame] | 477 | else | 
| Chris Bieneman | 55de3a2 | 2016-12-22 21:58:03 +0000 | [diff] [blame] | 478 | writeNListEntry<MachO::nlist>(NLE, OS, Obj.IsLittleEndian); | 
| Chris Bieneman | 07bb3c8 | 2016-06-02 22:54:06 +0000 | [diff] [blame] | 479 | } | 
| Chris Bieneman | 4c42377 | 2016-06-03 16:58:05 +0000 | [diff] [blame] | 480 | return Error::success(); | 
|  | 481 | } | 
| Chris Bieneman | 07bb3c8 | 2016-06-02 22:54:06 +0000 | [diff] [blame] | 482 |  | 
| Chris Bieneman | 4c42377 | 2016-06-03 16:58:05 +0000 | [diff] [blame] | 483 | Error MachOWriter::writeStringTable(raw_ostream &OS) { | 
|  | 484 | for (auto Str : Obj.LinkEdit.StringTable) { | 
| Chris Bieneman | 07bb3c8 | 2016-06-02 22:54:06 +0000 | [diff] [blame] | 485 | OS.write(Str.data(), Str.size()); | 
|  | 486 | OS.write('\0'); | 
|  | 487 | } | 
| Chris Bieneman | e8e7555 | 2016-05-25 17:09:07 +0000 | [diff] [blame] | 488 | return Error::success(); | 
|  | 489 | } | 
|  | 490 |  | 
| Chris Bieneman | 93e7119 | 2016-06-24 20:42:28 +0000 | [diff] [blame] | 491 | class UniversalWriter { | 
|  | 492 | public: | 
| Chris Bieneman | 8ff0c11 | 2016-06-27 19:53:53 +0000 | [diff] [blame] | 493 | UniversalWriter(yaml::YamlObjectFile &ObjectFile) | 
|  | 494 | : ObjectFile(ObjectFile), fileStart(0) {} | 
| Chris Bieneman | 93e7119 | 2016-06-24 20:42:28 +0000 | [diff] [blame] | 495 |  | 
|  | 496 | Error writeMachO(raw_ostream &OS); | 
|  | 497 |  | 
|  | 498 | private: | 
|  | 499 | Error writeFatHeader(raw_ostream &OS); | 
|  | 500 | Error writeFatArchs(raw_ostream &OS); | 
|  | 501 |  | 
|  | 502 | void ZeroToOffset(raw_ostream &OS, size_t offset); | 
|  | 503 |  | 
| Chris Bieneman | 8ff0c11 | 2016-06-27 19:53:53 +0000 | [diff] [blame] | 504 | yaml::YamlObjectFile &ObjectFile; | 
| Chris Bieneman | 93e7119 | 2016-06-24 20:42:28 +0000 | [diff] [blame] | 505 | uint64_t fileStart; | 
|  | 506 | }; | 
|  | 507 |  | 
|  | 508 | Error UniversalWriter::writeMachO(raw_ostream &OS) { | 
|  | 509 | fileStart = OS.tell(); | 
| Chris Bieneman | 8ff0c11 | 2016-06-27 19:53:53 +0000 | [diff] [blame] | 510 | if (ObjectFile.MachO) { | 
|  | 511 | MachOWriter Writer(*ObjectFile.MachO); | 
| Chris Bieneman | 93e7119 | 2016-06-24 20:42:28 +0000 | [diff] [blame] | 512 | return Writer.writeMachO(OS); | 
|  | 513 | } | 
|  | 514 | if (auto Err = writeFatHeader(OS)) | 
|  | 515 | return Err; | 
|  | 516 | if (auto Err = writeFatArchs(OS)) | 
|  | 517 | return Err; | 
| Chris Bieneman | 8ff0c11 | 2016-06-27 19:53:53 +0000 | [diff] [blame] | 518 | auto &FatFile = *ObjectFile.FatMachO; | 
| Chris Bieneman | 93e7119 | 2016-06-24 20:42:28 +0000 | [diff] [blame] | 519 | assert(FatFile.FatArchs.size() == FatFile.Slices.size()); | 
|  | 520 | for (size_t i = 0; i < FatFile.Slices.size(); i++) { | 
|  | 521 | ZeroToOffset(OS, FatFile.FatArchs[i].offset); | 
|  | 522 | MachOWriter Writer(FatFile.Slices[i]); | 
|  | 523 | if (auto Err = Writer.writeMachO(OS)) | 
|  | 524 | return Err; | 
|  | 525 | auto SliceEnd = FatFile.FatArchs[i].offset + FatFile.FatArchs[i].size; | 
|  | 526 | ZeroToOffset(OS, SliceEnd); | 
|  | 527 | } | 
|  | 528 | return Error::success(); | 
|  | 529 | } | 
|  | 530 |  | 
|  | 531 | Error UniversalWriter::writeFatHeader(raw_ostream &OS) { | 
| Chris Bieneman | 8ff0c11 | 2016-06-27 19:53:53 +0000 | [diff] [blame] | 532 | auto &FatFile = *ObjectFile.FatMachO; | 
| Chris Bieneman | 93e7119 | 2016-06-24 20:42:28 +0000 | [diff] [blame] | 533 | MachO::fat_header header; | 
|  | 534 | header.magic = FatFile.Header.magic; | 
|  | 535 | header.nfat_arch = FatFile.Header.nfat_arch; | 
|  | 536 | if (sys::IsLittleEndianHost) | 
|  | 537 | swapStruct(header); | 
|  | 538 | OS.write(reinterpret_cast<const char *>(&header), sizeof(MachO::fat_header)); | 
|  | 539 | return Error::success(); | 
|  | 540 | } | 
|  | 541 |  | 
|  | 542 | template <typename FatArchType> | 
|  | 543 | FatArchType constructFatArch(MachOYAML::FatArch &Arch) { | 
|  | 544 | FatArchType FatArch; | 
|  | 545 | FatArch.cputype = Arch.cputype; | 
|  | 546 | FatArch.cpusubtype = Arch.cpusubtype; | 
|  | 547 | FatArch.offset = Arch.offset; | 
|  | 548 | FatArch.size = Arch.size; | 
|  | 549 | FatArch.align = Arch.align; | 
|  | 550 | return FatArch; | 
|  | 551 | } | 
|  | 552 |  | 
|  | 553 | template <typename StructType> | 
|  | 554 | void writeFatArch(MachOYAML::FatArch &LC, raw_ostream &OS) {} | 
|  | 555 |  | 
|  | 556 | template <> | 
|  | 557 | void writeFatArch<MachO::fat_arch>(MachOYAML::FatArch &Arch, raw_ostream &OS) { | 
|  | 558 | auto FatArch = constructFatArch<MachO::fat_arch>(Arch); | 
|  | 559 | if (sys::IsLittleEndianHost) | 
|  | 560 | swapStruct(FatArch); | 
|  | 561 | OS.write(reinterpret_cast<const char *>(&FatArch), sizeof(MachO::fat_arch)); | 
|  | 562 | } | 
|  | 563 |  | 
|  | 564 | template <> | 
|  | 565 | void writeFatArch<MachO::fat_arch_64>(MachOYAML::FatArch &Arch, | 
|  | 566 | raw_ostream &OS) { | 
|  | 567 | auto FatArch = constructFatArch<MachO::fat_arch_64>(Arch); | 
|  | 568 | FatArch.reserved = Arch.reserved; | 
|  | 569 | if (sys::IsLittleEndianHost) | 
|  | 570 | swapStruct(FatArch); | 
|  | 571 | OS.write(reinterpret_cast<const char *>(&FatArch), | 
|  | 572 | sizeof(MachO::fat_arch_64)); | 
|  | 573 | } | 
|  | 574 |  | 
|  | 575 | Error UniversalWriter::writeFatArchs(raw_ostream &OS) { | 
| Chris Bieneman | 8ff0c11 | 2016-06-27 19:53:53 +0000 | [diff] [blame] | 576 | auto &FatFile = *ObjectFile.FatMachO; | 
| Chris Bieneman | 93e7119 | 2016-06-24 20:42:28 +0000 | [diff] [blame] | 577 | bool is64Bit = FatFile.Header.magic == MachO::FAT_MAGIC_64; | 
|  | 578 | for (auto Arch : FatFile.FatArchs) { | 
|  | 579 | if (is64Bit) | 
|  | 580 | writeFatArch<MachO::fat_arch_64>(Arch, OS); | 
|  | 581 | else | 
|  | 582 | writeFatArch<MachO::fat_arch>(Arch, OS); | 
|  | 583 | } | 
|  | 584 |  | 
|  | 585 | return Error::success(); | 
|  | 586 | } | 
|  | 587 |  | 
|  | 588 | void UniversalWriter::ZeroToOffset(raw_ostream &OS, size_t Offset) { | 
|  | 589 | auto currOffset = OS.tell() - fileStart; | 
|  | 590 | if (currOffset < Offset) | 
|  | 591 | ZeroFillBytes(OS, Offset - currOffset); | 
|  | 592 | } | 
|  | 593 |  | 
| Chris Bieneman | a23b26f | 2016-05-12 17:44:48 +0000 | [diff] [blame] | 594 | } // end anonymous namespace | 
|  | 595 |  | 
| Alex Brachet | c22d966 | 2019-08-07 02:44:49 +0000 | [diff] [blame] | 596 | namespace llvm { | 
|  | 597 | namespace yaml { | 
|  | 598 |  | 
|  | 599 | int yaml2macho(YamlObjectFile &Doc, raw_ostream &Out) { | 
| Chris Bieneman | 93e7119 | 2016-06-24 20:42:28 +0000 | [diff] [blame] | 600 | UniversalWriter Writer(Doc); | 
| Chris Bieneman | a23b26f | 2016-05-12 17:44:48 +0000 | [diff] [blame] | 601 | if (auto Err = Writer.writeMachO(Out)) { | 
|  | 602 | errs() << toString(std::move(Err)); | 
|  | 603 | return 1; | 
|  | 604 | } | 
|  | 605 | return 0; | 
| Chris Bieneman | b83c187 | 2016-05-11 22:07:48 +0000 | [diff] [blame] | 606 | } | 
| Alex Brachet | c22d966 | 2019-08-07 02:44:49 +0000 | [diff] [blame] | 607 |  | 
|  | 608 | } // namespace yaml | 
|  | 609 | } // namespace llvm |