1 //===- MachOLayoutBuilder.cpp -----------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "MachOLayoutBuilder.h"
10 #include "llvm/Support/Errc.h"
11 #include "llvm/Support/ErrorHandling.h"
17 uint32_t MachOLayoutBuilder::computeSizeOfCmds() const {
19 for (const auto &LC
: O
.LoadCommands
) {
20 const MachO::macho_load_command
&MLC
= LC
.MachOLoadCommand
;
21 auto cmd
= MLC
.load_command_data
.cmd
;
23 case MachO::LC_SEGMENT
:
24 Size
+= sizeof(MachO::segment_command
) +
25 sizeof(MachO::section
) * LC
.Sections
.size();
27 case MachO::LC_SEGMENT_64
:
28 Size
+= sizeof(MachO::segment_command_64
) +
29 sizeof(MachO::section_64
) * LC
.Sections
.size();
34 #define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
36 Size += sizeof(MachO::LCStruct) + LC.Payload.size(); \
38 #include "llvm/BinaryFormat/MachO.def"
39 #undef HANDLE_LOAD_COMMAND
46 void MachOLayoutBuilder::constructStringTable() {
47 for (std::unique_ptr
<SymbolEntry
> &Sym
: O
.SymTable
.Symbols
)
48 StrTableBuilder
.add(Sym
->Name
);
49 StrTableBuilder
.finalize();
52 void MachOLayoutBuilder::updateSymbolIndexes() {
54 for (auto &Symbol
: O
.SymTable
.Symbols
)
55 Symbol
->Index
= Index
++;
58 // Updates the index and the number of local/external/undefined symbols.
59 void 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());
70 "Symbols are not sorted by their types.");
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())
82 uint32_t NumExtDefSymbols
= 0;
83 for (; Iter
!= End
; ++Iter
) {
84 if ((*Iter
)->isUndefinedSymbol())
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
);
99 // Recomputes and updates offset and size fields in load commands and sections
100 // since they could be modified.
101 uint64_t MachOLayoutBuilder::layoutSegments() {
103 Is64Bit
? sizeof(MachO::mach_header_64
) : sizeof(MachO::mach_header
);
104 const bool IsObjectFile
=
105 O
.Header
.FileType
== MachO::HeaderFileType::MH_OBJECT
;
106 uint64_t Offset
= IsObjectFile
? (HeaderSize
+ O
.Header
.SizeOfCmds
) : 0;
107 for (auto &LC
: O
.LoadCommands
) {
108 auto &MLC
= LC
.MachOLoadCommand
;
110 uint64_t SegmentVmAddr
;
111 uint64_t SegmentVmSize
;
112 switch (MLC
.load_command_data
.cmd
) {
113 case MachO::LC_SEGMENT
:
114 SegmentVmAddr
= MLC
.segment_command_data
.vmaddr
;
115 SegmentVmSize
= MLC
.segment_command_data
.vmsize
;
116 Segname
= StringRef(MLC
.segment_command_data
.segname
,
117 strnlen(MLC
.segment_command_data
.segname
,
118 sizeof(MLC
.segment_command_data
.segname
)));
120 case MachO::LC_SEGMENT_64
:
121 SegmentVmAddr
= MLC
.segment_command_64_data
.vmaddr
;
122 SegmentVmSize
= MLC
.segment_command_64_data
.vmsize
;
123 Segname
= StringRef(MLC
.segment_command_64_data
.segname
,
124 strnlen(MLC
.segment_command_64_data
.segname
,
125 sizeof(MLC
.segment_command_64_data
.segname
)));
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
;
138 // Update file offsets and sizes of sections.
139 uint64_t SegOffset
= Offset
;
140 uint64_t SegFileSize
= 0;
142 for (auto &Sec
: LC
.Sections
) {
144 if (Sec
.isVirtualSection()) {
147 uint64_t PaddingSize
=
148 OffsetToAlignment(SegFileSize
, 1ull << Sec
.Align
);
149 Sec
.Offset
= SegOffset
+ SegFileSize
+ PaddingSize
;
150 Sec
.Size
= Sec
.Content
.size();
151 SegFileSize
+= PaddingSize
+ Sec
.Size
;
153 VMSize
= std::max(VMSize
, Sec
.Addr
+ Sec
.Size
);
155 if (Sec
.isVirtualSection()) {
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
);
169 Offset
+= SegFileSize
;
171 Offset
= alignTo(Offset
+ SegFileSize
, PageSize
);
172 SegFileSize
= alignTo(SegFileSize
, PageSize
);
173 // Use the original vmsize if the segment is __PAGEZERO.
175 Segname
== "__PAGEZERO" ? SegmentVmSize
: alignTo(VMSize
, PageSize
);
178 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();
184 MLC
.segment_command_data
.fileoff
= SegOffset
;
185 MLC
.segment_command_data
.vmsize
= VMSize
;
186 MLC
.segment_command_data
.filesize
= SegFileSize
;
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();
193 MLC
.segment_command_64_data
.fileoff
= SegOffset
;
194 MLC
.segment_command_64_data
.vmsize
= VMSize
;
195 MLC
.segment_command_64_data
.filesize
= SegFileSize
;
203 uint64_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
;
214 Error
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
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
;
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
;
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
;
260 for (auto &LC
: O
.LoadCommands
) {
261 auto &MLC
= LC
.MachOLoadCommand
;
262 auto cmd
= MLC
.load_command_data
.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();
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");
279 if (!O
.IndirectSymTable
.Symbols
.empty()) {
280 MLC
.dysymtab_command_data
.indirectsymoff
= StartOfIndirectSymbols
;
281 MLC
.dysymtab_command_data
.nindirectsyms
=
282 O
.IndirectSymTable
.Symbols
.size();
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();
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();
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();
314 case MachO::LC_LOAD_DYLINKER
:
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
:
324 case MachO::LC_SOURCE_VERSION
:
325 // Nothing to update.
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
);
334 return Error::success();
337 Error
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
);
347 } // end namespace macho
348 } // end namespace objcopy
349 } // end namespace llvm