blob: fc45bf9de804f13e02e0a8edf2671d02faf02b0e [file] [log] [blame]
Seiya Nuta552bcb82019-08-19 21:05:31 +00001//===- MachOLayoutBuilder.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 "MachOLayoutBuilder.h"
Guillaume Chateletaf11cc72019-09-12 15:20:36 +000010#include "llvm/Support/Alignment.h"
Seiya Nuta552bcb82019-08-19 21:05:31 +000011#include "llvm/Support/Errc.h"
12#include "llvm/Support/ErrorHandling.h"
13
14namespace llvm {
15namespace objcopy {
16namespace macho {
17
18uint32_t MachOLayoutBuilder::computeSizeOfCmds() const {
19 uint32_t Size = 0;
Alexander Shaposhnikovdc046c72020-02-21 13:18:36 -080020 for (const LoadCommand &LC : O.LoadCommands) {
Seiya Nuta12bd4902019-08-19 21:12:02 +000021 const MachO::macho_load_command &MLC = LC.MachOLoadCommand;
Seiya Nuta552bcb82019-08-19 21:05:31 +000022 auto cmd = MLC.load_command_data.cmd;
23 switch (cmd) {
24 case MachO::LC_SEGMENT:
25 Size += sizeof(MachO::segment_command) +
26 sizeof(MachO::section) * LC.Sections.size();
27 continue;
28 case MachO::LC_SEGMENT_64:
29 Size += sizeof(MachO::segment_command_64) +
30 sizeof(MachO::section_64) * LC.Sections.size();
31 continue;
32 }
33
34 switch (cmd) {
35#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
36 case MachO::LCName: \
37 Size += sizeof(MachO::LCStruct) + LC.Payload.size(); \
38 break;
39#include "llvm/BinaryFormat/MachO.def"
40#undef HANDLE_LOAD_COMMAND
41 }
42 }
43
44 return Size;
45}
46
47void MachOLayoutBuilder::constructStringTable() {
48 for (std::unique_ptr<SymbolEntry> &Sym : O.SymTable.Symbols)
49 StrTableBuilder.add(Sym->Name);
50 StrTableBuilder.finalize();
51}
52
53void MachOLayoutBuilder::updateSymbolIndexes() {
54 uint32_t Index = 0;
55 for (auto &Symbol : O.SymTable.Symbols)
56 Symbol->Index = Index++;
57}
58
59// Updates the index and the number of local/external/undefined symbols.
60void MachOLayoutBuilder::updateDySymTab(MachO::macho_load_command &MLC) {
61 assert(MLC.load_command_data.cmd == MachO::LC_DYSYMTAB);
62 // Make sure that nlist entries in the symbol table are sorted by the those
63 // types. The order is: local < defined external < undefined external.
64 assert(std::is_sorted(O.SymTable.Symbols.begin(), O.SymTable.Symbols.end(),
65 [](const std::unique_ptr<SymbolEntry> &A,
66 const std::unique_ptr<SymbolEntry> &B) {
Fangrui Song24200272019-11-19 17:27:25 -080067 bool AL = A->isLocalSymbol(), BL = B->isLocalSymbol();
68 if (AL != BL)
69 return AL;
70 return !AL && !A->isUndefinedSymbol() &&
71 B->isUndefinedSymbol();
Seiya Nuta552bcb82019-08-19 21:05:31 +000072 }) &&
73 "Symbols are not sorted by their types.");
74
75 uint32_t NumLocalSymbols = 0;
76 auto Iter = O.SymTable.Symbols.begin();
77 auto End = O.SymTable.Symbols.end();
78 for (; Iter != End; ++Iter) {
79 if ((*Iter)->isExternalSymbol())
80 break;
81
82 ++NumLocalSymbols;
83 }
84
85 uint32_t NumExtDefSymbols = 0;
86 for (; Iter != End; ++Iter) {
87 if ((*Iter)->isUndefinedSymbol())
88 break;
89
90 ++NumExtDefSymbols;
91 }
92
93 MLC.dysymtab_command_data.ilocalsym = 0;
94 MLC.dysymtab_command_data.nlocalsym = NumLocalSymbols;
95 MLC.dysymtab_command_data.iextdefsym = NumLocalSymbols;
96 MLC.dysymtab_command_data.nextdefsym = NumExtDefSymbols;
97 MLC.dysymtab_command_data.iundefsym = NumLocalSymbols + NumExtDefSymbols;
98 MLC.dysymtab_command_data.nundefsym =
99 O.SymTable.Symbols.size() - (NumLocalSymbols + NumExtDefSymbols);
100}
101
102// Recomputes and updates offset and size fields in load commands and sections
103// since they could be modified.
104uint64_t MachOLayoutBuilder::layoutSegments() {
105 auto HeaderSize =
106 Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
Seiya Nuta12bd4902019-08-19 21:12:02 +0000107 const bool IsObjectFile =
108 O.Header.FileType == MachO::HeaderFileType::MH_OBJECT;
109 uint64_t Offset = IsObjectFile ? (HeaderSize + O.Header.SizeOfCmds) : 0;
Alexander Shaposhnikovdc046c72020-02-21 13:18:36 -0800110 for (LoadCommand &LC : O.LoadCommands) {
Seiya Nuta552bcb82019-08-19 21:05:31 +0000111 auto &MLC = LC.MachOLoadCommand;
112 StringRef Segname;
Seiya Nuta12bd4902019-08-19 21:12:02 +0000113 uint64_t SegmentVmAddr;
114 uint64_t SegmentVmSize;
Seiya Nuta552bcb82019-08-19 21:05:31 +0000115 switch (MLC.load_command_data.cmd) {
116 case MachO::LC_SEGMENT:
Seiya Nuta12bd4902019-08-19 21:12:02 +0000117 SegmentVmAddr = MLC.segment_command_data.vmaddr;
118 SegmentVmSize = MLC.segment_command_data.vmsize;
Seiya Nuta552bcb82019-08-19 21:05:31 +0000119 Segname = StringRef(MLC.segment_command_data.segname,
120 strnlen(MLC.segment_command_data.segname,
121 sizeof(MLC.segment_command_data.segname)));
122 break;
123 case MachO::LC_SEGMENT_64:
Seiya Nuta12bd4902019-08-19 21:12:02 +0000124 SegmentVmAddr = MLC.segment_command_64_data.vmaddr;
125 SegmentVmSize = MLC.segment_command_64_data.vmsize;
Seiya Nuta552bcb82019-08-19 21:05:31 +0000126 Segname = StringRef(MLC.segment_command_64_data.segname,
127 strnlen(MLC.segment_command_64_data.segname,
128 sizeof(MLC.segment_command_64_data.segname)));
129 break;
130 default:
131 continue;
132 }
133
134 if (Segname == "__LINKEDIT") {
135 // We update the __LINKEDIT segment later (in layoutTail).
136 assert(LC.Sections.empty() && "__LINKEDIT segment has sections");
137 LinkEditLoadCommand = &MLC;
138 continue;
139 }
140
141 // Update file offsets and sizes of sections.
Seiya Nuta12bd4902019-08-19 21:12:02 +0000142 uint64_t SegOffset = Offset;
143 uint64_t SegFileSize = 0;
Seiya Nuta552bcb82019-08-19 21:05:31 +0000144 uint64_t VMSize = 0;
Alexander Shaposhnikovdc046c72020-02-21 13:18:36 -0800145 for (std::unique_ptr<Section> &Sec : LC.Sections) {
Seiya Nuta12bd4902019-08-19 21:12:02 +0000146 if (IsObjectFile) {
Alexander Shaposhnikovdc046c72020-02-21 13:18:36 -0800147 if (Sec->isVirtualSection()) {
148 Sec->Offset = 0;
Seiya Nuta12bd4902019-08-19 21:12:02 +0000149 } else {
Simon Pilgrim5a28f0a2019-08-20 10:25:57 +0000150 uint64_t PaddingSize =
Alexander Shaposhnikovdc046c72020-02-21 13:18:36 -0800151 offsetToAlignment(SegFileSize, Align(1ull << Sec->Align));
152 Sec->Offset = SegOffset + SegFileSize + PaddingSize;
153 Sec->Size = Sec->Content.size();
154 SegFileSize += PaddingSize + Sec->Size;
Seiya Nuta12bd4902019-08-19 21:12:02 +0000155 }
Alexander Shaposhnikovdc046c72020-02-21 13:18:36 -0800156 VMSize = std::max(VMSize, Sec->Addr + Sec->Size);
Seiya Nuta12bd4902019-08-19 21:12:02 +0000157 } else {
Alexander Shaposhnikovdc046c72020-02-21 13:18:36 -0800158 if (Sec->isVirtualSection()) {
159 Sec->Offset = 0;
160 VMSize += Sec->Size;
Seiya Nuta12bd4902019-08-19 21:12:02 +0000161 } else {
Alexander Shaposhnikovdc046c72020-02-21 13:18:36 -0800162 uint32_t SectOffset = Sec->Addr - SegmentVmAddr;
163 Sec->Offset = SegOffset + SectOffset;
164 Sec->Size = Sec->Content.size();
165 SegFileSize = std::max(SegFileSize, SectOffset + Sec->Size);
Seiya Nuta12bd4902019-08-19 21:12:02 +0000166 VMSize = std::max(VMSize, SegFileSize);
167 }
Seiya Nuta552bcb82019-08-19 21:05:31 +0000168 }
Seiya Nuta552bcb82019-08-19 21:05:31 +0000169 }
170
Seiya Nuta12bd4902019-08-19 21:12:02 +0000171 if (IsObjectFile) {
172 Offset += SegFileSize;
173 } else {
174 Offset = alignTo(Offset + SegFileSize, PageSize);
175 SegFileSize = alignTo(SegFileSize, PageSize);
176 // Use the original vmsize if the segment is __PAGEZERO.
177 VMSize =
178 Segname == "__PAGEZERO" ? SegmentVmSize : alignTo(VMSize, PageSize);
179 }
180
Seiya Nuta552bcb82019-08-19 21:05:31 +0000181 switch (MLC.load_command_data.cmd) {
182 case MachO::LC_SEGMENT:
183 MLC.segment_command_data.cmdsize =
184 sizeof(MachO::segment_command) +
185 sizeof(MachO::section) * LC.Sections.size();
186 MLC.segment_command_data.nsects = LC.Sections.size();
Seiya Nuta12bd4902019-08-19 21:12:02 +0000187 MLC.segment_command_data.fileoff = SegOffset;
Seiya Nuta552bcb82019-08-19 21:05:31 +0000188 MLC.segment_command_data.vmsize = VMSize;
Seiya Nuta12bd4902019-08-19 21:12:02 +0000189 MLC.segment_command_data.filesize = SegFileSize;
Seiya Nuta552bcb82019-08-19 21:05:31 +0000190 break;
191 case MachO::LC_SEGMENT_64:
192 MLC.segment_command_64_data.cmdsize =
193 sizeof(MachO::segment_command_64) +
194 sizeof(MachO::section_64) * LC.Sections.size();
195 MLC.segment_command_64_data.nsects = LC.Sections.size();
Seiya Nuta12bd4902019-08-19 21:12:02 +0000196 MLC.segment_command_64_data.fileoff = SegOffset;
Seiya Nuta552bcb82019-08-19 21:05:31 +0000197 MLC.segment_command_64_data.vmsize = VMSize;
Seiya Nuta12bd4902019-08-19 21:12:02 +0000198 MLC.segment_command_64_data.filesize = SegFileSize;
Seiya Nuta552bcb82019-08-19 21:05:31 +0000199 break;
200 }
Seiya Nuta552bcb82019-08-19 21:05:31 +0000201 }
202
203 return Offset;
204}
205
206uint64_t MachOLayoutBuilder::layoutRelocations(uint64_t Offset) {
Alexander Shaposhnikovdc046c72020-02-21 13:18:36 -0800207 for (LoadCommand &LC : O.LoadCommands)
208 for (std::unique_ptr<Section> &Sec : LC.Sections) {
209 Sec->RelOff = Sec->Relocations.empty() ? 0 : Offset;
210 Sec->NReloc = Sec->Relocations.size();
211 Offset += sizeof(MachO::any_relocation_info) * Sec->NReloc;
Seiya Nuta552bcb82019-08-19 21:05:31 +0000212 }
213
214 return Offset;
215}
216
217Error MachOLayoutBuilder::layoutTail(uint64_t Offset) {
218 // The order of LINKEDIT elements is as follows:
219 // rebase info, binding info, weak binding info, lazy binding info, export
220 // trie, data-in-code, symbol table, indirect symbol table, symbol table
221 // strings.
222 uint64_t NListSize = Is64Bit ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist);
223 uint64_t StartOfLinkEdit = Offset;
224 uint64_t StartOfRebaseInfo = StartOfLinkEdit;
225 uint64_t StartOfBindingInfo = StartOfRebaseInfo + O.Rebases.Opcodes.size();
226 uint64_t StartOfWeakBindingInfo = StartOfBindingInfo + O.Binds.Opcodes.size();
227 uint64_t StartOfLazyBindingInfo =
228 StartOfWeakBindingInfo + O.WeakBinds.Opcodes.size();
229 uint64_t StartOfExportTrie =
230 StartOfLazyBindingInfo + O.LazyBinds.Opcodes.size();
231 uint64_t StartOfFunctionStarts = StartOfExportTrie + O.Exports.Trie.size();
232 uint64_t StartOfDataInCode =
233 StartOfFunctionStarts + O.FunctionStarts.Data.size();
234 uint64_t StartOfSymbols = StartOfDataInCode + O.DataInCode.Data.size();
235 uint64_t StartOfIndirectSymbols =
236 StartOfSymbols + NListSize * O.SymTable.Symbols.size();
237 uint64_t StartOfSymbolStrings =
238 StartOfIndirectSymbols +
239 sizeof(uint32_t) * O.IndirectSymTable.Symbols.size();
240 uint64_t LinkEditSize =
241 (StartOfSymbolStrings + StrTableBuilder.getSize()) - StartOfLinkEdit;
242
243 // Now we have determined the layout of the contents of the __LINKEDIT
244 // segment. Update its load command.
245 if (LinkEditLoadCommand) {
246 MachO::macho_load_command *MLC = LinkEditLoadCommand;
247 switch (LinkEditLoadCommand->load_command_data.cmd) {
248 case MachO::LC_SEGMENT:
249 MLC->segment_command_data.cmdsize = sizeof(MachO::segment_command);
250 MLC->segment_command_data.fileoff = StartOfLinkEdit;
251 MLC->segment_command_data.vmsize = alignTo(LinkEditSize, PageSize);
252 MLC->segment_command_data.filesize = LinkEditSize;
253 break;
254 case MachO::LC_SEGMENT_64:
255 MLC->segment_command_64_data.cmdsize = sizeof(MachO::segment_command_64);
256 MLC->segment_command_64_data.fileoff = StartOfLinkEdit;
257 MLC->segment_command_64_data.vmsize = alignTo(LinkEditSize, PageSize);
258 MLC->segment_command_64_data.filesize = LinkEditSize;
259 break;
260 }
261 }
262
Alexander Shaposhnikovdc046c72020-02-21 13:18:36 -0800263 for (LoadCommand &LC : O.LoadCommands) {
Seiya Nuta552bcb82019-08-19 21:05:31 +0000264 auto &MLC = LC.MachOLoadCommand;
265 auto cmd = MLC.load_command_data.cmd;
266 switch (cmd) {
267 case MachO::LC_SYMTAB:
268 MLC.symtab_command_data.symoff = StartOfSymbols;
269 MLC.symtab_command_data.nsyms = O.SymTable.Symbols.size();
270 MLC.symtab_command_data.stroff = StartOfSymbolStrings;
271 MLC.symtab_command_data.strsize = StrTableBuilder.getSize();
272 break;
273 case MachO::LC_DYSYMTAB: {
274 if (MLC.dysymtab_command_data.ntoc != 0 ||
275 MLC.dysymtab_command_data.nmodtab != 0 ||
276 MLC.dysymtab_command_data.nextrefsyms != 0 ||
277 MLC.dysymtab_command_data.nlocrel != 0 ||
278 MLC.dysymtab_command_data.nextrel != 0)
279 return createStringError(llvm::errc::not_supported,
280 "shared library is not yet supported");
281
282 if (!O.IndirectSymTable.Symbols.empty()) {
283 MLC.dysymtab_command_data.indirectsymoff = StartOfIndirectSymbols;
284 MLC.dysymtab_command_data.nindirectsyms =
285 O.IndirectSymTable.Symbols.size();
286 }
287
288 updateDySymTab(MLC);
289 break;
290 }
291 case MachO::LC_DATA_IN_CODE:
292 MLC.linkedit_data_command_data.dataoff = StartOfDataInCode;
293 MLC.linkedit_data_command_data.datasize = O.DataInCode.Data.size();
294 break;
295 case MachO::LC_FUNCTION_STARTS:
296 MLC.linkedit_data_command_data.dataoff = StartOfFunctionStarts;
297 MLC.linkedit_data_command_data.datasize = O.FunctionStarts.Data.size();
298 break;
299 case MachO::LC_DYLD_INFO:
300 case MachO::LC_DYLD_INFO_ONLY:
301 MLC.dyld_info_command_data.rebase_off =
302 O.Rebases.Opcodes.empty() ? 0 : StartOfRebaseInfo;
303 MLC.dyld_info_command_data.rebase_size = O.Rebases.Opcodes.size();
304 MLC.dyld_info_command_data.bind_off =
305 O.Binds.Opcodes.empty() ? 0 : StartOfBindingInfo;
306 MLC.dyld_info_command_data.bind_size = O.Binds.Opcodes.size();
307 MLC.dyld_info_command_data.weak_bind_off =
308 O.WeakBinds.Opcodes.empty() ? 0 : StartOfWeakBindingInfo;
309 MLC.dyld_info_command_data.weak_bind_size = O.WeakBinds.Opcodes.size();
310 MLC.dyld_info_command_data.lazy_bind_off =
311 O.LazyBinds.Opcodes.empty() ? 0 : StartOfLazyBindingInfo;
312 MLC.dyld_info_command_data.lazy_bind_size = O.LazyBinds.Opcodes.size();
313 MLC.dyld_info_command_data.export_off =
314 O.Exports.Trie.empty() ? 0 : StartOfExportTrie;
315 MLC.dyld_info_command_data.export_size = O.Exports.Trie.size();
316 break;
317 case MachO::LC_LOAD_DYLINKER:
318 case MachO::LC_MAIN:
319 case MachO::LC_RPATH:
320 case MachO::LC_SEGMENT:
321 case MachO::LC_SEGMENT_64:
322 case MachO::LC_VERSION_MIN_MACOSX:
Alexander Shaposhnikov074af2d2019-10-24 17:35:10 -0700323 case MachO::LC_VERSION_MIN_IPHONEOS:
324 case MachO::LC_VERSION_MIN_TVOS:
325 case MachO::LC_VERSION_MIN_WATCHOS:
Seiya Nuta552bcb82019-08-19 21:05:31 +0000326 case MachO::LC_BUILD_VERSION:
327 case MachO::LC_ID_DYLIB:
328 case MachO::LC_LOAD_DYLIB:
329 case MachO::LC_UUID:
330 case MachO::LC_SOURCE_VERSION:
331 // Nothing to update.
332 break;
333 default:
334 // Abort if it's unsupported in order to prevent corrupting the object.
335 return createStringError(llvm::errc::not_supported,
336 "unsupported load command (cmd=0x%x)", cmd);
337 }
338 }
339
340 return Error::success();
341}
342
343Error MachOLayoutBuilder::layout() {
344 O.Header.NCmds = O.LoadCommands.size();
345 O.Header.SizeOfCmds = computeSizeOfCmds();
346 constructStringTable();
347 updateSymbolIndexes();
348 uint64_t Offset = layoutSegments();
349 Offset = layoutRelocations(Offset);
350 return layoutTail(Offset);
351}
352
353} // end namespace macho
354} // end namespace objcopy
355} // end namespace llvm