MachOLayoutBuilder.cpp revision 360784
1//===- 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/Alignment.h" 11#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; 20 for (const auto &LC : O.LoadCommands) { 21 const MachO::macho_load_command &MLC = LC.MachOLoadCommand; 22 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) { 67 bool AL = A->isLocalSymbol(), BL = B->isLocalSymbol(); 68 if (AL != BL) 69 return AL; 70 return !AL && !A->isUndefinedSymbol() && 71 B->isUndefinedSymbol(); 72 }) && 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); 107 const bool IsObjectFile = 108 O.Header.FileType == MachO::HeaderFileType::MH_OBJECT; 109 uint64_t Offset = IsObjectFile ? (HeaderSize + O.Header.SizeOfCmds) : 0; 110 for (auto &LC : O.LoadCommands) { 111 auto &MLC = LC.MachOLoadCommand; 112 StringRef Segname; 113 uint64_t SegmentVmAddr; 114 uint64_t SegmentVmSize; 115 switch (MLC.load_command_data.cmd) { 116 case MachO::LC_SEGMENT: 117 SegmentVmAddr = MLC.segment_command_data.vmaddr; 118 SegmentVmSize = MLC.segment_command_data.vmsize; 119 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: 124 SegmentVmAddr = MLC.segment_command_64_data.vmaddr; 125 SegmentVmSize = MLC.segment_command_64_data.vmsize; 126 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. 142 uint64_t SegOffset = Offset; 143 uint64_t SegFileSize = 0; 144 uint64_t VMSize = 0; 145 for (auto &Sec : LC.Sections) { 146 if (IsObjectFile) { 147 if (Sec.isVirtualSection()) { 148 Sec.Offset = 0; 149 } else { 150 uint64_t PaddingSize = 151 offsetToAlignment(SegFileSize, Align(1ull << Sec.Align)); 152 Sec.Offset = SegOffset + SegFileSize + PaddingSize; 153 Sec.Size = Sec.Content.size(); 154 SegFileSize += PaddingSize + Sec.Size; 155 } 156 VMSize = std::max(VMSize, Sec.Addr + Sec.Size); 157 } else { 158 if (Sec.isVirtualSection()) { 159 Sec.Offset = 0; 160 VMSize += Sec.Size; 161 } else { 162 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); 166 VMSize = std::max(VMSize, SegFileSize); 167 } 168 } 169 } 170 171 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 181 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(); 187 MLC.segment_command_data.fileoff = SegOffset; 188 MLC.segment_command_data.vmsize = VMSize; 189 MLC.segment_command_data.filesize = SegFileSize; 190 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(); 196 MLC.segment_command_64_data.fileoff = SegOffset; 197 MLC.segment_command_64_data.vmsize = VMSize; 198 MLC.segment_command_64_data.filesize = SegFileSize; 199 break; 200 } 201 } 202 203 return Offset; 204} 205 206uint64_t MachOLayoutBuilder::layoutRelocations(uint64_t Offset) { 207 for (auto &LC : O.LoadCommands) 208 for (auto &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; 212 } 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 263 for (auto &LC : O.LoadCommands) { 264 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: 323 case MachO::LC_VERSION_MIN_IPHONEOS: 324 case MachO::LC_VERSION_MIN_TVOS: 325 case MachO::LC_VERSION_MIN_WATCHOS: 326 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 356