773 lines · cpp
1//===-- llvm-lipo.cpp - a tool for manipulating universal binaries --------===//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-exception6//7//===----------------------------------------------------------------------===//8//9// A utility for creating / splitting / inspecting universal binaries.10//11//===----------------------------------------------------------------------===//12 13#include "llvm/ADT/STLExtras.h"14#include "llvm/BinaryFormat/MachO.h"15#include "llvm/IR/LLVMContext.h"16#include "llvm/IR/Module.h"17#include "llvm/Object/Archive.h"18#include "llvm/Object/Binary.h"19#include "llvm/Object/IRObjectFile.h"20#include "llvm/Object/MachO.h"21#include "llvm/Object/MachOUniversal.h"22#include "llvm/Object/MachOUniversalWriter.h"23#include "llvm/Object/ObjectFile.h"24#include "llvm/Option/Arg.h"25#include "llvm/Option/ArgList.h"26#include "llvm/Support/CommandLine.h"27#include "llvm/Support/Error.h"28#include "llvm/Support/FileOutputBuffer.h"29#include "llvm/Support/LLVMDriver.h"30#include "llvm/Support/TargetSelect.h"31#include "llvm/Support/WithColor.h"32#include "llvm/TargetParser/Triple.h"33#include "llvm/TextAPI/Architecture.h"34#include <optional>35 36using namespace llvm;37using namespace llvm::object;38 39static const StringRef ToolName = "llvm-lipo";40 41[[noreturn]] static void reportError(Twine Message) {42 WithColor::error(errs(), ToolName) << Message << "\n";43 errs().flush();44 exit(EXIT_FAILURE);45}46 47[[noreturn]] static void reportError(Error E) {48 assert(E);49 std::string Buf;50 raw_string_ostream OS(Buf);51 logAllUnhandledErrors(std::move(E), OS);52 OS.flush();53 reportError(Buf);54}55 56[[noreturn]] static void reportError(StringRef File, Error E) {57 assert(E);58 std::string Buf;59 raw_string_ostream OS(Buf);60 logAllUnhandledErrors(std::move(E), OS);61 OS.flush();62 WithColor::error(errs(), ToolName) << "'" << File << "': " << Buf;63 exit(EXIT_FAILURE);64}65 66namespace {67enum LipoID {68 LIPO_INVALID = 0, // This is not an option ID.69#define OPTION(...) LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(LIPO_, __VA_ARGS__),70#include "LipoOpts.inc"71#undef OPTION72};73 74namespace lipo {75#define OPTTABLE_STR_TABLE_CODE76#include "LipoOpts.inc"77#undef OPTTABLE_STR_TABLE_CODE78 79#define OPTTABLE_PREFIXES_TABLE_CODE80#include "LipoOpts.inc"81#undef OPTTABLE_PREFIXES_TABLE_CODE82 83using namespace llvm::opt;84static constexpr opt::OptTable::Info LipoInfoTable[] = {85#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(LIPO_, __VA_ARGS__),86#include "LipoOpts.inc"87#undef OPTION88};89} // namespace lipo90 91class LipoOptTable : public opt::GenericOptTable {92public:93 LipoOptTable()94 : opt::GenericOptTable(lipo::OptionStrTable, lipo::OptionPrefixesTable,95 lipo::LipoInfoTable) {}96};97 98enum class LipoAction {99 PrintArchs,100 PrintInfo,101 VerifyArch,102 ThinArch,103 ExtractArch,104 CreateUniversal,105 ReplaceArch,106};107 108struct InputFile {109 std::optional<StringRef> ArchType;110 StringRef FileName;111};112 113struct Config {114 SmallVector<InputFile, 1> InputFiles;115 SmallVector<std::string, 1> VerifyArchList;116 SmallVector<InputFile, 1> ReplacementFiles;117 StringMap<const uint32_t> SegmentAlignments;118 std::string ArchType;119 std::string OutputFile;120 LipoAction ActionToPerform;121 bool UseFat64;122};123 124static Slice createSliceFromArchive(LLVMContext &LLVMCtx, const Archive &A) {125 Expected<Slice> ArchiveOrSlice = Slice::create(A, &LLVMCtx);126 if (!ArchiveOrSlice)127 reportError(A.getFileName(), ArchiveOrSlice.takeError());128 return *ArchiveOrSlice;129}130 131static Slice createSliceFromIR(const IRObjectFile &IRO, unsigned Align) {132 Expected<Slice> IROrErr = Slice::create(IRO, Align);133 if (!IROrErr)134 reportError(IRO.getFileName(), IROrErr.takeError());135 return *IROrErr;136}137 138} // end namespace139 140static void validateArchitectureName(StringRef ArchitectureName) {141 if (!MachOObjectFile::isValidArch(ArchitectureName)) {142 std::string Buf;143 raw_string_ostream OS(Buf);144 OS << "Invalid architecture: " << ArchitectureName145 << "\nValid architecture names are:";146 for (auto arch : MachOObjectFile::getValidArchs())147 OS << " " << arch;148 reportError(Buf);149 }150}151 152static Config parseLipoOptions(ArrayRef<const char *> ArgsArr) {153 Config C;154 LipoOptTable T;155 unsigned MissingArgumentIndex, MissingArgumentCount;156 opt::InputArgList InputArgs =157 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);158 159 if (MissingArgumentCount)160 reportError("missing argument to " +161 StringRef(InputArgs.getArgString(MissingArgumentIndex)) +162 " option");163 164 if (InputArgs.size() == 0) {165 // printHelp does not accept Twine.166 T.printHelp(errs(), "llvm-lipo input[s] option[s]", "llvm-lipo");167 exit(EXIT_FAILURE);168 }169 170 if (InputArgs.hasArg(LIPO_help)) {171 // printHelp does not accept Twine.172 T.printHelp(outs(), "llvm-lipo input[s] option[s]", "llvm-lipo");173 exit(EXIT_SUCCESS);174 }175 176 if (InputArgs.hasArg(LIPO_version)) {177 outs() << ToolName + "\n";178 cl::PrintVersionMessage();179 exit(EXIT_SUCCESS);180 }181 182 for (auto *Arg : InputArgs.filtered(LIPO_UNKNOWN))183 reportError("unknown argument '" + Arg->getAsString(InputArgs) + "'");184 185 for (auto *Arg : InputArgs.filtered(LIPO_INPUT))186 C.InputFiles.push_back({std::nullopt, Arg->getValue()});187 for (auto *Arg : InputArgs.filtered(LIPO_arch)) {188 validateArchitectureName(Arg->getValue(0));189 assert(Arg->getValue(1) && "file_name is missing");190 C.InputFiles.push_back({StringRef(Arg->getValue(0)), Arg->getValue(1)});191 }192 193 if (C.InputFiles.empty())194 reportError("at least one input file should be specified");195 196 if (InputArgs.hasArg(LIPO_output))197 C.OutputFile = std::string(InputArgs.getLastArgValue(LIPO_output));198 199 for (auto *Segalign : InputArgs.filtered(LIPO_segalign)) {200 if (!Segalign->getValue(1))201 reportError("segalign is missing an argument: expects -segalign "202 "arch_type alignment_value");203 204 validateArchitectureName(Segalign->getValue(0));205 206 uint32_t AlignmentValue;207 if (!to_integer<uint32_t>(Segalign->getValue(1), AlignmentValue, 16))208 reportError("argument to -segalign <arch_type> " +209 Twine(Segalign->getValue(1)) +210 " (hex) is not a proper hexadecimal number");211 if (!isPowerOf2_32(AlignmentValue))212 reportError("argument to -segalign <arch_type> " +213 Twine(Segalign->getValue(1)) +214 " (hex) must be a non-zero power of two");215 if (Log2_32(AlignmentValue) > MachOUniversalBinary::MaxSectionAlignment)216 reportError(217 "argument to -segalign <arch_type> " + Twine(Segalign->getValue(1)) +218 " (hex) must be less than or equal to the maximum section align 2^" +219 Twine(MachOUniversalBinary::MaxSectionAlignment));220 auto Entry = C.SegmentAlignments.try_emplace(Segalign->getValue(0),221 Log2_32(AlignmentValue));222 if (!Entry.second)223 reportError("-segalign " + Twine(Segalign->getValue(0)) +224 " <alignment_value> specified multiple times: " +225 Twine(1 << Entry.first->second) + ", " +226 Twine(AlignmentValue));227 }228 229 C.UseFat64 = InputArgs.hasArg(LIPO_fat64);230 231 SmallVector<opt::Arg *, 1> ActionArgs(InputArgs.filtered(LIPO_action_group));232 if (ActionArgs.empty())233 reportError("at least one action should be specified");234 // errors if multiple actions specified other than replace235 // multiple replace flags may be specified, as long as they are not mixed with236 // other action flags237 auto ReplacementArgsRange = InputArgs.filtered(LIPO_replace);238 if (ActionArgs.size() > 1 &&239 ActionArgs.size() !=240 static_cast<size_t>(std::distance(ReplacementArgsRange.begin(),241 ReplacementArgsRange.end()))) {242 std::string Buf;243 raw_string_ostream OS(Buf);244 OS << "only one of the following actions can be specified:";245 for (auto *Arg : ActionArgs)246 OS << " " << Arg->getSpelling();247 reportError(Buf);248 }249 250 switch (ActionArgs[0]->getOption().getID()) {251 case LIPO_verify_arch:252 llvm::append_range(C.VerifyArchList,253 InputArgs.getAllArgValues(LIPO_verify_arch));254 if (C.VerifyArchList.empty())255 reportError(256 "verify_arch requires at least one architecture to be specified");257 if (C.InputFiles.size() > 1)258 reportError("verify_arch expects a single input file");259 C.ActionToPerform = LipoAction::VerifyArch;260 return C;261 262 case LIPO_archs:263 if (C.InputFiles.size() > 1)264 reportError("archs expects a single input file");265 C.ActionToPerform = LipoAction::PrintArchs;266 return C;267 268 case LIPO_info:269 C.ActionToPerform = LipoAction::PrintInfo;270 return C;271 272 case LIPO_thin:273 if (C.InputFiles.size() > 1)274 reportError("thin expects a single input file");275 if (C.OutputFile.empty())276 reportError("thin expects a single output file");277 C.ArchType = ActionArgs[0]->getValue();278 validateArchitectureName(C.ArchType);279 C.ActionToPerform = LipoAction::ThinArch;280 return C;281 282 case LIPO_extract:283 if (C.InputFiles.size() > 1)284 reportError("extract expects a single input file");285 if (C.OutputFile.empty())286 reportError("extract expects a single output file");287 C.ArchType = ActionArgs[0]->getValue();288 validateArchitectureName(C.ArchType);289 C.ActionToPerform = LipoAction::ExtractArch;290 return C;291 292 case LIPO_create:293 if (C.OutputFile.empty())294 reportError("create expects a single output file to be specified");295 C.ActionToPerform = LipoAction::CreateUniversal;296 return C;297 298 case LIPO_replace:299 for (auto *Action : ActionArgs) {300 assert(Action->getValue(1) && "file_name is missing");301 validateArchitectureName(Action->getValue(0));302 C.ReplacementFiles.push_back(303 {StringRef(Action->getValue(0)), Action->getValue(1)});304 }305 306 if (C.OutputFile.empty())307 reportError("replace expects a single output file to be specified");308 if (C.InputFiles.size() > 1)309 reportError("replace expects a single input file");310 C.ActionToPerform = LipoAction::ReplaceArch;311 return C;312 313 default:314 reportError("llvm-lipo action unspecified");315 }316}317 318static SmallVector<OwningBinary<Binary>, 1>319readInputBinaries(LLVMContext &LLVMCtx, ArrayRef<InputFile> InputFiles) {320 SmallVector<OwningBinary<Binary>, 1> InputBinaries;321 for (const InputFile &IF : InputFiles) {322 Expected<OwningBinary<Binary>> BinaryOrErr =323 createBinary(IF.FileName, &LLVMCtx);324 if (!BinaryOrErr)325 reportError(IF.FileName, BinaryOrErr.takeError());326 const Binary *B = BinaryOrErr->getBinary();327 if (!B->isArchive() && !B->isMachO() && !B->isMachOUniversalBinary() &&328 !B->isIR())329 reportError("File " + IF.FileName + " has unsupported binary format");330 if (IF.ArchType && (B->isMachO() || B->isArchive() || B->isIR())) {331 const auto S = B->isMachO() ? Slice(*cast<MachOObjectFile>(B))332 : B->isArchive()333 ? createSliceFromArchive(LLVMCtx, *cast<Archive>(B))334 : createSliceFromIR(*cast<IRObjectFile>(B), 0);335 const auto SpecifiedCPUType = MachO::getCPUTypeFromArchitecture(336 MachO::getArchitectureFromName(337 Triple(*IF.ArchType).getArchName()))338 .first;339 // For compatibility with cctools' lipo the comparison is relaxed just to340 // checking cputypes.341 if (S.getCPUType() != SpecifiedCPUType)342 reportError("specified architecture: " + *IF.ArchType +343 " for file: " + B->getFileName() +344 " does not match the file's architecture (" +345 S.getArchString() + ")");346 }347 InputBinaries.push_back(std::move(*BinaryOrErr));348 }349 return InputBinaries;350}351 352[[noreturn]] static void353verifyArch(ArrayRef<OwningBinary<Binary>> InputBinaries,354 ArrayRef<std::string> VerifyArchList) {355 assert(!VerifyArchList.empty() &&356 "The list of architectures should be non-empty");357 assert(InputBinaries.size() == 1 && "Incorrect number of input binaries");358 359 for (StringRef Arch : VerifyArchList)360 validateArchitectureName(Arch);361 362 if (auto UO =363 dyn_cast<MachOUniversalBinary>(InputBinaries.front().getBinary())) {364 for (StringRef Arch : VerifyArchList) {365 Expected<MachOUniversalBinary::ObjectForArch> Obj =366 UO->getObjectForArch(Arch);367 if (!Obj)368 exit(EXIT_FAILURE);369 }370 } else if (auto O =371 dyn_cast<MachOObjectFile>(InputBinaries.front().getBinary())) {372 const Triple::ArchType ObjectArch = O->getArch();373 for (StringRef Arch : VerifyArchList)374 if (ObjectArch != Triple(Arch).getArch())375 exit(EXIT_FAILURE);376 } else {377 llvm_unreachable("Unexpected binary format");378 }379 exit(EXIT_SUCCESS);380}381 382static void printBinaryArchs(LLVMContext &LLVMCtx, const Binary *Binary,383 raw_ostream &OS) {384 // Prints trailing space for compatibility with cctools lipo.385 if (auto UO = dyn_cast<MachOUniversalBinary>(Binary)) {386 for (const auto &O : UO->objects()) {387 // Order here is important, because both MachOObjectFile and388 // IRObjectFile can be created with a binary that has embedded bitcode.389 Expected<std::unique_ptr<MachOObjectFile>> MachOObjOrError =390 O.getAsObjectFile();391 if (MachOObjOrError) {392 OS << Slice(*(MachOObjOrError->get())).getArchString() << " ";393 continue;394 }395 Expected<std::unique_ptr<IRObjectFile>> IROrError =396 O.getAsIRObject(LLVMCtx);397 if (IROrError) {398 consumeError(MachOObjOrError.takeError());399 Expected<Slice> SliceOrErr = Slice::create(**IROrError, O.getAlign());400 if (!SliceOrErr) {401 reportError(Binary->getFileName(), SliceOrErr.takeError());402 continue;403 }404 OS << SliceOrErr.get().getArchString() << " ";405 continue;406 }407 Expected<std::unique_ptr<Archive>> ArchiveOrError = O.getAsArchive();408 if (ArchiveOrError) {409 consumeError(MachOObjOrError.takeError());410 consumeError(IROrError.takeError());411 OS << createSliceFromArchive(LLVMCtx, **ArchiveOrError).getArchString()412 << " ";413 continue;414 }415 consumeError(ArchiveOrError.takeError());416 reportError(Binary->getFileName(), MachOObjOrError.takeError());417 reportError(Binary->getFileName(), IROrError.takeError());418 }419 OS << "\n";420 return;421 }422 423 if (const auto *MachO = dyn_cast<MachOObjectFile>(Binary)) {424 OS << Slice(*MachO).getArchString() << " \n";425 return;426 }427 428 if (const auto *A = dyn_cast<Archive>(Binary)) {429 OS << createSliceFromArchive(LLVMCtx, *A).getArchString() << "\n";430 return;431 }432 433 // This should be always the case, as this is tested in readInputBinaries434 const auto *IR = cast<IRObjectFile>(Binary);435 Expected<Slice> SliceOrErr = createSliceFromIR(*IR, 0);436 if (!SliceOrErr)437 reportError(IR->getFileName(), SliceOrErr.takeError());438 439 OS << SliceOrErr->getArchString() << " \n";440}441 442[[noreturn]] static void443printArchs(LLVMContext &LLVMCtx, ArrayRef<OwningBinary<Binary>> InputBinaries) {444 assert(InputBinaries.size() == 1 && "Incorrect number of input binaries");445 printBinaryArchs(LLVMCtx, InputBinaries.front().getBinary(), outs());446 exit(EXIT_SUCCESS);447}448 449[[noreturn]] static void450printInfo(LLVMContext &LLVMCtx, ArrayRef<OwningBinary<Binary>> InputBinaries) {451 // Group universal and thin files together for compatibility with cctools lipo452 for (auto &IB : InputBinaries) {453 const Binary *Binary = IB.getBinary();454 if (Binary->isMachOUniversalBinary()) {455 outs() << "Architectures in the fat file: " << Binary->getFileName()456 << " are: ";457 printBinaryArchs(LLVMCtx, Binary, outs());458 }459 }460 for (auto &IB : InputBinaries) {461 const Binary *Binary = IB.getBinary();462 if (!Binary->isMachOUniversalBinary()) {463 assert((Binary->isMachO() || Binary->isArchive()) &&464 "expected MachO binary");465 outs() << "Non-fat file: " << Binary->getFileName()466 << " is architecture: ";467 printBinaryArchs(LLVMCtx, Binary, outs());468 }469 }470 exit(EXIT_SUCCESS);471}472 473[[noreturn]] static void thinSlice(LLVMContext &LLVMCtx,474 ArrayRef<OwningBinary<Binary>> InputBinaries,475 StringRef ArchType,476 StringRef OutputFileName) {477 assert(!ArchType.empty() && "The architecture type should be non-empty");478 assert(InputBinaries.size() == 1 && "Incorrect number of input binaries");479 assert(!OutputFileName.empty() && "Thin expects a single output file");480 481 if (InputBinaries.front().getBinary()->isMachO()) {482 reportError("input file " +483 InputBinaries.front().getBinary()->getFileName() +484 " must be a fat file when the -thin option is specified");485 exit(EXIT_FAILURE);486 }487 488 auto *UO = cast<MachOUniversalBinary>(InputBinaries.front().getBinary());489 Expected<std::unique_ptr<MachOObjectFile>> Obj =490 UO->getMachOObjectForArch(ArchType);491 Expected<std::unique_ptr<IRObjectFile>> IRObj =492 UO->getIRObjectForArch(ArchType, LLVMCtx);493 Expected<std::unique_ptr<Archive>> Ar = UO->getArchiveForArch(ArchType);494 if (!Obj && !IRObj && !Ar)495 reportError("fat input file " + UO->getFileName() +496 " does not contain the specified architecture " + ArchType +497 " to thin it to");498 Binary *B;499 // Order here is important, because both Obj and IRObj will be valid with a500 // binary that has embedded bitcode.501 if (Obj)502 B = Obj->get();503 else if (IRObj)504 B = IRObj->get();505 else506 B = Ar->get();507 508 Expected<std::unique_ptr<FileOutputBuffer>> OutFileOrError =509 FileOutputBuffer::create(OutputFileName,510 B->getMemoryBufferRef().getBufferSize(),511 sys::fs::can_execute(UO->getFileName())512 ? FileOutputBuffer::F_executable513 : 0);514 if (!OutFileOrError)515 reportError(OutputFileName, OutFileOrError.takeError());516 std::copy(B->getMemoryBufferRef().getBufferStart(),517 B->getMemoryBufferRef().getBufferEnd(),518 OutFileOrError.get()->getBufferStart());519 if (Error E = OutFileOrError.get()->commit())520 reportError(OutputFileName, std::move(E));521 exit(EXIT_SUCCESS);522}523 524static void checkArchDuplicates(ArrayRef<Slice> Slices) {525 DenseMap<uint64_t, const Binary *> CPUIds;526 for (const auto &S : Slices) {527 auto Entry = CPUIds.try_emplace(S.getCPUID(), S.getBinary());528 if (!Entry.second)529 reportError(Entry.first->second->getFileName() + " and " +530 S.getBinary()->getFileName() +531 " have the same architecture " + S.getArchString() +532 " and therefore cannot be in the same universal binary");533 }534}535 536template <typename Range>537static void updateAlignments(Range &Slices,538 const StringMap<const uint32_t> &Alignments) {539 for (auto &Slice : Slices) {540 auto Alignment = Alignments.find(Slice.getArchString());541 if (Alignment != Alignments.end())542 Slice.setP2Alignment(Alignment->second);543 }544}545 546static void checkUnusedAlignments(ArrayRef<Slice> Slices,547 const StringMap<const uint32_t> &Alignments) {548 auto HasArch = [&](StringRef Arch) {549 return llvm::any_of(Slices,550 [Arch](Slice S) { return S.getArchString() == Arch; });551 };552 for (StringRef Arch : Alignments.keys())553 if (!HasArch(Arch))554 reportError("-segalign " + Arch +555 " <value> specified but resulting fat file does not contain "556 "that architecture ");557}558 559// Updates vector ExtractedObjects with the MachOObjectFiles extracted from560// Universal Binary files to transfer ownership.561static SmallVector<Slice, 2>562buildSlices(LLVMContext &LLVMCtx, ArrayRef<OwningBinary<Binary>> InputBinaries,563 const StringMap<const uint32_t> &Alignments,564 SmallVectorImpl<std::unique_ptr<SymbolicFile>> &ExtractedObjects) {565 SmallVector<Slice, 2> Slices;566 for (auto &IB : InputBinaries) {567 const Binary *InputBinary = IB.getBinary();568 if (auto UO = dyn_cast<MachOUniversalBinary>(InputBinary)) {569 for (const auto &O : UO->objects()) {570 // Order here is important, because both MachOObjectFile and571 // IRObjectFile can be created with a binary that has embedded bitcode.572 Expected<std::unique_ptr<MachOObjectFile>> BinaryOrError =573 O.getAsObjectFile();574 if (BinaryOrError) {575 Slices.emplace_back(*(BinaryOrError.get()), O.getAlign());576 ExtractedObjects.push_back(std::move(BinaryOrError.get()));577 continue;578 }579 Expected<std::unique_ptr<IRObjectFile>> IROrError =580 O.getAsIRObject(LLVMCtx);581 if (IROrError) {582 consumeError(BinaryOrError.takeError());583 Slice S = createSliceFromIR(**IROrError, O.getAlign());584 ExtractedObjects.emplace_back(std::move(IROrError.get()));585 Slices.emplace_back(std::move(S));586 continue;587 }588 reportError(InputBinary->getFileName(), BinaryOrError.takeError());589 }590 } else if (const auto *O = dyn_cast<MachOObjectFile>(InputBinary)) {591 Slices.emplace_back(*O);592 } else if (const auto *A = dyn_cast<Archive>(InputBinary)) {593 Slices.push_back(createSliceFromArchive(LLVMCtx, *A));594 } else if (const auto *IRO = dyn_cast<IRObjectFile>(InputBinary)) {595 // Original Apple's lipo set the alignment to 0596 Expected<Slice> SliceOrErr = Slice::create(*IRO, 0);597 if (!SliceOrErr) {598 reportError(InputBinary->getFileName(), SliceOrErr.takeError());599 continue;600 }601 Slices.emplace_back(std::move(SliceOrErr.get()));602 } else {603 llvm_unreachable("Unexpected binary format");604 }605 }606 updateAlignments(Slices, Alignments);607 return Slices;608}609 610[[noreturn]] static void611createUniversalBinary(LLVMContext &LLVMCtx,612 ArrayRef<OwningBinary<Binary>> InputBinaries,613 const StringMap<const uint32_t> &Alignments,614 StringRef OutputFileName, FatHeaderType HeaderType) {615 assert(InputBinaries.size() >= 1 && "Incorrect number of input binaries");616 assert(!OutputFileName.empty() && "Create expects a single output file");617 618 SmallVector<std::unique_ptr<SymbolicFile>, 1> ExtractedObjects;619 SmallVector<Slice, 1> Slices =620 buildSlices(LLVMCtx, InputBinaries, Alignments, ExtractedObjects);621 checkArchDuplicates(Slices);622 checkUnusedAlignments(Slices, Alignments);623 624 llvm::stable_sort(Slices);625 if (Error E = writeUniversalBinary(Slices, OutputFileName, HeaderType))626 reportError(std::move(E));627 628 exit(EXIT_SUCCESS);629}630 631[[noreturn]] static void632extractSlice(LLVMContext &LLVMCtx, ArrayRef<OwningBinary<Binary>> InputBinaries,633 const StringMap<const uint32_t> &Alignments, StringRef ArchType,634 StringRef OutputFileName) {635 assert(!ArchType.empty() &&636 "The architecture type should be non-empty");637 assert(InputBinaries.size() == 1 && "Incorrect number of input binaries");638 assert(!OutputFileName.empty() && "Thin expects a single output file");639 640 if (InputBinaries.front().getBinary()->isMachO()) {641 reportError("input file " +642 InputBinaries.front().getBinary()->getFileName() +643 " must be a fat file when the -extract option is specified");644 }645 646 SmallVector<std::unique_ptr<SymbolicFile>, 2> ExtractedObjects;647 SmallVector<Slice, 2> Slices =648 buildSlices(LLVMCtx, InputBinaries, Alignments, ExtractedObjects);649 erase_if(Slices, [ArchType](const Slice &S) {650 return ArchType != S.getArchString();651 });652 653 if (Slices.empty())654 reportError(655 "fat input file " + InputBinaries.front().getBinary()->getFileName() +656 " does not contain the specified architecture " + ArchType);657 658 llvm::stable_sort(Slices);659 if (Error E = writeUniversalBinary(Slices, OutputFileName))660 reportError(std::move(E));661 exit(EXIT_SUCCESS);662}663 664static StringMap<Slice>665buildReplacementSlices(ArrayRef<OwningBinary<Binary>> ReplacementBinaries,666 const StringMap<const uint32_t> &Alignments) {667 StringMap<Slice> Slices;668 // populates StringMap of slices to replace with; error checks for mismatched669 // replace flag args, fat files, and duplicate arch_types670 for (const auto &OB : ReplacementBinaries) {671 const Binary *ReplacementBinary = OB.getBinary();672 auto O = dyn_cast<MachOObjectFile>(ReplacementBinary);673 if (!O)674 reportError("replacement file: " + ReplacementBinary->getFileName() +675 " is a fat file (must be a thin file)");676 Slice S(*O);677 auto Entry = Slices.try_emplace(S.getArchString(), S);678 if (!Entry.second)679 reportError("-replace " + S.getArchString() +680 " <file_name> specified multiple times: " +681 Entry.first->second.getBinary()->getFileName() + ", " +682 O->getFileName());683 }684 auto SlicesMapRange = map_range(685 Slices, [](StringMapEntry<Slice> &E) -> Slice & { return E.getValue(); });686 updateAlignments(SlicesMapRange, Alignments);687 return Slices;688}689 690[[noreturn]] static void691replaceSlices(LLVMContext &LLVMCtx,692 ArrayRef<OwningBinary<Binary>> InputBinaries,693 const StringMap<const uint32_t> &Alignments,694 StringRef OutputFileName, ArrayRef<InputFile> ReplacementFiles) {695 assert(InputBinaries.size() == 1 && "Incorrect number of input binaries");696 assert(!OutputFileName.empty() && "Replace expects a single output file");697 698 if (InputBinaries.front().getBinary()->isMachO())699 reportError("input file " +700 InputBinaries.front().getBinary()->getFileName() +701 " must be a fat file when the -replace option is specified");702 703 SmallVector<OwningBinary<Binary>, 1> ReplacementBinaries =704 readInputBinaries(LLVMCtx, ReplacementFiles);705 706 StringMap<Slice> ReplacementSlices =707 buildReplacementSlices(ReplacementBinaries, Alignments);708 SmallVector<std::unique_ptr<SymbolicFile>, 2> ExtractedObjects;709 SmallVector<Slice, 2> Slices =710 buildSlices(LLVMCtx, InputBinaries, Alignments, ExtractedObjects);711 712 for (auto &Slice : Slices) {713 auto It = ReplacementSlices.find(Slice.getArchString());714 if (It != ReplacementSlices.end()) {715 Slice = It->second;716 ReplacementSlices.erase(It); // only keep remaining replacing arch_types717 }718 }719 720 if (!ReplacementSlices.empty())721 reportError("-replace " + ReplacementSlices.begin()->first() +722 " <file_name> specified but fat file: " +723 InputBinaries.front().getBinary()->getFileName() +724 " does not contain that architecture");725 726 checkUnusedAlignments(Slices, Alignments);727 728 llvm::stable_sort(Slices);729 if (Error E = writeUniversalBinary(Slices, OutputFileName))730 reportError(std::move(E));731 exit(EXIT_SUCCESS);732}733 734int llvm_lipo_main(int argc, char **argv, const llvm::ToolContext &) {735 llvm::InitializeAllTargetInfos();736 llvm::InitializeAllTargetMCs();737 llvm::InitializeAllAsmParsers();738 739 Config C = parseLipoOptions(ArrayRef(argv + 1, argc - 1));740 LLVMContext LLVMCtx;741 SmallVector<OwningBinary<Binary>, 1> InputBinaries =742 readInputBinaries(LLVMCtx, C.InputFiles);743 744 switch (C.ActionToPerform) {745 case LipoAction::VerifyArch:746 verifyArch(InputBinaries, C.VerifyArchList);747 break;748 case LipoAction::PrintArchs:749 printArchs(LLVMCtx, InputBinaries);750 break;751 case LipoAction::PrintInfo:752 printInfo(LLVMCtx, InputBinaries);753 break;754 case LipoAction::ThinArch:755 thinSlice(LLVMCtx, InputBinaries, C.ArchType, C.OutputFile);756 break;757 case LipoAction::ExtractArch:758 extractSlice(LLVMCtx, InputBinaries, C.SegmentAlignments, C.ArchType,759 C.OutputFile);760 break;761 case LipoAction::CreateUniversal:762 createUniversalBinary(763 LLVMCtx, InputBinaries, C.SegmentAlignments, C.OutputFile,764 C.UseFat64 ? FatHeaderType::Fat64Header : FatHeaderType::FatHeader);765 break;766 case LipoAction::ReplaceArch:767 replaceSlices(LLVMCtx, InputBinaries, C.SegmentAlignments, C.OutputFile,768 C.ReplacementFiles);769 break;770 }771 return EXIT_SUCCESS;772}773