[llvm] r372666 - [llvm-lipo] Add support for archives

Alexander Shaposhnikov via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 23 15:22:56 PDT 2019


Author: alexshap
Date: Mon Sep 23 15:22:55 2019
New Revision: 372666

URL: http://llvm.org/viewvc/llvm-project?rev=372666&view=rev
Log:
[llvm-lipo] Add support for archives 

Add support for creating universal binaries which 
can contain an archive.

Differential revision: https://reviews.llvm.org/D67758

Test plan: make check-all

Added:
    llvm/trunk/test/tools/llvm-lipo/create-archive-input.test
Modified:
    llvm/trunk/tools/llvm-lipo/llvm-lipo.cpp

Added: llvm/trunk/test/tools/llvm-lipo/create-archive-input.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-lipo/create-archive-input.test?rev=372666&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-lipo/create-archive-input.test (added)
+++ llvm/trunk/test/tools/llvm-lipo/create-archive-input.test Mon Sep 23 15:22:55 2019
@@ -0,0 +1,26 @@
+# RUN: yaml2obj %p/Inputs/i386-slice.yaml > %t-i386.o
+# RUN: yaml2obj %p/Inputs/x86_64-slice.yaml > %t-x86_64.o
+# RUN: yaml2obj %p/Inputs/i386-x86_64-universal.yaml > %t-universal.o
+
+# RUN: llvm-ar cr %t.empty.a
+# RUN: not llvm-lipo %t.empty.a -create -output /dev/null 2>&1 | FileCheck --check-prefix=EMPTY-ARCHIVE %s
+
+# RUN: llvm-ar cr %t.different_architectures.a %t-i386.o %t-x86_64.o
+# RUN: not llvm-lipo %t.different_architectures.a -create -output /dev/null 2>&1 | FileCheck --check-prefix=ARCHIVE-WITH-DIFFERENT-ARCHS %s
+
+# RUN: llvm-ar cr %t.contains_fat_binary.a %t-universal.o 
+# RUN: not llvm-lipo %t.contains_fat_binary.a -create -output /dev/null 2>&1 | FileCheck --check-prefix=ARCHIVE-WITH-FAT-BINARY %s
+
+# RUN: llvm-ar cr %t-i386-lib.a %t-i386.o
+# RUN: llvm-lipo %t-i386-lib.a %t-x86_64.o -create -output %t-i386-x86_64-universal.o
+# RUN: llvm-lipo %t-i386-x86_64-universal.o -info | FileCheck --check-prefix=INFO-i386-x86_64 %s
+# RUN: llvm-lipo %t-i386-x86_64-universal.o -thin i386 -output %t-extracted-i386-lib.a
+# RUN: cmp %t-extracted-i386-lib.a %t-i386-lib.a
+# RUN: llvm-lipo %t-i386-x86_64-universal.o -thin x86_64 -output %t-extracted-x86_64.o
+# RUN: cmp %t-extracted-x86_64.o %t-x86_64.o
+#
+# EMPTY-ARCHIVE: empty archive
+# ARCHIVE-WITH-DIFFERENT-ARCHS: all members must match
+# ARCHIVE-WITH-FAT-BINARY: fat file (not allowed in an archive)
+#
+# INFO-i386-x86_64: i386 x86_64

Modified: llvm/trunk/tools/llvm-lipo/llvm-lipo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-lipo/llvm-lipo.cpp?rev=372666&r1=372665&r2=372666&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-lipo/llvm-lipo.cpp (original)
+++ llvm/trunk/tools/llvm-lipo/llvm-lipo.cpp Mon Sep 23 15:22:55 2019
@@ -101,12 +101,156 @@ struct Config {
   LipoAction ActionToPerform;
 };
 
