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