1 //===- MachOUniversalWriter.h - MachO universal binary writer----*- 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 // Declares the Slice class and writeUniversalBinary function for writing a
10 // MachO universal binary file.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_OBJECT_MACHOUNIVERSALWRITER_H
15 #define LLVM_OBJECT_MACHOUNIVERSALWRITER_H
16 
17 #include "llvm/ADT/ArrayRef.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/ADT/Twine.h"
20 #include "llvm/BinaryFormat/MachO.h"
21 #include "llvm/Support/Error.h"
22 #include <cstdint>
23 #include <string>
24 
25 namespace llvm {
26 class LLVMContext;
27 
28 namespace object {
29 class Archive;
30 class Binary;
31 class IRObjectFile;
32 class MachOObjectFile;
33 
34 class Slice {
35   const Binary *B;
36   uint32_t CPUType;
37   uint32_t CPUSubType;
38   std::string ArchName;
39 
40   // P2Alignment field stores slice alignment values from universal
41   // binaries. This is also needed to order the slices so the total
42   // file size can be calculated before creating the output buffer.
43   uint32_t P2Alignment;
44 
45   Slice(const IRObjectFile &IRO, uint32_t CPUType, uint32_t CPUSubType,
46         std::string ArchName, uint32_t Align);
47 
48 public:
49   explicit Slice(const MachOObjectFile &O);
50 
51   Slice(const MachOObjectFile &O, uint32_t Align);
52 
53   /// This constructor takes pre-specified \param CPUType , \param CPUSubType ,
54   /// \param ArchName , \param Align instead of inferring them from the archive
55   /// members.
56   Slice(const Archive &A, uint32_t CPUType, uint32_t CPUSubType,
57         std::string ArchName, uint32_t Align);
58 
59   static Expected<Slice> create(const Archive &A,
60                                 LLVMContext *LLVMCtx = nullptr);
61 
62   static Expected<Slice> create(const IRObjectFile &IRO, uint32_t Align);
63 
64   void setP2Alignment(uint32_t Align) { P2Alignment = Align; }
65 
66   const Binary *getBinary() const { return B; }
67 
68   uint32_t getCPUType() const { return CPUType; }
69 
70   uint32_t getCPUSubType() const { return CPUSubType; }
71 
72   uint32_t getP2Alignment() const { return P2Alignment; }
73 
74   uint64_t getCPUID() const {
75     return static_cast<uint64_t>(CPUType) << 32 | CPUSubType;
76   }
77 
78   std::string getArchString() const {
79     if (!ArchName.empty())
80       return ArchName;
81     return ("unknown(" + Twine(CPUType) + "," +
82             Twine(CPUSubType & ~MachO::CPU_SUBTYPE_MASK) + ")")
83         .str();
84   }
85 
86   friend bool operator<(const Slice &Lhs, const Slice &Rhs) {
87     if (Lhs.CPUType == Rhs.CPUType)
88       return Lhs.CPUSubType < Rhs.CPUSubType;
89     // force arm64-family to follow after all other slices for
90     // compatibility with cctools lipo
91     if (Lhs.CPUType == MachO::CPU_TYPE_ARM64)
92       return false;
93     if (Rhs.CPUType == MachO::CPU_TYPE_ARM64)
94       return true;
95     // Sort by alignment to minimize file size
96     return Lhs.P2Alignment < Rhs.P2Alignment;
97   }
98 };
99 
100 Error writeUniversalBinary(ArrayRef<Slice> Slices, StringRef OutputFileName);
101 
102 Error writeUniversalBinaryToStream(ArrayRef<Slice> Slices, raw_ostream &Out);
103 
104 } // end namespace object
105 
106 } // end namespace llvm
107 
108 #endif // LLVM_OBJECT_MACHOUNIVERSALWRITER_H
109