-struct Slice {
-  const MachOObjectFile *ObjectFile;
-  // Requires Alignment field to store slice alignment values from universal
-  // binaries. Also needed to order the slices using compareSlices, so the total
+// For compatibility with cctools lipo, a file's alignment is calculated as the
+// minimum aligment of all segments. For object files, the file's alignment is
+// the maximum alignment of its sections.
+static uint32_t calculateFileAlignment(const MachOObjectFile &O) {
+  uint32_t P2CurrentAlignment;
+  uint32_t P2MinAlignment = MachOUniversalBinary::MaxSectionAlignment;
+  const bool Is64Bit = O.is64Bit();
+
+  for (const auto &LC : O.load_commands()) {
+    if (LC.C.cmd != (Is64Bit ? MachO::LC_SEGMENT_64 : MachO::LC_SEGMENT))
+      continue;
+    if (O.getHeader().filetype == MachO::MH_OBJECT) {
+      unsigned NumberOfSections =
+          (Is64Bit ? O.getSegment64LoadCommand(LC).nsects
+                   : O.getSegmentLoadCommand(LC).nsects);
+      P2CurrentAlignment = NumberOfSections ? 2 : P2MinAlignment;
+      for (unsigned SI = 0; SI < NumberOfSections; ++SI) {
+        P2CurrentAlignment = std::max(P2CurrentAlignment,
+                                      (Is64Bit ? O.getSection64(LC, SI).align
+                                               : O.getSection(LC, SI).align));
+      }
+    } else {
+      P2CurrentAlignment =
+          countTrailingZeros(Is64Bit ? O.getSegment64LoadCommand(LC).vmaddr
+                                     : O.getSegmentLoadCommand(LC).vmaddr);
+    }
+    P2MinAlignment = std::min(P2MinAlignment, P2CurrentAlignment);
+  }
+  // return a value >= 4 byte aligned, and less than MachO MaxSectionAlignment
+  return std::max(
+      static_cast<uint32_t>(2),
+      std::min(P2MinAlignment, static_cast<uint32_t>(
+                                   MachOUniversalBinary::MaxSectionAlignment)));
+}
+
+static uint32_t calculateAlignment(const MachOObjectFile *ObjectFile) {
+  switch (ObjectFile->getHeader().cputype) {
+  case MachO::CPU_TYPE_I386:
+  case MachO::CPU_TYPE_X86_64:
+  case MachO::CPU_TYPE_POWERPC:
+  case MachO::CPU_TYPE_POWERPC64:
+    return 12; // log2 value of page size(4k) for x86 and PPC
+  case MachO::CPU_TYPE_ARM:
+  case MachO::CPU_TYPE_ARM64:
+  case MachO::CPU_TYPE_ARM64_32:
+    return 14; // log2 value of page size(16k) for Darwin ARM
+  default:
+    return calculateFileAlignment(*ObjectFile);
+  }
+}
+
+class Slice {
+  const Binary *B;
+  uint32_t CPUType;
+  uint32_t CPUSubType;
+  std::string ArchName;
+
+  // P2Alignment field stores slice alignment values from universal
+  // binaries. This is also needed to order the slices so the total
   // file size can be calculated before creating the output buffer.
-  uint32_t Alignment;
+  uint32_t P2Alignment;
+
+public:
+  Slice(const MachOObjectFile *O, uint32_t Align)
+      : B(O), CPUType(O->getHeader().cputype),
+        CPUSubType(O->getHeader().cpusubtype),
+        ArchName(O->getArchTriple().getArchName()), P2Alignment(Align) {}
+
+  explicit Slice(const MachOObjectFile *O) : Slice(O, calculateAlignment(O)){};
+
+  explicit Slice(const Archive *A) : B(A) {
+    Error Err = Error::success();
+    std::unique_ptr<MachOObjectFile> FO = nullptr;
+    for (const Archive::Child &Child : A->children(Err)) {
+      Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary();
+      if (!ChildOrErr)
+        reportError(A->getFileName(), ChildOrErr.takeError());
+      Binary *Bin = ChildOrErr.get().get();
+      if (Bin->isMachOUniversalBinary())
+        reportError(("archive member " + Bin->getFileName() +
+                     " is a fat file (not allowed in an archive)")
+                        .str());
+      if (!Bin->isMachO())
+        reportError(("archive member " + Bin->getFileName() +
+                     " is not a MachO file (not allowed in an archive)"));
+      MachOObjectFile *O = cast<MachOObjectFile>(Bin);
+      if (FO &&
+          std::tie(FO->getHeader().cputype, FO->getHeader().cpusubtype) !=
+              std::tie(O->getHeader().cputype, O->getHeader().cpusubtype)) {
+        reportError(("archive member " + O->getFileName() + " cputype (" +
+                     Twine(O->getHeader().cputype) + ") and cpusubtype(" +
+                     Twine(O->getHeader().cpusubtype) +
+                     ") does not match previous archive members cputype (" +
+                     Twine(FO->getHeader().cputype) + ") and cpusubtype(" +
+                     Twine(FO->getHeader().cpusubtype) +
+                     ") (all members must match) " + FO->getFileName())
+                        .str());
+      }
+      if (!FO) {
+        ChildOrErr.get().release();
+        FO.reset(O);
+      }
+    }
+    if (Err)
+      reportError(A->getFileName(), std::move(Err));
+    if (!FO)
+      reportError(("empty archive with no architecture specification: " +
+                   A->getFileName() + " (can't determine architecture for it)")
+                      .str());
+    CPUType = FO->getHeader().cputype;
+    CPUSubType = FO->getHeader().cpusubtype;
+    ArchName = FO->getArchTriple().getArchName();
+    // Replicate the behavior of cctools lipo.
+    P2Alignment = FO->is64Bit() ? 3 : 2;
+  }
+
+  void setP2Alignment(uint32_t Align) { P2Alignment = Align; }
+
+  const Binary *getBinary() const { return B; }
+
+  uint32_t getCPUType() const { return CPUType; }
+
+  uint32_t getCPUSubType() const { return CPUSubType; }
+
+  uint32_t getP2Alignment() const { return P2Alignment; }
+
+  uint64_t getCPUID() const {
+    return static_cast<uint64_t>(CPUType) << 32 | CPUSubType;
+  }
+
+  std::string getArchString() const {
+    if (!ArchName.empty())
+      return ArchName;
+    return ("unknown(" + Twine(CPUType) + "," +
+            Twine(CPUSubType & ~MachO::CPU_SUBTYPE_MASK) + ")")
+        .str();
+  }
+
+  friend bool operator<(const Slice &Lhs, const Slice &Rhs) {
+    if (Lhs.CPUType == Rhs.CPUType)
+      return Lhs.CPUSubType < Rhs.CPUSubType;
+    // force arm64-family to follow after all other slices for
+    // compatibility with cctools lipo
+    if (Lhs.CPUType == MachO::CPU_TYPE_ARM64)
+      return false;
+    if (Rhs.CPUType == MachO::CPU_TYPE_ARM64)
+      return true;
+    // Sort by alignment to minimize file size
+    return Lhs.P2Alignment < Rhs.P2Alignment;
+  }
 };
 
 } // end namespace
