blob: 09e8530e8452822e69b4df94434c1b8f35ef35b7 [file] [log] [blame]
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +00001//===- MachOWriter.cpp ------------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "MachOWriter.h"
11#include "../llvm-objcopy.h"
12#include "Object.h"
13#include "llvm/ADT/STLExtras.h"
14#include "llvm/BinaryFormat/MachO.h"
15#include "llvm/Object/MachO.h"
16#include <memory>
17
18namespace llvm {
19namespace objcopy {
20namespace macho {
21
22size_t MachOWriter::headerSize() const {
23 return Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
24}
25
26size_t MachOWriter::loadCommandsSize() const { return O.Header.SizeOfCmds; }
27
28size_t MachOWriter::symTableSize() const {
29 return O.SymTable.NameList.size() *
30 (Is64Bit ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist));
31}
32
33size_t MachOWriter::strTableSize() const {
34 size_t S = 0;
35 for (const auto &Str : O.StrTable.Strings)
36 S += Str.size();
37 S += (O.StrTable.Strings.empty() ? 0 : O.StrTable.Strings.size() - 1);
38 return S;
39}
40
41size_t MachOWriter::totalSize() const {
42 // Going from tail to head and looking for an appropriate "anchor" to
43 // calculate the total size assuming that all the offsets are either valid
44 // ("true") or 0 (0 indicates that the corresponding part is missing).
45
46 SmallVector<size_t, 7> Ends;
47 if (O.SymTabCommandIndex) {
48 const MachO::symtab_command &SymTabCommand =
49 O.LoadCommands[*O.SymTabCommandIndex]
50 .MachOLoadCommand.symtab_command_data;
51 if (SymTabCommand.symoff) {
52 assert((SymTabCommand.nsyms == O.SymTable.NameList.size()) &&
53 "Incorrect number of symbols");
54 Ends.push_back(SymTabCommand.symoff + symTableSize());
55 }
56 if (SymTabCommand.stroff) {
57 assert((SymTabCommand.strsize == strTableSize()) &&
58 "Incorrect string table size");
59 Ends.push_back(SymTabCommand.stroff + SymTabCommand.strsize);
60 }
61 }
62 if (O.DyLdInfoCommandIndex) {
63 const MachO::dyld_info_command &DyLdInfoCommand =
64 O.LoadCommands[*O.DyLdInfoCommandIndex]
65 .MachOLoadCommand.dyld_info_command_data;
66 if (DyLdInfoCommand.rebase_off) {
67 assert((DyLdInfoCommand.rebase_size == O.Rebases.Opcodes.size()) &&
68 "Incorrect rebase opcodes size");
69 Ends.push_back(DyLdInfoCommand.rebase_off + DyLdInfoCommand.rebase_size);
70 }
71 if (DyLdInfoCommand.bind_off) {
72 assert((DyLdInfoCommand.bind_size == O.Binds.Opcodes.size()) &&
73 "Incorrect bind opcodes size");
74 Ends.push_back(DyLdInfoCommand.bind_off + DyLdInfoCommand.bind_size);
75 }
76 if (DyLdInfoCommand.weak_bind_off) {
77 assert((DyLdInfoCommand.weak_bind_size == O.WeakBinds.Opcodes.size()) &&
78 "Incorrect weak bind opcodes size");
79 Ends.push_back(DyLdInfoCommand.weak_bind_off +
80 DyLdInfoCommand.weak_bind_size);
81 }
82 if (DyLdInfoCommand.lazy_bind_off) {
83 assert((DyLdInfoCommand.lazy_bind_size == O.LazyBinds.Opcodes.size()) &&
84 "Incorrect lazy bind opcodes size");
85 Ends.push_back(DyLdInfoCommand.lazy_bind_off +
86 DyLdInfoCommand.lazy_bind_size);
87 }
88 if (DyLdInfoCommand.export_off) {
89 assert((DyLdInfoCommand.export_size == O.Exports.Trie.size()) &&
90 "Incorrect trie size");
91 Ends.push_back(DyLdInfoCommand.export_off + DyLdInfoCommand.export_size);
92 }
93 }
94
95 // Otherwise, use the last section / reloction.
96 for (const auto &LC : O.LoadCommands)
97 for (const auto &S : LC.Sections) {
98 Ends.push_back(S.Offset + S.Size);
99 if (S.RelOff)
100 Ends.push_back(S.RelOff +
101 S.NReloc * sizeof(MachO::any_relocation_info));
102 }
103
104 if (!Ends.empty())
105 return *std::max_element(Ends.begin(), Ends.end());
106
107 // Otherwise, we have only Mach header and load commands.
108 return headerSize() + loadCommandsSize();
109}
110
111void MachOWriter::writeHeader() {
112 MachO::mach_header_64 Header;
113
114 Header.magic = O.Header.Magic;
115 Header.cputype = O.Header.CPUType;
116 Header.cpusubtype = O.Header.CPUSubType;
117 Header.filetype = O.Header.FileType;
118 Header.ncmds = O.Header.NCmds;
119 Header.sizeofcmds = O.Header.SizeOfCmds;
120 Header.flags = O.Header.Flags;
121 Header.reserved = O.Header.Reserved;
122
123 if (IsLittleEndian != sys::IsLittleEndianHost)
124 MachO::swapStruct(Header);
125
126 auto HeaderSize =
127 Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
128 memcpy(B.getBufferStart(), &Header, HeaderSize);
129}
130
131void MachOWriter::writeLoadCommands() {
132 uint8_t *Begin = B.getBufferStart() + headerSize();
133 MachO::macho_load_command MLC;
134 for (const auto &LC : O.LoadCommands) {
135#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
136 case MachO::LCName: \
137 assert(sizeof(MachO::LCStruct) + LC.Payload.size() == \
138 LC.MachOLoadCommand.load_command_data.cmdsize); \
139 MLC = LC.MachOLoadCommand; \
140 if (IsLittleEndian != sys::IsLittleEndianHost) \
141 MachO::swapStruct(MLC.LCStruct##_data); \
142 memcpy(Begin, &MLC.LCStruct##_data, sizeof(MachO::LCStruct)); \
143 Begin += sizeof(MachO::LCStruct); \
144 memcpy(Begin, LC.Payload.data(), LC.Payload.size()); \
145 Begin += LC.Payload.size(); \
146 break;
147
148 switch (LC.MachOLoadCommand.load_command_data.cmd) {
149 default:
150 assert(sizeof(MachO::load_command) + LC.Payload.size() ==
151 LC.MachOLoadCommand.load_command_data.cmdsize);
152 MLC = LC.MachOLoadCommand;
153 if (IsLittleEndian != sys::IsLittleEndianHost)
154 MachO::swapStruct(MLC.load_command_data);
155 memcpy(Begin, &MLC.load_command_data, sizeof(MachO::load_command));
156 Begin += sizeof(MachO::load_command);
157 memcpy(Begin, LC.Payload.data(), LC.Payload.size());
158 Begin += LC.Payload.size();
159 break;
160#include "llvm/BinaryFormat/MachO.def"
161 }
162 }
163}
164
165void MachOWriter::writeSections() {
166 for (const auto &LC : O.LoadCommands)
167 for (const auto &Sec : LC.Sections) {
168 assert(Sec.Offset && "Section offset can not be zero");
169 assert((Sec.Size == Sec.Content.size()) && "Incorrect section size");
170 memcpy(B.getBufferStart() + Sec.Offset, Sec.Content.data(),
171 Sec.Content.size());
172 for (size_t Index = 0; Index < Sec.Relocations.size(); ++Index) {
173 MachO::any_relocation_info R = Sec.Relocations[Index];
174 if (IsLittleEndian != sys::IsLittleEndianHost)
175 MachO::swapStruct(R);
176 memcpy(B.getBufferStart() + Sec.RelOff +
177 Index * sizeof(MachO::any_relocation_info),
178 &R, sizeof(R));
179 }
180 }
181}
182
183template <typename NListType>
184void writeNListEntry(const NListEntry &NLE, bool IsLittleEndian, char *&Out) {
185 NListType ListEntry;
186 ListEntry.n_strx = NLE.n_strx;
187 ListEntry.n_type = NLE.n_type;
188 ListEntry.n_sect = NLE.n_sect;
189 ListEntry.n_desc = NLE.n_desc;
190 ListEntry.n_value = NLE.n_value;
191
192 if (IsLittleEndian != sys::IsLittleEndianHost)
193 MachO::swapStruct(ListEntry);
194 memcpy(Out, reinterpret_cast<const char *>(&ListEntry), sizeof(NListType));
195 Out += sizeof(NListType);
196}
197
198void MachOWriter::writeSymbolTable() {
199 if (!O.SymTabCommandIndex)
200 return;
201 const MachO::symtab_command &SymTabCommand =
202 O.LoadCommands[*O.SymTabCommandIndex]
203 .MachOLoadCommand.symtab_command_data;
204 assert((SymTabCommand.nsyms == O.SymTable.NameList.size()) &&
205 "Incorrect number of symbols");
206 char *Out = (char *)B.getBufferStart() + SymTabCommand.symoff;
207 for (auto NLE : O.SymTable.NameList) {
208 if (Is64Bit)
209 writeNListEntry<MachO::nlist_64>(NLE, IsLittleEndian, Out);
210 else
211 writeNListEntry<MachO::nlist>(NLE, IsLittleEndian, Out);
212 }
213}
214
215void MachOWriter::writeStringTable() {
216 if (!O.SymTabCommandIndex)
217 return;
218 const MachO::symtab_command &SymTabCommand =
219 O.LoadCommands[*O.SymTabCommandIndex]
220 .MachOLoadCommand.symtab_command_data;
221 char *Out = (char *)B.getBufferStart() + SymTabCommand.stroff;
222 assert((SymTabCommand.strsize == strTableSize()) &&
223 "Incorrect string table size");
224 for (size_t Index = 0; Index < O.StrTable.Strings.size(); ++Index) {
225 memcpy(Out, O.StrTable.Strings[Index].data(),
226 O.StrTable.Strings[Index].size());
227 Out += O.StrTable.Strings[Index].size();
228 if (Index + 1 != O.StrTable.Strings.size()) {
229 memcpy(Out, "\0", 1);
230 Out += 1;
231 }
232 }
233}
234
235void MachOWriter::writeRebaseInfo() {
236 if (!O.DyLdInfoCommandIndex)
237 return;
238 const MachO::dyld_info_command &DyLdInfoCommand =
239 O.LoadCommands[*O.DyLdInfoCommandIndex]
240 .MachOLoadCommand.dyld_info_command_data;
241 char *Out = (char *)B.getBufferStart() + DyLdInfoCommand.rebase_off;
242 assert((DyLdInfoCommand.rebase_size == O.Rebases.Opcodes.size()) &&
243 "Incorrect rebase opcodes size");
244 memcpy(Out, O.Rebases.Opcodes.data(), O.Rebases.Opcodes.size());
245}
246
247void MachOWriter::writeBindInfo() {
248 if (!O.DyLdInfoCommandIndex)
249 return;
250 const MachO::dyld_info_command &DyLdInfoCommand =
251 O.LoadCommands[*O.DyLdInfoCommandIndex]
252 .MachOLoadCommand.dyld_info_command_data;
253 char *Out = (char *)B.getBufferStart() + DyLdInfoCommand.bind_off;
254 assert((DyLdInfoCommand.bind_size == O.Binds.Opcodes.size()) &&
255 "Incorrect bind opcodes size");
256 memcpy(Out, O.Binds.Opcodes.data(), O.Binds.Opcodes.size());
257}
258
259void MachOWriter::writeWeakBindInfo() {
260 if (!O.DyLdInfoCommandIndex)
261 return;
262 const MachO::dyld_info_command &DyLdInfoCommand =
263 O.LoadCommands[*O.DyLdInfoCommandIndex]
264 .MachOLoadCommand.dyld_info_command_data;
265 char *Out = (char *)B.getBufferStart() + DyLdInfoCommand.weak_bind_off;
266 assert((DyLdInfoCommand.weak_bind_size == O.WeakBinds.Opcodes.size()) &&
267 "Incorrect weak bind opcodes size");
268 memcpy(Out, O.WeakBinds.Opcodes.data(), O.WeakBinds.Opcodes.size());
269}
270
271void MachOWriter::writeLazyBindInfo() {
272 if (!O.DyLdInfoCommandIndex)
273 return;
274 const MachO::dyld_info_command &DyLdInfoCommand =
275 O.LoadCommands[*O.DyLdInfoCommandIndex]
276 .MachOLoadCommand.dyld_info_command_data;
277 char *Out = (char *)B.getBufferStart() + DyLdInfoCommand.lazy_bind_off;
278 assert((DyLdInfoCommand.lazy_bind_size == O.LazyBinds.Opcodes.size()) &&
279 "Incorrect lazy bind opcodes size");
280 memcpy(Out, O.LazyBinds.Opcodes.data(), O.LazyBinds.Opcodes.size());
281}
282
283void MachOWriter::writeExportInfo() {
284 if (!O.DyLdInfoCommandIndex)
285 return;
286 const MachO::dyld_info_command &DyLdInfoCommand =
287 O.LoadCommands[*O.DyLdInfoCommandIndex]
288 .MachOLoadCommand.dyld_info_command_data;
289 char *Out = (char *)B.getBufferStart() + DyLdInfoCommand.export_off;
290 assert((DyLdInfoCommand.export_size == O.Exports.Trie.size()) &&
291 "Incorrect export trie size");
292 memcpy(Out, O.Exports.Trie.data(), O.Exports.Trie.size());
293}
294
295void MachOWriter::writeTail() {
296 typedef void (MachOWriter::*WriteHandlerType)(void);
297 typedef std::pair<uint64_t, WriteHandlerType> WriteOperation;
298 SmallVector<WriteOperation, 7> Queue;
299
300 if (O.SymTabCommandIndex) {
301 const MachO::symtab_command &SymTabCommand =
302 O.LoadCommands[*O.SymTabCommandIndex]
303 .MachOLoadCommand.symtab_command_data;
304 if (SymTabCommand.symoff)
305 Queue.push_back({SymTabCommand.symoff, &MachOWriter::writeSymbolTable});
306 if (SymTabCommand.stroff)
307 Queue.push_back({SymTabCommand.stroff, &MachOWriter::writeStringTable});
308 }
309
310 if (O.DyLdInfoCommandIndex) {
311 const MachO::dyld_info_command &DyLdInfoCommand =
312 O.LoadCommands[*O.DyLdInfoCommandIndex]
313 .MachOLoadCommand.dyld_info_command_data;
314 if (DyLdInfoCommand.rebase_off)
315 Queue.push_back(
316 {DyLdInfoCommand.rebase_off, &MachOWriter::writeRebaseInfo});
317 if (DyLdInfoCommand.bind_off)
318 Queue.push_back({DyLdInfoCommand.bind_off, &MachOWriter::writeBindInfo});
319 if (DyLdInfoCommand.weak_bind_off)
320 Queue.push_back(
321 {DyLdInfoCommand.weak_bind_off, &MachOWriter::writeWeakBindInfo});
322 if (DyLdInfoCommand.lazy_bind_off)
323 Queue.push_back(
324 {DyLdInfoCommand.lazy_bind_off, &MachOWriter::writeLazyBindInfo});
325 if (DyLdInfoCommand.export_off)
326 Queue.push_back(
327 {DyLdInfoCommand.export_off, &MachOWriter::writeExportInfo});
328 }
329
330 llvm::sort(Queue, [](const WriteOperation &LHS, const WriteOperation &RHS) {
331 return LHS.first < RHS.first;
332 });
333
334 for (auto WriteOp : Queue)
335 (this->*WriteOp.second)();
336}
337
338Error MachOWriter::write() {
339 if (Error E = B.allocate(totalSize()))
340 return E;
341 memset(B.getBufferStart(), 0, totalSize());
342 writeHeader();
343 writeLoadCommands();
344 writeSections();
345 writeTail();
Jordan Rupprecht2e862c72019-02-04 19:09:20 +0000346 return B.commit();
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000347}
348
349} // end namespace macho
350} // end namespace objcopy
351} // end namespace llvm