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/Alignment.h"
11 #include "llvm/Support/Errc.h"
12 #include "llvm/Support/ErrorHandling.h"
18 uint32_t MachOLayoutBuilder::computeSizeOfCmds() const {
20 for (const auto &LC
: O
.LoadCommands
) {
21 const MachO::macho_load_command
&MLC
= LC
.MachOLoadCommand
;
22 auto cmd
= MLC
.load_command_data
.cmd
;
24 case MachO::LC_SEGMENT
:
25 Size
+= sizeof(MachO::segment_command
) +
26 sizeof(MachO::section
) * LC
.Sections
.size();
28 case MachO::LC_SEGMENT_64
:
29 Size
+= sizeof(MachO::segment_command_64
) +
30 sizeof(MachO::section_64
) * LC
.Sections
.size();
35 #define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
37 Size += sizeof(MachO::LCStruct) + LC.Payload.size(); \
39 #include "llvm/BinaryFormat/MachO.def"
40 #undef HANDLE_LOAD_COMMAND
47 void MachOLayoutBuilder::constructStringTable() {
48 for (std::unique_ptr
<SymbolEntry
> &Sym
: O
.SymTable
.Symbols
)
49 StrTableBuilder
.add(Sym
->Name
);
50 StrTableBuilder
.finalize();
53 void MachOLayoutBuilder::updateSymbolIndexes() {
55 for (auto &Symbol
: O
.SymTable
.Symbols
)
56 Symbol
->Index
= Index
++;
59 // Updates the index and the number of local/external/undefined symbols.
60 void 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
) {
67 return (A
->isLocalSymbol() && !B
->isLocalSymbol()) ||
68 (!A
->isUndefinedSymbol() &&
69 B
->isUndefinedSymbol());
71 "Symbols are not sorted by their types.");
73 uint32_t NumLocalSymbols
= 0;
74 auto Iter
= O
.SymTable
.Symbols
.begin();
75 auto End
= O
.SymTable
.Symbols
.end();
76 for (; Iter
!= End
; ++Iter
) {
77 if ((*Iter
)->isExternalSymbol())
83 uint32_t NumExtDefSymbols
= 0;
84 for (; Iter
!= End
; ++Iter
) {
85 if ((*Iter
)->isUndefinedSymbol())
91 MLC
.dysymtab_command_data
.ilocalsym
= 0;
92 MLC
.dysymtab_command_data
.nlocalsym
= NumLocalSymbols
;
93 MLC
.dysymtab_command_data
.iextdefsym
= NumLocalSymbols
;
94 MLC
.dysymtab_command_data
.nextdefsym
= NumExtDefSymbols
;
95 MLC
.dysymtab_command_data
.iundefsym
= NumLocalSymbols
+ NumExtDefSymbols
;
96 MLC
.dysymtab_command_data
.nundefsym
=
97 O
.SymTable
.Symbols
.size() - (NumLocalSymbols
+ NumExtDefSymbols
);
100 // Recomputes and updates offset and size fields in load commands and sections
101 // since they could be modified.
102 uint64_t MachOLayoutBuilder::layoutSegments() {
104 Is64Bit
? sizeof(MachO::mach_header_64
) : sizeof(MachO::mach_header
);
105 const bool IsObjectFile
=
106 O
.Header
.FileType
== MachO::HeaderFileType::MH_OBJECT
;
107 uint64_t Offset
= IsObjectFile
? (HeaderSize
+ O
.Header
.SizeOfCmds
) : 0;
108 for (auto &LC
: O
.LoadCommands
) {
109 auto &MLC
= LC
.MachOLoadCommand
;
111 uint64_t SegmentVmAddr
;
112 uint64_t SegmentVmSize
;
113 switch (MLC
.load_command_data
.cmd
) {
114 case MachO::LC_SEGMENT
:
115 SegmentVmAddr
= MLC
.segment_command_data
.vmaddr
;
116 SegmentVmSize
= MLC
.segment_command_data
.vmsize
;
117 Segname
= StringRef(MLC
.segment_command_data
.segname
,
118 strnlen(MLC
.segment_command_data
.segname
,
119 sizeof(MLC
.segment_command_data
.segname
)));
121 case MachO::LC_SEGMENT_64
:
122 SegmentVmAddr
= MLC
.segment_command_64_data
.vmaddr
;
123 SegmentVmSize
= MLC
.segment_command_64_data
.vmsize
;
124 Segname
= StringRef(MLC
.segment_command_64_data
.segname
,
125 strnlen(MLC
.segment_command_64_data
.segname
,
126 sizeof(MLC
.segment_command_64_data
.segname
)));
132 if (Segname
== "__LINKEDIT") {
133 // We update the __LINKEDIT segment later (in layoutTail).
134 assert(LC
.Sections
.empty() && "__LINKEDIT segment has sections");
135 LinkEditLoadCommand
= &MLC
;
139 // Update file offsets and sizes of sections.
140 uint64_t SegOffset
= Offset
;
141 uint64_t SegFileSize
= 0;
143 for (auto &Sec
: LC
.Sections
) {
145 if (Sec
.isVirtualSection()) {
148 uint64_t PaddingSize
=
149 offsetToAlignment(SegFileSize
, llvm::Align(1ull << Sec
.Align
));
150 Sec
.Offset
= SegOffset
+ SegFileSize
+ PaddingSize
;
151 Sec
.Size
= Sec
.Content
.size();
152 SegFileSize
+= PaddingSize
+ Sec
.Size
;
154 VMSize
= std::max(VMSize
, Sec
.Addr
+ Sec
.Size
);
156 if (Sec
.isVirtualSection()) {
160 uint32_t SectOffset
= Sec
.Addr
- SegmentVmAddr
;
161 Sec
.Offset
= SegOffset
+ SectOffset
;
162 Sec
.Size
= Sec
.Content
.size();
163 SegFileSize
= std::max(SegFileSize
, SectOffset
+ Sec
.Size
);
164 VMSize
= std::max(VMSize
, SegFileSize
);
170 Offset
+= SegFileSize
;
172 Offset
= alignTo(Offset
+ SegFileSize
, PageSize
);
173 SegFileSize
= alignTo(SegFileSize
, PageSize
);
174 // Use the original vmsize if the segment is __PAGEZERO.
176 Segname
== "__PAGEZERO" ? SegmentVmSize
: alignTo(VMSize
, PageSize
);
179 switch (MLC
.load_command_data
.cmd
) {
180 case MachO::LC_SEGMENT
:
181 MLC
.segment_command_data
.cmdsize
=
182 sizeof(MachO::segment_command
) +
183 sizeof(MachO::section
) * LC
.Sections
.size();
184 MLC
.segment_command_data
.nsects
= LC
.Sections
.size();
185 MLC
.segment_command_data
.fileoff
= SegOffset
;
186 MLC
.segment_command_data
.vmsize
= VMSize
;
187 MLC
.segment_command_data
.filesize
= SegFileSize
;
189 case MachO::LC_SEGMENT_64
:
190 MLC
.segment_command_64_data
.cmdsize
=
191 sizeof(MachO::segment_command_64
) +
192 sizeof(MachO::section_64
) * LC
.Sections
.size();
193 MLC
.segment_command_64_data
.nsects
= LC
.Sections
.size();
194 MLC
.segment_command_64_data
.fileoff
= SegOffset
;
195 MLC
.segment_command_64_data
.vmsize
= VMSize
;
196 MLC
.segment_command_64_data
.filesize
= SegFileSize
;
204 uint64_t MachOLayoutBuilder::layoutRelocations(uint64_t Offset
) {
205 for (auto &LC
: O
.LoadCommands
)
206 for (auto &Sec
: LC
.Sections
) {
207 Sec
.RelOff
= Sec
.Relocations
.empty() ? 0 : Offset
;
208 Sec
.NReloc
= Sec
.Relocations
.size();
209 Offset
+= sizeof(MachO::any_relocation_info
) * Sec
.NReloc
;
215 Error
MachOLayoutBuilder::layoutTail(uint64_t Offset
) {
216 // The order of LINKEDIT elements is as follows:
217 // rebase info, binding info, weak binding info, lazy binding info, export
218 // trie, data-in-code, symbol table, indirect symbol table, symbol table
220 uint64_t NListSize
= Is64Bit
? sizeof(MachO::nlist_64
) : sizeof(MachO::nlist
);
221 uint64_t StartOfLinkEdit
= Offset
;
222 uint64_t StartOfRebaseInfo
= StartOfLinkEdit
;
223 uint64_t StartOfBindingInfo
= StartOfRebaseInfo
+ O
.Rebases
.Opcodes
.size();
224 uint64_t StartOfWeakBindingInfo
= StartOfBindingInfo
+ O
.Binds
.Opcodes
.size();
225 uint64_t StartOfLazyBindingInfo
=
226 StartOfWeakBindingInfo
+ O
.WeakBinds
.Opcodes
.size();
227 uint64_t StartOfExportTrie
=
228 StartOfLazyBindingInfo
+ O
.LazyBinds
.Opcodes
.size();
229 uint64_t StartOfFunctionStarts
= StartOfExportTrie
+ O
.Exports
.Trie
.size();
230 uint64_t StartOfDataInCode
=
231 StartOfFunctionStarts
+ O
.FunctionStarts
.Data
.size();
232 uint64_t StartOfSymbols
= StartOfDataInCode
+ O
.DataInCode
.Data
.size();
233 uint64_t StartOfIndirectSymbols
=
234 StartOfSymbols
+ NListSize
* O
.SymTable
.Symbols
.size();
235 uint64_t StartOfSymbolStrings
=
236 StartOfIndirectSymbols
+
237 sizeof(uint32_t) * O
.IndirectSymTable
.Symbols
.size();
238 uint64_t LinkEditSize
=
239 (StartOfSymbolStrings
+ StrTableBuilder
.getSize()) - StartOfLinkEdit
;
241 // Now we have determined the layout of the contents of the __LINKEDIT
242 // segment. Update its load command.
243 if (LinkEditLoadCommand
) {
244 MachO::macho_load_command
*MLC
= LinkEditLoadCommand
;
245 switch (LinkEditLoadCommand
->load_command_data
.cmd
) {
246 case MachO::LC_SEGMENT
:
247 MLC
->segment_command_data
.cmdsize
= sizeof(MachO::segment_command
);
248 MLC
->segment_command_data
.fileoff
= StartOfLinkEdit
;
249 MLC
->segment_command_data
.vmsize
= alignTo(LinkEditSize
, PageSize
);
250 MLC
->segment_command_data
.filesize
= LinkEditSize
;
252 case MachO::LC_SEGMENT_64
:
253 MLC
->segment_command_64_data
.cmdsize
= sizeof(MachO::segment_command_64
);
254 MLC
->segment_command_64_data
.fileoff
= StartOfLinkEdit
;
255 MLC
->segment_command_64_data
.vmsize
= alignTo(LinkEditSize
, PageSize
);
256 MLC
->segment_command_64_data
.filesize
= LinkEditSize
;
261 for (auto &LC
: O
.LoadCommands
) {
262 auto &MLC
= LC
.MachOLoadCommand
;
263 auto cmd
= MLC
.load_command_data
.cmd
;
265 case MachO::LC_SYMTAB
:
266 MLC
.symtab_command_data
.symoff
= StartOfSymbols
;
267 MLC
.symtab_command_data
.nsyms
= O
.SymTable
.Symbols
.size();
268 MLC
.symtab_command_data
.stroff
= StartOfSymbolStrings
;
269 MLC
.symtab_command_data
.strsize
= StrTableBuilder
.getSize();
271 case MachO::LC_DYSYMTAB
: {
272 if (MLC
.dysymtab_command_data
.ntoc
!= 0 ||
273 MLC
.dysymtab_command_data
.nmodtab
!= 0 ||
274 MLC
.dysymtab_command_data
.nextrefsyms
!= 0 ||
275 MLC
.dysymtab_command_data
.nlocrel
!= 0 ||
276 MLC
.dysymtab_command_data
.nextrel
!= 0)
277 return createStringError(llvm::errc::not_supported
,
278 "shared library is not yet supported");
280 if (!O
.IndirectSymTable
.Symbols
.empty()) {
281 MLC
.dysymtab_command_data
.indirectsymoff
= StartOfIndirectSymbols
;
282 MLC
.dysymtab_command_data
.nindirectsyms
=
283 O
.IndirectSymTable
.Symbols
.size();
289 case MachO::LC_DATA_IN_CODE
:
290 MLC
.linkedit_data_command_data
.dataoff
= StartOfDataInCode
;
291 MLC
.linkedit_data_command_data
.datasize
= O
.DataInCode
.Data
.size();
293 case MachO::LC_FUNCTION_STARTS
:
294 MLC
.linkedit_data_command_data
.dataoff
= StartOfFunctionStarts
;
295 MLC
.linkedit_data_command_data
.datasize
= O
.FunctionStarts
.Data
.size();
297 case MachO::LC_DYLD_INFO
:
298 case MachO::LC_DYLD_INFO_ONLY
:
299 MLC
.dyld_info_command_data
.rebase_off
=
300 O
.Rebases
.Opcodes
.empty() ? 0 : StartOfRebaseInfo
;
301 MLC
.dyld_info_command_data
.rebase_size
= O
.Rebases
.Opcodes
.size();
302 MLC
.dyld_info_command_data
.bind_off
=
303 O
.Binds
.Opcodes
.empty() ? 0 : StartOfBindingInfo
;
304 MLC
.dyld_info_command_data
.bind_size
= O
.Binds
.Opcodes
.size();
305 MLC
.dyld_info_command_data
.weak_bind_off
=
306 O
.WeakBinds
.Opcodes
.empty() ? 0 : StartOfWeakBindingInfo
;
307 MLC
.dyld_info_command_data
.weak_bind_size
= O
.WeakBinds
.Opcodes
.size();
308 MLC
.dyld_info_command_data
.lazy_bind_off
=
309 O
.LazyBinds
.Opcodes
.empty() ? 0 : StartOfLazyBindingInfo
;
310 MLC
.dyld_info_command_data
.lazy_bind_size
= O
.LazyBinds
.Opcodes
.size();
311 MLC
.dyld_info_command_data
.export_off
=
312 O
.Exports
.Trie
.empty() ? 0 : StartOfExportTrie
;
313 MLC
.dyld_info_command_data
.export_size
= O
.Exports
.Trie
.size();
315 case MachO::LC_LOAD_DYLINKER
:
317 case MachO::LC_RPATH
:
318 case MachO::LC_SEGMENT
:
319 case MachO::LC_SEGMENT_64
:
320 case MachO::LC_VERSION_MIN_MACOSX
:
321 case MachO::LC_BUILD_VERSION
:
322 case MachO::LC_ID_DYLIB
:
323 case MachO::LC_LOAD_DYLIB
:
325 case MachO::LC_SOURCE_VERSION
:
326 // Nothing to update.
329 // Abort if it's unsupported in order to prevent corrupting the object.
330 return createStringError(llvm::errc::not_supported
,
331 "unsupported load command (cmd=0x%x)", cmd
);
335 return Error::success();
338 Error
MachOLayoutBuilder::layout() {
339 O
.Header
.NCmds
= O
.LoadCommands
.size();
340 O
.Header
.SizeOfCmds
= computeSizeOfCmds();
341 constructStringTable();
342 updateSymbolIndexes();
343 uint64_t Offset
= layoutSegments();
344 Offset
= layoutRelocations(Offset
);
345 return layoutTail(Offset
);
348 } // end namespace macho
349 } // end namespace objcopy
350 } // end namespace llvm