@@ -281,11 +425,8 @@ readInputBinaries(ArrayRef<std::string>
     Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(InputFile);
     if (!BinaryOrErr)
       reportError(InputFile, BinaryOrErr.takeError());
-    // TODO: Add compatibility for archive files
-    if (BinaryOrErr->getBinary()->isArchive())
-      reportError("File " + InputFile +
-                  " is an archive file and is not yet supported.");
-    if (!BinaryOrErr->getBinary()->isMachO() &&
+    if (!BinaryOrErr->getBinary()->isArchive() &&
+        !BinaryOrErr->getBinary()->isMachO() &&
         !BinaryOrErr->getBinary()->isMachOUniversalBinary())
       reportError("File " + InputFile + " has unsupported binary format");
     InputBinaries.push_back(std::move(*BinaryOrErr));
@@ -306,8 +447,9 @@ static void verifyArch(ArrayRef<OwningBi
   if (auto UO =
           dyn_cast<MachOUniversalBinary>(InputBinaries.front().getBinary())) {
     for (StringRef Arch : VerifyArchList) {
-      auto ObjForArch = UO->getObjectForArch(Arch);
-      if (!ObjForArch)
+      Expected<MachOUniversalBinary::ObjectForArch> Obj =
+          UO->getObjectForArch(Arch);
+      if (!Obj)
         exit(EXIT_FAILURE);
     }
   } else if (auto O =
@@ -322,34 +464,29 @@ static void verifyArch(ArrayRef<OwningBi
   exit(EXIT_SUCCESS);
 }
 
-// Returns a string of the given Object file's architecture type
-// Unknown architectures formatted unknown(CPUType,CPUSubType) for compatibility
-// with cctools lipo
-static std::string getArchString(const MachOObjectFile &ObjectFile) {
-  const Triple T = ObjectFile.getArchTriple();
-  const StringRef ObjectArch = T.getArchName();
-  if (!ObjectArch.empty())
-    return ObjectArch;
-  return ("unknown(" + Twine(ObjectFile.getHeader().cputype) + "," +
-          Twine(ObjectFile.getHeader().cpusubtype & ~MachO::CPU_SUBTYPE_MASK) +
-          ")")
-      .str();
-}
-
 static void printBinaryArchs(const Binary *Binary, raw_ostream &OS) {
   // Prints trailing space for compatibility with cctools lipo.
   if (auto UO = dyn_cast<MachOUniversalBinary>(Binary)) {
     for (const auto &O : UO->objects()) {
-      Expected<std::unique_ptr<MachOObjectFile>> BinaryOrError =
+      Expected<std::unique_ptr<MachOObjectFile>> MachOObjOrError =
           O.getAsObjectFile();
-      if (!BinaryOrError)
-        reportError(Binary->getFileName(), BinaryOrError.takeError());
-      OS << getArchString(*BinaryOrError.get().get()) << " ";
+      if (MachOObjOrError) {
+        OS << Slice(MachOObjOrError->get()).getArchString() << " ";
+        continue;
+      }
+      Expected<std::unique_ptr<Archive>> ArchiveOrError = O.getAsArchive();
+      if (ArchiveOrError) {
+        consumeError(MachOObjOrError.takeError());
+        OS << Slice(ArchiveOrError->get()).getArchString() << " ";
+        continue;
+      }
+      consumeError(ArchiveOrError.takeError());
+      reportError(Binary->getFileName(), MachOObjOrError.takeError());
     }
     OS << "\n";
     return;
   }
-  OS << getArchString(*cast<MachOObjectFile>(Binary)) << " \n";
+  OS << Slice(cast<MachOObjectFile>(Binary)).getArchString() << " \n";
 }
 
 LLVM_ATTRIBUTE_NORETURN
@@ -399,21 +536,23 @@ static void extractSlice(ArrayRef<Owning
   auto *UO = cast<MachOUniversalBinary>(InputBinaries.front().getBinary());
   Expected<std::unique_ptr<MachOObjectFile>> Obj =
       UO->getMachOObjectForArch(ThinArchType);
-  if (!Obj)
+  Expected<std::unique_ptr<Archive>> Ar = UO->getArchiveForArch(ThinArchType);
+  if (!Obj && !Ar)
     reportError("fat input file " + UO->getFileName() +
                 " does not contain the specified architecture " + ThinArchType +
                 " to thin it to");
-
+  Binary *B = Obj ? static_cast<Binary *>(Obj->get())
+                  : static_cast<Binary *>(Ar->get());
   Expected<std::unique_ptr<FileOutputBuffer>> OutFileOrError =
       FileOutputBuffer::create(OutputFileName,
-                               Obj.get()->getMemoryBufferRef().getBufferSize(),
+                               B->getMemoryBufferRef().getBufferSize(),
                                sys::fs::can_execute(UO->getFileName())
                                    ? FileOutputBuffer::F_executable
                                    : 0);
   if (!OutFileOrError)
     reportError(OutputFileName, OutFileOrError.takeError());
-  std::copy(Obj.get()->getMemoryBufferRef().getBufferStart(),
-            Obj.get()->getMemoryBufferRef().getBufferEnd(),
+  std::copy(B->getMemoryBufferRef().getBufferStart(),
+            B->getMemoryBufferRef().getBufferEnd(),
             OutFileOrError.get()->getBufferStart());
   if (Error E = OutFileOrError.get()->commit())
     reportError(OutputFileName, std::move(E));
@@ -421,98 +560,24 @@ static void extractSlice(ArrayRef<Owning
 }
 
 static void checkArchDuplicates(const ArrayRef<Slice> &Slices) {
-  DenseMap<uint64_t, const MachOObjectFile *> CPUIds;
-  auto CPUIDForSlice = [](const Slice &S) {
-    return static_cast<uint64_t>(S.ObjectFile->getHeader().cputype) << 32 |
-           S.ObjectFile->getHeader().cpusubtype;
-  };
+  DenseMap<uint64_t, const Binary *> CPUIds;
   for (const auto &S : Slices) {
-    auto Entry = CPUIds.try_emplace(CPUIDForSlice(S), S.ObjectFile);
+    auto Entry = CPUIds.try_emplace(S.getCPUID(), S.getBinary());
     if (!Entry.second)
       reportError(Entry.first->second->getFileName() + " and " +
-                  S.ObjectFile->getFileName() + " have the same architecture " +
-                  getArchString(*S.ObjectFile) +
+                  S.getBinary()->getFileName() +
+                  " have the same architecture " + S.getArchString() +
                   " and therefore cannot be in the same universal binary");
   }
 }
 
-// For compatibility with cctools lipo, alignment is calculated as the minimum
-// aligment of all segments. Each segments's alignment is the maximum alignment
-// from its sections
-static uint32_t calculateSegmentAlignment(const MachOObjectFile &O) {
-  uint32_t P2CurrentAlignment;
-  uint32_t P2MinAlignment = MachOUniversalBinary::MaxSectionAlignment;
-  const bool Is64Bit = O.is64Bit();
-
-  for (const auto &LC : O.load_commands()) {
-    if (LC.C.cmd != (Is64Bit ? MachO::LC_SEGMENT_64 : MachO::LC_SEGMENT))
-      continue;
-    if (O.getHeader().filetype == MachO::MH_OBJECT) {
-      unsigned NumberOfSections =
-          (Is64Bit ? O.getSegment64LoadCommand(LC).nsects
-                   : O.getSegmentLoadCommand(LC).nsects);
-      P2CurrentAlignment = NumberOfSections ? 2 : P2MinAlignment;
-      for (unsigned SI = 0; SI < NumberOfSections; ++SI) {
-        P2CurrentAlignment = std::max(P2CurrentAlignment,
-                                      (Is64Bit ? O.getSection64(LC, SI).align
-                                               : O.getSection(LC, SI).align));
-      }
-    } else {
-      P2CurrentAlignment =
-          countTrailingZeros(Is64Bit ? O.getSegment64LoadCommand(LC).vmaddr
-                                     : O.getSegmentLoadCommand(LC).vmaddr);
-    }
-    P2MinAlignment = std::min(P2MinAlignment, P2CurrentAlignment);
-  }
-  // return a value >= 4 byte aligned, and less than MachO MaxSectionAlignment
-  return std::max(
-      static_cast<uint32_t>(2),
-      std::min(P2MinAlignment, static_cast<uint32_t>(
-                                   MachOUniversalBinary::MaxSectionAlignment)));
-}
-
-static uint32_t calculateAlignment(const MachOObjectFile *ObjectFile) {
-  switch (ObjectFile->getHeader().cputype) {
-  case MachO::CPU_TYPE_I386:
-  case MachO::CPU_TYPE_X86_64:
-  case MachO::CPU_TYPE_POWERPC:
-  case MachO::CPU_TYPE_POWERPC64:
-    return 12; // log2 value of page size(4k) for x86 and PPC
-  case MachO::CPU_TYPE_ARM:
-  case MachO::CPU_TYPE_ARM64:
-  case MachO::CPU_TYPE_ARM64_32:
-    return 14; // log2 value of page size(16k) for Darwin ARM
-  default:
-    return calculateSegmentAlignment(*ObjectFile);
-  }
-}
-
-// This function replicates ordering from cctools lipo for consistency
-static bool compareSlices(const Slice &Lhs, const Slice &Rhs) {
-  if (Lhs.ObjectFile->getHeader().cputype ==
-      Rhs.ObjectFile->getHeader().cputype)
-    return Lhs.ObjectFile->getHeader().cpusubtype <
-           Rhs.ObjectFile->getHeader().cpusubtype;
-
-  // force arm64-family to follow after all other slices for compatibility
-  // with cctools lipo
-  if (Lhs.ObjectFile->getHeader().cputype == MachO::CPU_TYPE_ARM64)
-    return false;
-  if (Rhs.ObjectFile->getHeader().cputype == MachO::CPU_TYPE_ARM64)
-    return true;
-
-  // Sort by alignment to minimize file size
-  return Lhs.Alignment < Rhs.Alignment;
-}
-
 template <typename Range>
-static void
-updateSegmentAlignments(Range &Slices,
-                        const StringMap<const uint32_t> &Alignments) {
+static void updateAlignments(Range &Slices,
+                             const StringMap<const uint32_t> &Alignments) {
   for (auto &Slice : Slices) {
-    auto Alignment = Alignments.find(getArchString(*Slice.ObjectFile));
+    auto Alignment = Alignments.find(Slice.getArchString());
     if (Alignment != Alignments.end())
-      Slice.Alignment = Alignment->second;
+      Slice.setP2Alignment(Alignment->second);
   }
 }
 
@@ -520,7 +585,7 @@ static void checkUnusedAlignments(ArrayR
                                   const StringMap<const uint32_t> &Alignments) {
   auto HasArch = [&](StringRef Arch) {
     return llvm::find_if(Slices, [Arch](Slice S) {
-             return getArchString(*S.ObjectFile) == Arch;
+             return S.getArchString() == Arch;
            }) != Slices.end();
   };
   for (StringRef Arch : Alignments.keys())
@@ -546,15 +611,17 @@ static SmallVector<Slice, 2> buildSlices
         if (!BinaryOrError)
           reportError(InputBinary->getFileName(), BinaryOrError.takeError());
         ExtractedObjects.push_back(std::move(BinaryOrError.get()));
-        Slices.push_back(Slice{ExtractedObjects.back().get(), O.getAlign()});
+        Slices.emplace_back(ExtractedObjects.back().get(), O.getAlign());
       }
     } else if (auto O = dyn_cast<MachOObjectFile>(InputBinary)) {
-      Slices.push_back(Slice{O, calculateAlignment(O)});
+      Slices.emplace_back(O);
+    } else if (auto A = dyn_cast<Archive>(InputBinary)) {
+      Slices.emplace_back(A);
     } else {
       llvm_unreachable("Unexpected binary format");
     }
   }
-  updateSegmentAlignments(Slices, Alignments);
+  updateAlignments(Slices, Alignments);
   return Slices;
 }
 
@@ -564,22 +631,20 @@ buildFatArchList(ArrayRef<Slice> Slices)
   uint64_t Offset =
       sizeof(MachO::fat_header) + Slices.size() * sizeof(MachO::fat_arch);
 
-  for (size_t Index = 0, Size = Slices.size(); Index < Size; ++Index) {
-    Offset = alignTo(Offset, 1ull << Slices[Index].Alignment);
-    const MachOObjectFile *ObjectFile = Slices[Index].ObjectFile;
+  for (const auto &S : Slices) {
+    Offset = alignTo(Offset, 1ull << S.getP2Alignment());
     if (Offset > UINT32_MAX)
       reportError("fat file too large to be created because the offset "
                   "field in struct fat_arch is only 32-bits and the offset " +
-                  Twine(Offset) + " for " + ObjectFile->getFileName() +
-                  " for architecture " + getArchString(*ObjectFile) +
-                  "exceeds that.");
+                  Twine(Offset) + " for " + S.getBinary()->getFileName() +
+                  " for architecture " + S.getArchString() + "exceeds that.");
 
     MachO::fat_arch FatArch;
-    FatArch.cputype = ObjectFile->getHeader().cputype;
-    FatArch.cpusubtype = ObjectFile->getHeader().cpusubtype;
+    FatArch.cputype = S.getCPUType();
+    FatArch.cpusubtype = S.getCPUSubType();
     FatArch.offset = Offset;
-    FatArch.size = ObjectFile->getMemoryBufferRef().getBufferSize();
-    FatArch.align = Slices[Index].Alignment;
+    FatArch.size = S.getBinary()->getMemoryBufferRef().getBufferSize();
+    FatArch.align = S.getP2Alignment();
     Offset += FatArch.size;
     FatArchList.push_back(FatArch);
   }
@@ -592,11 +657,11 @@ static void createUniversalBinary(SmallV
   FatHeader.magic = MachO::FAT_MAGIC;
   FatHeader.nfat_arch = Slices.size();
 
-  stable_sort(Slices, compareSlices);
+  stable_sort(Slices);
   SmallVector<MachO::fat_arch, 2> FatArchList = buildFatArchList(Slices);
 
   const bool IsExecutable = any_of(Slices, [](Slice S) {
-    return sys::fs::can_execute(S.ObjectFile->getFileName());
+    return sys::fs::can_execute(S.getBinary()->getFileName());
   });
   const uint64_t OutputFileSize =
       FatArchList.back().offset + FatArchList.back().size;
@@ -614,7 +679,7 @@ static void createUniversalBinary(SmallV
   std::memcpy(OutFile->getBufferStart(), &FatHeader, sizeof(MachO::fat_header));
 
   for (size_t Index = 0, Size = Slices.size(); Index < Size; ++Index) {
-    MemoryBufferRef BufferRef = Slices[Index].ObjectFile->getMemoryBufferRef();
+    MemoryBufferRef BufferRef = Slices[Index].getBinary()->getMemoryBufferRef();
     std::copy(BufferRef.getBufferStart(), BufferRef.getBufferEnd(),
               OutFile->getBufferStart() + FatArchList[Index].offset);
   }
@@ -674,17 +739,16 @@ buildReplacementSlices(ArrayRef<OwningBi
                   " for replacement file: " + ReplacementBinary->getFileName() +
                   " does not match the file's architecture");
 
-    auto Entry =
-        Slices.try_emplace(ReplacementArch, Slice{O, calculateAlignment(O)});
+    auto Entry = Slices.try_emplace(ReplacementArch, Slice(O));
     if (!Entry.second)
       reportError("-replace " + ReplacementArch +
                   " <file_name> specified multiple times: " +
-                  Entry.first->second.ObjectFile->getFileName() + ", " +
+                  Entry.first->second.getBinary()->getFileName() + ", " +
                   O->getFileName());
   }
   auto SlicesMapRange = map_range(
       Slices, [](StringMapEntry<Slice> &E) -> Slice & { return E.getValue(); });
-  updateSegmentAlignments(SlicesMapRange, Alignments);
+  updateAlignments(SlicesMapRange, Alignments);
   return Slices;
 }
 
@@ -714,7 +778,7 @@ static void replaceSlices(ArrayRef<Ownin
       buildSlices(InputBinaries, Alignments, ExtractedObjects);
 
   for (auto &Slice : Slices) {
-    auto It = ReplacementSlices.find(getArchString(*Slice.ObjectFile));
+    auto It = ReplacementSlices.find(Slice.getArchString());
     if (It != ReplacementSlices.end()) {
       Slice = It->second;
       ReplacementSlices.erase(It); // only keep remaining replacing arch_types




More information about the llvm-commits mailing list