blob: 74200c5aa62a0b646601f0ee19b60e59367f3ece [file] [log] [blame]
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +00001//===- MachOWriter.cpp ------------------------------------------*- C++ -*-===//
2//
Chandler Carruth127252b2019-02-11 08:25:19 +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
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "MachOWriter.h"
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +000010#include "Object.h"
11#include "llvm/ADT/STLExtras.h"
12#include "llvm/BinaryFormat/MachO.h"
13#include "llvm/Object/MachO.h"
Seiya Nutab728e532019-06-08 01:22:54 +000014#include "llvm/Support/Errc.h"
15#include "llvm/Support/ErrorHandling.h"
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +000016#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 {
Seiya Nutaf923d9b2019-06-21 00:21:50 +000029 return O.SymTable.Symbols.size() *
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +000030 (Is64Bit ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist));
31}
32
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +000033size_t MachOWriter::totalSize() const {
34 // Going from tail to head and looking for an appropriate "anchor" to
35 // calculate the total size assuming that all the offsets are either valid
36 // ("true") or 0 (0 indicates that the corresponding part is missing).
37
38 SmallVector<size_t, 7> Ends;
39 if (O.SymTabCommandIndex) {
40 const MachO::symtab_command &SymTabCommand =
41 O.LoadCommands[*O.SymTabCommandIndex]
42 .MachOLoadCommand.symtab_command_data;
Seiya Nuta1e335612019-08-19 06:45:48 +000043 if (SymTabCommand.symoff) {
44 assert((SymTabCommand.nsyms == O.SymTable.Symbols.size()) &&
45 "Incorrect number of symbols");
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +000046 Ends.push_back(SymTabCommand.symoff + symTableSize());
Seiya Nuta1e335612019-08-19 06:45:48 +000047 }
48 if (SymTabCommand.stroff) {
49 assert((SymTabCommand.strsize == StrTableBuilder.getSize()) &&
50 "Incorrect string table size");
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +000051 Ends.push_back(SymTabCommand.stroff + SymTabCommand.strsize);
Seiya Nuta1e335612019-08-19 06:45:48 +000052 }
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +000053 }
54 if (O.DyLdInfoCommandIndex) {
55 const MachO::dyld_info_command &DyLdInfoCommand =
56 O.LoadCommands[*O.DyLdInfoCommandIndex]
57 .MachOLoadCommand.dyld_info_command_data;
58 if (DyLdInfoCommand.rebase_off) {
59 assert((DyLdInfoCommand.rebase_size == O.Rebases.Opcodes.size()) &&
60 "Incorrect rebase opcodes size");
61 Ends.push_back(DyLdInfoCommand.rebase_off + DyLdInfoCommand.rebase_size);
62 }
63 if (DyLdInfoCommand.bind_off) {
64 assert((DyLdInfoCommand.bind_size == O.Binds.Opcodes.size()) &&
65 "Incorrect bind opcodes size");
66 Ends.push_back(DyLdInfoCommand.bind_off + DyLdInfoCommand.bind_size);
67 }
68 if (DyLdInfoCommand.weak_bind_off) {
69 assert((DyLdInfoCommand.weak_bind_size == O.WeakBinds.Opcodes.size()) &&
70 "Incorrect weak bind opcodes size");
71 Ends.push_back(DyLdInfoCommand.weak_bind_off +
72 DyLdInfoCommand.weak_bind_size);
73 }
74 if (DyLdInfoCommand.lazy_bind_off) {
75 assert((DyLdInfoCommand.lazy_bind_size == O.LazyBinds.Opcodes.size()) &&
76 "Incorrect lazy bind opcodes size");
77 Ends.push_back(DyLdInfoCommand.lazy_bind_off +
78 DyLdInfoCommand.lazy_bind_size);
79 }
80 if (DyLdInfoCommand.export_off) {
81 assert((DyLdInfoCommand.export_size == O.Exports.Trie.size()) &&
82 "Incorrect trie size");
83 Ends.push_back(DyLdInfoCommand.export_off + DyLdInfoCommand.export_size);
84 }
85 }
86
87 // Otherwise, use the last section / reloction.
88 for (const auto &LC : O.LoadCommands)
89 for (const auto &S : LC.Sections) {
90 Ends.push_back(S.Offset + S.Size);
91 if (S.RelOff)
92 Ends.push_back(S.RelOff +
93 S.NReloc * sizeof(MachO::any_relocation_info));
94 }
95
96 if (!Ends.empty())
97 return *std::max_element(Ends.begin(), Ends.end());
98
99 // Otherwise, we have only Mach header and load commands.
100 return headerSize() + loadCommandsSize();
101}
102
103void MachOWriter::writeHeader() {
104 MachO::mach_header_64 Header;
105
106 Header.magic = O.Header.Magic;
107 Header.cputype = O.Header.CPUType;
108 Header.cpusubtype = O.Header.CPUSubType;
109 Header.filetype = O.Header.FileType;
110 Header.ncmds = O.Header.NCmds;
111 Header.sizeofcmds = O.Header.SizeOfCmds;
112 Header.flags = O.Header.Flags;
113 Header.reserved = O.Header.Reserved;
114
115 if (IsLittleEndian != sys::IsLittleEndianHost)
116 MachO::swapStruct(Header);
117
118 auto HeaderSize =
119 Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
120 memcpy(B.getBufferStart(), &Header, HeaderSize);
121}
122
Seiya Nuta1e335612019-08-19 06:45:48 +0000123void MachOWriter::updateSymbolIndexes() {
124 uint32_t Index = 0;
125 for (auto &Symbol : O.SymTable.Symbols) {
126 Symbol->Index = Index;
127 Index++;
128 }
129}
130
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000131void MachOWriter::writeLoadCommands() {
132 uint8_t *Begin = B.getBufferStart() + headerSize();
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000133 for (const auto &LC : O.LoadCommands) {
Seiya Nutab728e532019-06-08 01:22:54 +0000134 // Construct a load command.
135 MachO::macho_load_command MLC = LC.MachOLoadCommand;
136 switch (MLC.load_command_data.cmd) {
137 case MachO::LC_SEGMENT:
138 if (IsLittleEndian != sys::IsLittleEndianHost)
139 MachO::swapStruct(MLC.segment_command_data);
140 memcpy(Begin, &MLC.segment_command_data, sizeof(MachO::segment_command));
141 Begin += sizeof(MachO::segment_command);
142
143 for (const auto &Sec : LC.Sections)
144 writeSectionInLoadCommand<MachO::section>(Sec, Begin);
145 continue;
146 case MachO::LC_SEGMENT_64:
147 if (IsLittleEndian != sys::IsLittleEndianHost)
148 MachO::swapStruct(MLC.segment_command_64_data);
149 memcpy(Begin, &MLC.segment_command_64_data,
150 sizeof(MachO::segment_command_64));
151 Begin += sizeof(MachO::segment_command_64);
152
153 for (const auto &Sec : LC.Sections)
154 writeSectionInLoadCommand<MachO::section_64>(Sec, Begin);
155 continue;
156 }
157
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000158#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
159 case MachO::LCName: \
160 assert(sizeof(MachO::LCStruct) + LC.Payload.size() == \
Seiya Nutab728e532019-06-08 01:22:54 +0000161 MLC.load_command_data.cmdsize); \
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000162 if (IsLittleEndian != sys::IsLittleEndianHost) \
163 MachO::swapStruct(MLC.LCStruct##_data); \
164 memcpy(Begin, &MLC.LCStruct##_data, sizeof(MachO::LCStruct)); \
165 Begin += sizeof(MachO::LCStruct); \
166 memcpy(Begin, LC.Payload.data(), LC.Payload.size()); \
167 Begin += LC.Payload.size(); \
168 break;
169
Seiya Nutab728e532019-06-08 01:22:54 +0000170 // Copy the load command as it is.
171 switch (MLC.load_command_data.cmd) {
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000172 default:
173 assert(sizeof(MachO::load_command) + LC.Payload.size() ==
Seiya Nutab728e532019-06-08 01:22:54 +0000174 MLC.load_command_data.cmdsize);
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000175 if (IsLittleEndian != sys::IsLittleEndianHost)
176 MachO::swapStruct(MLC.load_command_data);
177 memcpy(Begin, &MLC.load_command_data, sizeof(MachO::load_command));
178 Begin += sizeof(MachO::load_command);
179 memcpy(Begin, LC.Payload.data(), LC.Payload.size());
180 Begin += LC.Payload.size();
181 break;
182#include "llvm/BinaryFormat/MachO.def"
183 }
184 }
185}
186
Seiya Nutab728e532019-06-08 01:22:54 +0000187template <typename StructType>
188void MachOWriter::writeSectionInLoadCommand(const Section &Sec, uint8_t *&Out) {
189 StructType Temp;
190 assert(Sec.Segname.size() <= sizeof(Temp.segname) && "too long segment name");
191 assert(Sec.Sectname.size() <= sizeof(Temp.sectname) &&
192 "too long section name");
193 memset(&Temp, 0, sizeof(StructType));
194 memcpy(Temp.segname, Sec.Segname.data(), Sec.Segname.size());
195 memcpy(Temp.sectname, Sec.Sectname.data(), Sec.Sectname.size());
196 Temp.addr = Sec.Addr;
197 Temp.size = Sec.Size;
198 Temp.offset = Sec.Offset;
199 Temp.align = Sec.Align;
200 Temp.reloff = Sec.RelOff;
201 Temp.nreloc = Sec.NReloc;
202 Temp.flags = Sec.Flags;
203 Temp.reserved1 = Sec.Reserved1;
204 Temp.reserved2 = Sec.Reserved2;
205
206 if (IsLittleEndian != sys::IsLittleEndianHost)
207 MachO::swapStruct(Temp);
208 memcpy(Out, &Temp, sizeof(StructType));
209 Out += sizeof(StructType);
210}
211
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000212void MachOWriter::writeSections() {
213 for (const auto &LC : O.LoadCommands)
214 for (const auto &Sec : LC.Sections) {
Seiya Nutab728e532019-06-08 01:22:54 +0000215 if (Sec.isVirtualSection())
216 continue;
217
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000218 assert(Sec.Offset && "Section offset can not be zero");
219 assert((Sec.Size == Sec.Content.size()) && "Incorrect section size");
220 memcpy(B.getBufferStart() + Sec.Offset, Sec.Content.data(),
221 Sec.Content.size());
222 for (size_t Index = 0; Index < Sec.Relocations.size(); ++Index) {
Seiya Nutaf923d9b2019-06-21 00:21:50 +0000223 auto RelocInfo = Sec.Relocations[Index];
224 if (!RelocInfo.Scattered) {
225 auto *Info =
226 reinterpret_cast<MachO::relocation_info *>(&RelocInfo.Info);
227 Info->r_symbolnum = RelocInfo.Symbol->Index;
228 }
229
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000230 if (IsLittleEndian != sys::IsLittleEndianHost)
Seiya Nutaf923d9b2019-06-21 00:21:50 +0000231 MachO::swapStruct(
232 reinterpret_cast<MachO::any_relocation_info &>(RelocInfo.Info));
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000233 memcpy(B.getBufferStart() + Sec.RelOff +
234 Index * sizeof(MachO::any_relocation_info),
Seiya Nutaf923d9b2019-06-21 00:21:50 +0000235 &RelocInfo.Info, sizeof(RelocInfo.Info));
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000236 }
237 }
238}
239
240template <typename NListType>
Seiya Nutaf923d9b2019-06-21 00:21:50 +0000241void writeNListEntry(const SymbolEntry &SE, bool IsLittleEndian, char *&Out,
242 uint32_t Nstrx) {
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000243 NListType ListEntry;
Seiya Nutaf923d9b2019-06-21 00:21:50 +0000244 ListEntry.n_strx = Nstrx;
245 ListEntry.n_type = SE.n_type;
246 ListEntry.n_sect = SE.n_sect;
247 ListEntry.n_desc = SE.n_desc;
248 ListEntry.n_value = SE.n_value;
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000249
250 if (IsLittleEndian != sys::IsLittleEndianHost)
251 MachO::swapStruct(ListEntry);
252 memcpy(Out, reinterpret_cast<const char *>(&ListEntry), sizeof(NListType));
253 Out += sizeof(NListType);
254}
255
256void MachOWriter::writeSymbolTable() {
257 if (!O.SymTabCommandIndex)
258 return;
259 const MachO::symtab_command &SymTabCommand =
260 O.LoadCommands[*O.SymTabCommandIndex]
261 .MachOLoadCommand.symtab_command_data;
Seiya Nutaf923d9b2019-06-21 00:21:50 +0000262
263 uint8_t *StrTable = (uint8_t *)B.getBufferStart() + SymTabCommand.stroff;
Seiya Nuta1e335612019-08-19 06:45:48 +0000264 StrTableBuilder.write(StrTable);
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000265}
266
267void MachOWriter::writeStringTable() {
268 if (!O.SymTabCommandIndex)
269 return;
270 const MachO::symtab_command &SymTabCommand =
271 O.LoadCommands[*O.SymTabCommandIndex]
272 .MachOLoadCommand.symtab_command_data;
Seiya Nutaf923d9b2019-06-21 00:21:50 +0000273
274 char *SymTable = (char *)B.getBufferStart() + SymTabCommand.symoff;
275 for (auto Iter = O.SymTable.Symbols.begin(), End = O.SymTable.Symbols.end();
276 Iter != End; Iter++) {
277 SymbolEntry *Sym = Iter->get();
Seiya Nuta1e335612019-08-19 06:45:48 +0000278 auto Nstrx = StrTableBuilder.getOffset(Sym->Name);
Seiya Nutaf923d9b2019-06-21 00:21:50 +0000279
280 if (Is64Bit)
281 writeNListEntry<MachO::nlist_64>(*Sym, IsLittleEndian, SymTable, Nstrx);
282 else
283 writeNListEntry<MachO::nlist>(*Sym, IsLittleEndian, SymTable, Nstrx);
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000284 }
285}
286
287void MachOWriter::writeRebaseInfo() {
288 if (!O.DyLdInfoCommandIndex)
289 return;
290 const MachO::dyld_info_command &DyLdInfoCommand =
291 O.LoadCommands[*O.DyLdInfoCommandIndex]
292 .MachOLoadCommand.dyld_info_command_data;
293 char *Out = (char *)B.getBufferStart() + DyLdInfoCommand.rebase_off;
294 assert((DyLdInfoCommand.rebase_size == O.Rebases.Opcodes.size()) &&
295 "Incorrect rebase opcodes size");
296 memcpy(Out, O.Rebases.Opcodes.data(), O.Rebases.Opcodes.size());
297}
298
299void MachOWriter::writeBindInfo() {
300 if (!O.DyLdInfoCommandIndex)
301 return;
302 const MachO::dyld_info_command &DyLdInfoCommand =
303 O.LoadCommands[*O.DyLdInfoCommandIndex]
304 .MachOLoadCommand.dyld_info_command_data;
305 char *Out = (char *)B.getBufferStart() + DyLdInfoCommand.bind_off;
306 assert((DyLdInfoCommand.bind_size == O.Binds.Opcodes.size()) &&
307 "Incorrect bind opcodes size");
308 memcpy(Out, O.Binds.Opcodes.data(), O.Binds.Opcodes.size());
309}
310
311void MachOWriter::writeWeakBindInfo() {
312 if (!O.DyLdInfoCommandIndex)
313 return;
314 const MachO::dyld_info_command &DyLdInfoCommand =
315 O.LoadCommands[*O.DyLdInfoCommandIndex]
316 .MachOLoadCommand.dyld_info_command_data;
317 char *Out = (char *)B.getBufferStart() + DyLdInfoCommand.weak_bind_off;
318 assert((DyLdInfoCommand.weak_bind_size == O.WeakBinds.Opcodes.size()) &&
319 "Incorrect weak bind opcodes size");
320 memcpy(Out, O.WeakBinds.Opcodes.data(), O.WeakBinds.Opcodes.size());
321}
322
323void MachOWriter::writeLazyBindInfo() {
324 if (!O.DyLdInfoCommandIndex)
325 return;
326 const MachO::dyld_info_command &DyLdInfoCommand =
327 O.LoadCommands[*O.DyLdInfoCommandIndex]
328 .MachOLoadCommand.dyld_info_command_data;
329 char *Out = (char *)B.getBufferStart() + DyLdInfoCommand.lazy_bind_off;
330 assert((DyLdInfoCommand.lazy_bind_size == O.LazyBinds.Opcodes.size()) &&
331 "Incorrect lazy bind opcodes size");
332 memcpy(Out, O.LazyBinds.Opcodes.data(), O.LazyBinds.Opcodes.size());
333}
334
335void MachOWriter::writeExportInfo() {
336 if (!O.DyLdInfoCommandIndex)
337 return;
338 const MachO::dyld_info_command &DyLdInfoCommand =
339 O.LoadCommands[*O.DyLdInfoCommandIndex]
340 .MachOLoadCommand.dyld_info_command_data;
341 char *Out = (char *)B.getBufferStart() + DyLdInfoCommand.export_off;
342 assert((DyLdInfoCommand.export_size == O.Exports.Trie.size()) &&
343 "Incorrect export trie size");
344 memcpy(Out, O.Exports.Trie.data(), O.Exports.Trie.size());
345}
346
347void MachOWriter::writeTail() {
348 typedef void (MachOWriter::*WriteHandlerType)(void);
349 typedef std::pair<uint64_t, WriteHandlerType> WriteOperation;
350 SmallVector<WriteOperation, 7> Queue;
351
352 if (O.SymTabCommandIndex) {
353 const MachO::symtab_command &SymTabCommand =
354 O.LoadCommands[*O.SymTabCommandIndex]
355 .MachOLoadCommand.symtab_command_data;
356 if (SymTabCommand.symoff)
357 Queue.push_back({SymTabCommand.symoff, &MachOWriter::writeSymbolTable});
358 if (SymTabCommand.stroff)
359 Queue.push_back({SymTabCommand.stroff, &MachOWriter::writeStringTable});
360 }
361
362 if (O.DyLdInfoCommandIndex) {
363 const MachO::dyld_info_command &DyLdInfoCommand =
364 O.LoadCommands[*O.DyLdInfoCommandIndex]
365 .MachOLoadCommand.dyld_info_command_data;
366 if (DyLdInfoCommand.rebase_off)
367 Queue.push_back(
368 {DyLdInfoCommand.rebase_off, &MachOWriter::writeRebaseInfo});
369 if (DyLdInfoCommand.bind_off)
370 Queue.push_back({DyLdInfoCommand.bind_off, &MachOWriter::writeBindInfo});
371 if (DyLdInfoCommand.weak_bind_off)
372 Queue.push_back(
373 {DyLdInfoCommand.weak_bind_off, &MachOWriter::writeWeakBindInfo});
374 if (DyLdInfoCommand.lazy_bind_off)
375 Queue.push_back(
376 {DyLdInfoCommand.lazy_bind_off, &MachOWriter::writeLazyBindInfo});
377 if (DyLdInfoCommand.export_off)
378 Queue.push_back(
379 {DyLdInfoCommand.export_off, &MachOWriter::writeExportInfo});
380 }
381
382 llvm::sort(Queue, [](const WriteOperation &LHS, const WriteOperation &RHS) {
383 return LHS.first < RHS.first;
384 });
385
386 for (auto WriteOp : Queue)
387 (this->*WriteOp.second)();
388}
389
Seiya Nuta1e335612019-08-19 06:45:48 +0000390void MachOWriter::updateSizeOfCmds() {
391 auto Size = 0;
392 for (const auto &LC : O.LoadCommands) {
393 auto &MLC = LC.MachOLoadCommand;
394 auto cmd = MLC.load_command_data.cmd;
395
396 switch (cmd) {
397 case MachO::LC_SEGMENT:
398 Size += sizeof(MachO::segment_command) +
399 sizeof(MachO::section) * LC.Sections.size();
400 continue;
401 case MachO::LC_SEGMENT_64:
402 Size += sizeof(MachO::segment_command_64) +
403 sizeof(MachO::section_64) * LC.Sections.size();
404 continue;
405 }
406
407 switch (cmd) {
408#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
409 case MachO::LCName: \
410 Size += sizeof(MachO::LCStruct); \
411 break;
412#include "llvm/BinaryFormat/MachO.def"
413#undef HANDLE_LOAD_COMMAND
414 }
415 }
416
417 O.Header.SizeOfCmds = Size;
418}
419
420// Updates the index and the number of local/external/undefined symbols. Here we
421// assume that MLC is a LC_DYSYMTAB and the nlist entries in the symbol table
422// are already sorted by the those types.
423void MachOWriter::updateDySymTab(MachO::macho_load_command &MLC) {
424 uint32_t NumLocalSymbols = 0;
425 auto Iter = O.SymTable.Symbols.begin();
426 auto End = O.SymTable.Symbols.end();
427 for (; Iter != End; Iter++) {
428 if ((*Iter)->n_type & (MachO::N_EXT | MachO::N_PEXT))
429 break;
430
431 NumLocalSymbols++;
432 }
433
434 uint32_t NumExtDefSymbols = 0;
435 for (; Iter != End; Iter++) {
436 if (((*Iter)->n_type & MachO::N_TYPE) == MachO::N_UNDF)
437 break;
438
439 NumExtDefSymbols++;
440 }
441
442 MLC.dysymtab_command_data.ilocalsym = 0;
443 MLC.dysymtab_command_data.nlocalsym = NumLocalSymbols;
444 MLC.dysymtab_command_data.iextdefsym = NumLocalSymbols;
445 MLC.dysymtab_command_data.nextdefsym = NumExtDefSymbols;
446 MLC.dysymtab_command_data.iundefsym = NumLocalSymbols + NumExtDefSymbols;
447 MLC.dysymtab_command_data.nundefsym =
448 O.SymTable.Symbols.size() - (NumLocalSymbols + NumExtDefSymbols);
449}
450
451// Recomputes and updates offset and size fields in load commands and sections
452// since they could be modified.
453Error MachOWriter::layout() {
454 auto SizeOfCmds = loadCommandsSize();
455 auto Offset = headerSize() + SizeOfCmds;
456 O.Header.NCmds = O.LoadCommands.size();
457 O.Header.SizeOfCmds = SizeOfCmds;
458
459 // Lay out sections.
460 for (auto &LC : O.LoadCommands) {
461 uint64_t FileOff = Offset;
462 uint64_t VMSize = 0;
463 uint64_t FileOffsetInSegment = 0;
464 for (auto &Sec : LC.Sections) {
465 if (!Sec.isVirtualSection()) {
466 auto FilePaddingSize =
467 OffsetToAlignment(FileOffsetInSegment, 1ull << Sec.Align);
468 Sec.Offset = Offset + FileOffsetInSegment + FilePaddingSize;
469 Sec.Size = Sec.Content.size();
470 FileOffsetInSegment += FilePaddingSize + Sec.Size;
471 }
472
473 VMSize = std::max(VMSize, Sec.Addr + Sec.Size);
474 }
475
476 // TODO: Handle the __PAGEZERO segment.
477 auto &MLC = LC.MachOLoadCommand;
478 switch (MLC.load_command_data.cmd) {
479 case MachO::LC_SEGMENT:
480 MLC.segment_command_data.cmdsize =
481 sizeof(MachO::segment_command) +
482 sizeof(MachO::section) * LC.Sections.size();
483 MLC.segment_command_data.nsects = LC.Sections.size();
484 MLC.segment_command_data.fileoff = FileOff;
485 MLC.segment_command_data.vmsize = VMSize;
486 MLC.segment_command_data.filesize = FileOffsetInSegment;
487 break;
488 case MachO::LC_SEGMENT_64:
489 MLC.segment_command_64_data.cmdsize =
490 sizeof(MachO::segment_command_64) +
491 sizeof(MachO::section_64) * LC.Sections.size();
492 MLC.segment_command_64_data.nsects = LC.Sections.size();
493 MLC.segment_command_64_data.fileoff = FileOff;
494 MLC.segment_command_64_data.vmsize = VMSize;
495 MLC.segment_command_64_data.filesize = FileOffsetInSegment;
496 break;
497 }
498
499 Offset += FileOffsetInSegment;
500 }
501
502 // Lay out relocations.
503 for (auto &LC : O.LoadCommands)
504 for (auto &Sec : LC.Sections) {
505 Sec.RelOff = Sec.Relocations.empty() ? 0 : Offset;
506 Sec.NReloc = Sec.Relocations.size();
507 Offset += sizeof(MachO::any_relocation_info) * Sec.NReloc;
508 }
509
510 // Lay out tail stuff.
511 auto NListSize = Is64Bit ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist);
512 for (auto &LC : O.LoadCommands) {
513 auto &MLC = LC.MachOLoadCommand;
514 auto cmd = MLC.load_command_data.cmd;
515 switch (cmd) {
516 case MachO::LC_SYMTAB:
517 MLC.symtab_command_data.nsyms = O.SymTable.Symbols.size();
518 MLC.symtab_command_data.strsize = StrTableBuilder.getSize();
519 MLC.symtab_command_data.symoff = Offset;
520 Offset += NListSize * MLC.symtab_command_data.nsyms;
521 MLC.symtab_command_data.stroff = Offset;
522 Offset += MLC.symtab_command_data.strsize;
523 break;
524 case MachO::LC_DYSYMTAB: {
525 if (MLC.dysymtab_command_data.ntoc != 0 ||
526 MLC.dysymtab_command_data.nmodtab != 0 ||
527 MLC.dysymtab_command_data.nextrefsyms != 0 ||
528 MLC.dysymtab_command_data.nlocrel != 0 ||
529 MLC.dysymtab_command_data.nextrel != 0)
530 return createStringError(llvm::errc::not_supported,
531 "shared library is not yet supported");
532
533 if (MLC.dysymtab_command_data.nindirectsyms != 0)
534 return createStringError(llvm::errc::not_supported,
535 "indirect symbol table is not yet supported");
536
537 updateDySymTab(MLC);
538 break;
539 }
540 case MachO::LC_SEGMENT:
541 case MachO::LC_SEGMENT_64:
542 case MachO::LC_VERSION_MIN_MACOSX:
543 case MachO::LC_BUILD_VERSION:
544 case MachO::LC_ID_DYLIB:
545 case MachO::LC_LOAD_DYLIB:
546 case MachO::LC_UUID:
547 case MachO::LC_SOURCE_VERSION:
548 // Nothing to update.
549 break;
550 default:
551 // Abort if it's unsupported in order to prevent corrupting the object.
552 return createStringError(llvm::errc::not_supported,
553 "unsupported load command (cmd=0x%x)", cmd);
554 }
555 }
556
557 return Error::success();
558}
559
560void MachOWriter::constructStringTable() {
561 for (std::unique_ptr<SymbolEntry> &Sym : O.SymTable.Symbols)
562 StrTableBuilder.add(Sym->Name);
563 StrTableBuilder.finalize();
564}
565
566Error MachOWriter::finalize() {
567 updateSizeOfCmds();
568 constructStringTable();
569
570 if (auto E = layout())
571 return E;
572
573 return Error::success();
574}
Seiya Nutab728e532019-06-08 01:22:54 +0000575
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000576Error MachOWriter::write() {
577 if (Error E = B.allocate(totalSize()))
578 return E;
579 memset(B.getBufferStart(), 0, totalSize());
580 writeHeader();
Seiya Nuta1e335612019-08-19 06:45:48 +0000581 updateSymbolIndexes();
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000582 writeLoadCommands();
583 writeSections();
584 writeTail();
Jordan Rupprecht2e862c72019-02-04 19:09:20 +0000585 return B.commit();
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000586}
587
588} // end namespace macho
589} // end namespace objcopy
590} // end namespace llvm