xref: /freebsd-src/contrib/llvm-project/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
181ad6265SDimitry Andric //===- MachOObjcopy.cpp -----------------------------------------*- C++ -*-===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric 
981ad6265SDimitry Andric #include "llvm/ObjCopy/MachO/MachOObjcopy.h"
1081ad6265SDimitry Andric #include "Archive.h"
1181ad6265SDimitry Andric #include "MachOReader.h"
1281ad6265SDimitry Andric #include "MachOWriter.h"
1381ad6265SDimitry Andric #include "llvm/ADT/DenseSet.h"
1481ad6265SDimitry Andric #include "llvm/ObjCopy/CommonConfig.h"
1581ad6265SDimitry Andric #include "llvm/ObjCopy/MachO/MachOConfig.h"
1681ad6265SDimitry Andric #include "llvm/ObjCopy/MultiFormatConfig.h"
1781ad6265SDimitry Andric #include "llvm/ObjCopy/ObjCopy.h"
1881ad6265SDimitry Andric #include "llvm/Object/ArchiveWriter.h"
1981ad6265SDimitry Andric #include "llvm/Object/MachOUniversal.h"
2081ad6265SDimitry Andric #include "llvm/Object/MachOUniversalWriter.h"
2181ad6265SDimitry Andric #include "llvm/Support/Errc.h"
2281ad6265SDimitry Andric #include "llvm/Support/Error.h"
2381ad6265SDimitry Andric #include "llvm/Support/FileOutputBuffer.h"
2481ad6265SDimitry Andric #include "llvm/Support/Path.h"
2581ad6265SDimitry Andric #include "llvm/Support/SmallVectorMemoryBuffer.h"
2681ad6265SDimitry Andric 
2781ad6265SDimitry Andric using namespace llvm;
2881ad6265SDimitry Andric using namespace llvm::objcopy;
2981ad6265SDimitry Andric using namespace llvm::objcopy::macho;
3081ad6265SDimitry Andric using namespace llvm::object;
3181ad6265SDimitry Andric 
3281ad6265SDimitry Andric using SectionPred = std::function<bool(const std::unique_ptr<Section> &Sec)>;
3381ad6265SDimitry Andric using LoadCommandPred = std::function<bool(const LoadCommand &LC)>;
3481ad6265SDimitry Andric 
3581ad6265SDimitry Andric #ifndef NDEBUG
3681ad6265SDimitry Andric static bool isLoadCommandWithPayloadString(const LoadCommand &LC) {
3781ad6265SDimitry Andric   // TODO: Add support for LC_REEXPORT_DYLIB, LC_LOAD_UPWARD_DYLIB and
3881ad6265SDimitry Andric   // LC_LAZY_LOAD_DYLIB
3981ad6265SDimitry Andric   return LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_RPATH ||
4081ad6265SDimitry Andric          LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_ID_DYLIB ||
4181ad6265SDimitry Andric          LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_LOAD_DYLIB ||
4281ad6265SDimitry Andric          LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_LOAD_WEAK_DYLIB;
4381ad6265SDimitry Andric }
4481ad6265SDimitry Andric #endif
4581ad6265SDimitry Andric 
4681ad6265SDimitry Andric static StringRef getPayloadString(const LoadCommand &LC) {
4781ad6265SDimitry Andric   assert(isLoadCommandWithPayloadString(LC) &&
4881ad6265SDimitry Andric          "unsupported load command encountered");
4981ad6265SDimitry Andric 
5081ad6265SDimitry Andric   return StringRef(reinterpret_cast<const char *>(LC.Payload.data()),
5181ad6265SDimitry Andric                    LC.Payload.size())
5281ad6265SDimitry Andric       .rtrim('\0');
5381ad6265SDimitry Andric }
5481ad6265SDimitry Andric 
5581ad6265SDimitry Andric static Error removeSections(const CommonConfig &Config, Object &Obj) {
5681ad6265SDimitry Andric   SectionPred RemovePred = [](const std::unique_ptr<Section> &) {
5781ad6265SDimitry Andric     return false;
5881ad6265SDimitry Andric   };
5981ad6265SDimitry Andric 
6081ad6265SDimitry Andric   if (!Config.ToRemove.empty()) {
6181ad6265SDimitry Andric     RemovePred = [&Config, RemovePred](const std::unique_ptr<Section> &Sec) {
6281ad6265SDimitry Andric       return Config.ToRemove.matches(Sec->CanonicalName);
6381ad6265SDimitry Andric     };
6481ad6265SDimitry Andric   }
6581ad6265SDimitry Andric 
6681ad6265SDimitry Andric   if (Config.StripAll || Config.StripDebug) {
6781ad6265SDimitry Andric     // Remove all debug sections.
6881ad6265SDimitry Andric     RemovePred = [RemovePred](const std::unique_ptr<Section> &Sec) {
6981ad6265SDimitry Andric       if (Sec->Segname == "__DWARF")
7081ad6265SDimitry Andric         return true;
7181ad6265SDimitry Andric 
7281ad6265SDimitry Andric       return RemovePred(Sec);
7381ad6265SDimitry Andric     };
7481ad6265SDimitry Andric   }
7581ad6265SDimitry Andric 
7681ad6265SDimitry Andric   if (!Config.OnlySection.empty()) {
7781ad6265SDimitry Andric     // Overwrite RemovePred because --only-section takes priority.
7881ad6265SDimitry Andric     RemovePred = [&Config](const std::unique_ptr<Section> &Sec) {
7981ad6265SDimitry Andric       return !Config.OnlySection.matches(Sec->CanonicalName);
8081ad6265SDimitry Andric     };
8181ad6265SDimitry Andric   }
8281ad6265SDimitry Andric 
8381ad6265SDimitry Andric   return Obj.removeSections(RemovePred);
8481ad6265SDimitry Andric }
8581ad6265SDimitry Andric 
8681ad6265SDimitry Andric static void markSymbols(const CommonConfig &, Object &Obj) {
8781ad6265SDimitry Andric   // Symbols referenced from the indirect symbol table must not be removed.
8881ad6265SDimitry Andric   for (IndirectSymbolEntry &ISE : Obj.IndirectSymTable.Symbols)
8981ad6265SDimitry Andric     if (ISE.Symbol)
9081ad6265SDimitry Andric       (*ISE.Symbol)->Referenced = true;
9181ad6265SDimitry Andric }
9281ad6265SDimitry Andric 
9381ad6265SDimitry Andric static void updateAndRemoveSymbols(const CommonConfig &Config,
9481ad6265SDimitry Andric                                    const MachOConfig &MachOConfig,
9581ad6265SDimitry Andric                                    Object &Obj) {
9681ad6265SDimitry Andric   for (SymbolEntry &Sym : Obj.SymTable) {
9781ad6265SDimitry Andric     auto I = Config.SymbolsToRename.find(Sym.Name);
9881ad6265SDimitry Andric     if (I != Config.SymbolsToRename.end())
9981ad6265SDimitry Andric       Sym.Name = std::string(I->getValue());
10081ad6265SDimitry Andric   }
10181ad6265SDimitry Andric 
10281ad6265SDimitry Andric   auto RemovePred = [&Config, &MachOConfig,
10381ad6265SDimitry Andric                      &Obj](const std::unique_ptr<SymbolEntry> &N) {
10481ad6265SDimitry Andric     if (N->Referenced)
10581ad6265SDimitry Andric       return false;
10681ad6265SDimitry Andric     if (MachOConfig.KeepUndefined && N->isUndefinedSymbol())
10781ad6265SDimitry Andric       return false;
10881ad6265SDimitry Andric     if (N->n_desc & MachO::REFERENCED_DYNAMICALLY)
10981ad6265SDimitry Andric       return false;
11081ad6265SDimitry Andric     if (Config.StripAll)
11181ad6265SDimitry Andric       return true;
11281ad6265SDimitry Andric     if (Config.DiscardMode == DiscardType::All && !(N->n_type & MachO::N_EXT))
11381ad6265SDimitry Andric       return true;
11481ad6265SDimitry Andric     // This behavior is consistent with cctools' strip.
11581ad6265SDimitry Andric     if (MachOConfig.StripSwiftSymbols &&
11681ad6265SDimitry Andric         (Obj.Header.Flags & MachO::MH_DYLDLINK) && Obj.SwiftVersion &&
11781ad6265SDimitry Andric         *Obj.SwiftVersion && N->isSwiftSymbol())
11881ad6265SDimitry Andric       return true;
11981ad6265SDimitry Andric     return false;
12081ad6265SDimitry Andric   };
12181ad6265SDimitry Andric 
12281ad6265SDimitry Andric   Obj.SymTable.removeSymbols(RemovePred);
12381ad6265SDimitry Andric }
12481ad6265SDimitry Andric 
12581ad6265SDimitry Andric template <typename LCType>
12681ad6265SDimitry Andric static void updateLoadCommandPayloadString(LoadCommand &LC, StringRef S) {
12781ad6265SDimitry Andric   assert(isLoadCommandWithPayloadString(LC) &&
12881ad6265SDimitry Andric          "unsupported load command encountered");
12981ad6265SDimitry Andric 
13081ad6265SDimitry Andric   uint32_t NewCmdsize = alignTo(sizeof(LCType) + S.size() + 1, 8);
13181ad6265SDimitry Andric 
13281ad6265SDimitry Andric   LC.MachOLoadCommand.load_command_data.cmdsize = NewCmdsize;
13381ad6265SDimitry Andric   LC.Payload.assign(NewCmdsize - sizeof(LCType), 0);
13481ad6265SDimitry Andric   std::copy(S.begin(), S.end(), LC.Payload.begin());
13581ad6265SDimitry Andric }
13681ad6265SDimitry Andric 
13781ad6265SDimitry Andric static LoadCommand buildRPathLoadCommand(StringRef Path) {
13881ad6265SDimitry Andric   LoadCommand LC;
13981ad6265SDimitry Andric   MachO::rpath_command RPathLC;
14081ad6265SDimitry Andric   RPathLC.cmd = MachO::LC_RPATH;
14181ad6265SDimitry Andric   RPathLC.path = sizeof(MachO::rpath_command);
14281ad6265SDimitry Andric   RPathLC.cmdsize = alignTo(sizeof(MachO::rpath_command) + Path.size() + 1, 8);
14381ad6265SDimitry Andric   LC.MachOLoadCommand.rpath_command_data = RPathLC;
14481ad6265SDimitry Andric   LC.Payload.assign(RPathLC.cmdsize - sizeof(MachO::rpath_command), 0);
14581ad6265SDimitry Andric   std::copy(Path.begin(), Path.end(), LC.Payload.begin());
14681ad6265SDimitry Andric   return LC;
14781ad6265SDimitry Andric }
14881ad6265SDimitry Andric 
14981ad6265SDimitry Andric static Error processLoadCommands(const MachOConfig &MachOConfig, Object &Obj) {
15081ad6265SDimitry Andric   // Remove RPaths.
15181ad6265SDimitry Andric   DenseSet<StringRef> RPathsToRemove(MachOConfig.RPathsToRemove.begin(),
15281ad6265SDimitry Andric                                      MachOConfig.RPathsToRemove.end());
15381ad6265SDimitry Andric 
15481ad6265SDimitry Andric   LoadCommandPred RemovePred = [&RPathsToRemove,
15581ad6265SDimitry Andric                                 &MachOConfig](const LoadCommand &LC) {
15681ad6265SDimitry Andric     if (LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_RPATH) {
15781ad6265SDimitry Andric       // When removing all RPaths we don't need to care
15881ad6265SDimitry Andric       // about what it contains
15981ad6265SDimitry Andric       if (MachOConfig.RemoveAllRpaths)
16081ad6265SDimitry Andric         return true;
16181ad6265SDimitry Andric 
16281ad6265SDimitry Andric       StringRef RPath = getPayloadString(LC);
16381ad6265SDimitry Andric       if (RPathsToRemove.count(RPath)) {
16481ad6265SDimitry Andric         RPathsToRemove.erase(RPath);
16581ad6265SDimitry Andric         return true;
16681ad6265SDimitry Andric       }
16781ad6265SDimitry Andric     }
16881ad6265SDimitry Andric     return false;
16981ad6265SDimitry Andric   };
17081ad6265SDimitry Andric 
17181ad6265SDimitry Andric   if (Error E = Obj.removeLoadCommands(RemovePred))
17281ad6265SDimitry Andric     return E;
17381ad6265SDimitry Andric 
17481ad6265SDimitry Andric   // Emit an error if the Mach-O binary does not contain an rpath path name
17581ad6265SDimitry Andric   // specified in -delete_rpath.
17681ad6265SDimitry Andric   for (StringRef RPath : MachOConfig.RPathsToRemove) {
17781ad6265SDimitry Andric     if (RPathsToRemove.count(RPath))
17881ad6265SDimitry Andric       return createStringError(errc::invalid_argument,
17981ad6265SDimitry Andric                                "no LC_RPATH load command with path: %s",
18081ad6265SDimitry Andric                                RPath.str().c_str());
18181ad6265SDimitry Andric   }
18281ad6265SDimitry Andric 
18381ad6265SDimitry Andric   DenseSet<StringRef> RPaths;
18481ad6265SDimitry Andric 
18581ad6265SDimitry Andric   // Get all existing RPaths.
18681ad6265SDimitry Andric   for (LoadCommand &LC : Obj.LoadCommands) {
18781ad6265SDimitry Andric     if (LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_RPATH)
18881ad6265SDimitry Andric       RPaths.insert(getPayloadString(LC));
18981ad6265SDimitry Andric   }
19081ad6265SDimitry Andric 
19181ad6265SDimitry Andric   // Throw errors for invalid RPaths.
19281ad6265SDimitry Andric   for (const auto &OldNew : MachOConfig.RPathsToUpdate) {
19381ad6265SDimitry Andric     StringRef Old = OldNew.getFirst();
19481ad6265SDimitry Andric     StringRef New = OldNew.getSecond();
19581ad6265SDimitry Andric     if (!RPaths.contains(Old))
19681ad6265SDimitry Andric       return createStringError(errc::invalid_argument,
19781ad6265SDimitry Andric                                "no LC_RPATH load command with path: " + Old);
19881ad6265SDimitry Andric     if (RPaths.contains(New))
19981ad6265SDimitry Andric       return createStringError(errc::invalid_argument,
20081ad6265SDimitry Andric                                "rpath '" + New +
20181ad6265SDimitry Andric                                    "' would create a duplicate load command");
20281ad6265SDimitry Andric   }
20381ad6265SDimitry Andric 
20481ad6265SDimitry Andric   // Update load commands.
20581ad6265SDimitry Andric   for (LoadCommand &LC : Obj.LoadCommands) {
20681ad6265SDimitry Andric     switch (LC.MachOLoadCommand.load_command_data.cmd) {
20781ad6265SDimitry Andric     case MachO::LC_ID_DYLIB:
20881ad6265SDimitry Andric       if (MachOConfig.SharedLibId)
20981ad6265SDimitry Andric         updateLoadCommandPayloadString<MachO::dylib_command>(
21081ad6265SDimitry Andric             LC, *MachOConfig.SharedLibId);
21181ad6265SDimitry Andric       break;
21281ad6265SDimitry Andric 
21381ad6265SDimitry Andric     case MachO::LC_RPATH: {
21481ad6265SDimitry Andric       StringRef RPath = getPayloadString(LC);
21581ad6265SDimitry Andric       StringRef NewRPath = MachOConfig.RPathsToUpdate.lookup(RPath);
21681ad6265SDimitry Andric       if (!NewRPath.empty())
21781ad6265SDimitry Andric         updateLoadCommandPayloadString<MachO::rpath_command>(LC, NewRPath);
21881ad6265SDimitry Andric       break;
21981ad6265SDimitry Andric     }
22081ad6265SDimitry Andric 
22181ad6265SDimitry Andric     // TODO: Add LC_REEXPORT_DYLIB, LC_LAZY_LOAD_DYLIB, and LC_LOAD_UPWARD_DYLIB
22281ad6265SDimitry Andric     // here once llvm-objcopy supports them.
22381ad6265SDimitry Andric     case MachO::LC_LOAD_DYLIB:
22481ad6265SDimitry Andric     case MachO::LC_LOAD_WEAK_DYLIB:
22581ad6265SDimitry Andric       StringRef InstallName = getPayloadString(LC);
22681ad6265SDimitry Andric       StringRef NewInstallName =
22781ad6265SDimitry Andric           MachOConfig.InstallNamesToUpdate.lookup(InstallName);
22881ad6265SDimitry Andric       if (!NewInstallName.empty())
22981ad6265SDimitry Andric         updateLoadCommandPayloadString<MachO::dylib_command>(LC,
23081ad6265SDimitry Andric                                                              NewInstallName);
23181ad6265SDimitry Andric       break;
23281ad6265SDimitry Andric     }
23381ad6265SDimitry Andric   }
23481ad6265SDimitry Andric 
23581ad6265SDimitry Andric   // Add new RPaths.
23681ad6265SDimitry Andric   for (StringRef RPath : MachOConfig.RPathToAdd) {
23781ad6265SDimitry Andric     if (RPaths.contains(RPath))
23881ad6265SDimitry Andric       return createStringError(errc::invalid_argument,
23981ad6265SDimitry Andric                                "rpath '" + RPath +
24081ad6265SDimitry Andric                                    "' would create a duplicate load command");
24181ad6265SDimitry Andric     RPaths.insert(RPath);
24281ad6265SDimitry Andric     Obj.LoadCommands.push_back(buildRPathLoadCommand(RPath));
24381ad6265SDimitry Andric   }
24481ad6265SDimitry Andric 
24581ad6265SDimitry Andric   for (StringRef RPath : MachOConfig.RPathToPrepend) {
24681ad6265SDimitry Andric     if (RPaths.contains(RPath))
24781ad6265SDimitry Andric       return createStringError(errc::invalid_argument,
24881ad6265SDimitry Andric                                "rpath '" + RPath +
24981ad6265SDimitry Andric                                    "' would create a duplicate load command");
25081ad6265SDimitry Andric 
25181ad6265SDimitry Andric     RPaths.insert(RPath);
25281ad6265SDimitry Andric     Obj.LoadCommands.insert(Obj.LoadCommands.begin(),
25381ad6265SDimitry Andric                             buildRPathLoadCommand(RPath));
25481ad6265SDimitry Andric   }
25581ad6265SDimitry Andric 
25681ad6265SDimitry Andric   // Unlike appending rpaths, the indexes of subsequent load commands must
25781ad6265SDimitry Andric   // be recalculated after prepending one.
25881ad6265SDimitry Andric   if (!MachOConfig.RPathToPrepend.empty())
25981ad6265SDimitry Andric     Obj.updateLoadCommandIndexes();
26081ad6265SDimitry Andric 
26181ad6265SDimitry Andric   // Remove any empty segments if required.
26281ad6265SDimitry Andric   if (!MachOConfig.EmptySegmentsToRemove.empty()) {
26381ad6265SDimitry Andric     auto RemovePred = [&MachOConfig](const LoadCommand &LC) {
26481ad6265SDimitry Andric       if (LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_SEGMENT_64 ||
26581ad6265SDimitry Andric           LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_SEGMENT) {
26681ad6265SDimitry Andric         return LC.Sections.empty() &&
26781ad6265SDimitry Andric                MachOConfig.EmptySegmentsToRemove.contains(*LC.getSegmentName());
26881ad6265SDimitry Andric       }
26981ad6265SDimitry Andric       return false;
27081ad6265SDimitry Andric     };
27181ad6265SDimitry Andric     if (Error E = Obj.removeLoadCommands(RemovePred))
27281ad6265SDimitry Andric       return E;
27381ad6265SDimitry Andric   }
27481ad6265SDimitry Andric 
27581ad6265SDimitry Andric   return Error::success();
27681ad6265SDimitry Andric }
27781ad6265SDimitry Andric 
27881ad6265SDimitry Andric static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
27981ad6265SDimitry Andric                                Object &Obj) {
28081ad6265SDimitry Andric   for (LoadCommand &LC : Obj.LoadCommands)
28181ad6265SDimitry Andric     for (const std::unique_ptr<Section> &Sec : LC.Sections) {
28281ad6265SDimitry Andric       if (Sec->CanonicalName == SecName) {
28381ad6265SDimitry Andric         Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
28481ad6265SDimitry Andric             FileOutputBuffer::create(Filename, Sec->Content.size());
28581ad6265SDimitry Andric         if (!BufferOrErr)
28681ad6265SDimitry Andric           return BufferOrErr.takeError();
28781ad6265SDimitry Andric         std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr);
28881ad6265SDimitry Andric         llvm::copy(Sec->Content, Buf->getBufferStart());
28981ad6265SDimitry Andric 
29081ad6265SDimitry Andric         if (Error E = Buf->commit())
29181ad6265SDimitry Andric           return E;
29281ad6265SDimitry Andric         return Error::success();
29381ad6265SDimitry Andric       }
29481ad6265SDimitry Andric     }
29581ad6265SDimitry Andric 
29681ad6265SDimitry Andric   return createStringError(object_error::parse_failed, "section '%s' not found",
29781ad6265SDimitry Andric                            SecName.str().c_str());
29881ad6265SDimitry Andric }
29981ad6265SDimitry Andric 
30081ad6265SDimitry Andric static Error addSection(const NewSectionInfo &NewSection, Object &Obj) {
30181ad6265SDimitry Andric   std::pair<StringRef, StringRef> Pair = NewSection.SectionName.split(',');
30281ad6265SDimitry Andric   StringRef TargetSegName = Pair.first;
30381ad6265SDimitry Andric   Section Sec(TargetSegName, Pair.second);
30481ad6265SDimitry Andric   Sec.Content =
30581ad6265SDimitry Andric       Obj.NewSectionsContents.save(NewSection.SectionData->getBuffer());
30681ad6265SDimitry Andric   Sec.Size = Sec.Content.size();
30781ad6265SDimitry Andric 
30881ad6265SDimitry Andric   // Add the a section into an existing segment.
30981ad6265SDimitry Andric   for (LoadCommand &LC : Obj.LoadCommands) {
310*bdd1243dSDimitry Andric     std::optional<StringRef> SegName = LC.getSegmentName();
31181ad6265SDimitry Andric     if (SegName && SegName == TargetSegName) {
31281ad6265SDimitry Andric       uint64_t Addr = *LC.getSegmentVMAddr();
31381ad6265SDimitry Andric       for (const std::unique_ptr<Section> &S : LC.Sections)
31481ad6265SDimitry Andric         Addr = std::max(Addr, S->Addr + S->Size);
31581ad6265SDimitry Andric       LC.Sections.push_back(std::make_unique<Section>(Sec));
31681ad6265SDimitry Andric       LC.Sections.back()->Addr = Addr;
31781ad6265SDimitry Andric       return Error::success();
31881ad6265SDimitry Andric     }
31981ad6265SDimitry Andric   }
32081ad6265SDimitry Andric 
32181ad6265SDimitry Andric   // There's no segment named TargetSegName. Create a new load command and
32281ad6265SDimitry Andric   // Insert a new section into it.
32381ad6265SDimitry Andric   LoadCommand &NewSegment =
32481ad6265SDimitry Andric       Obj.addSegment(TargetSegName, alignTo(Sec.Size, 16384));
32581ad6265SDimitry Andric   NewSegment.Sections.push_back(std::make_unique<Section>(Sec));
32681ad6265SDimitry Andric   NewSegment.Sections.back()->Addr = *NewSegment.getSegmentVMAddr();
32781ad6265SDimitry Andric   return Error::success();
32881ad6265SDimitry Andric }
32981ad6265SDimitry Andric 
33081ad6265SDimitry Andric static Expected<Section &> findSection(StringRef SecName, Object &O) {
33181ad6265SDimitry Andric   StringRef SegName;
33281ad6265SDimitry Andric   std::tie(SegName, SecName) = SecName.split(",");
33381ad6265SDimitry Andric   auto FoundSeg =
33481ad6265SDimitry Andric       llvm::find_if(O.LoadCommands, [SegName](const LoadCommand &LC) {
33581ad6265SDimitry Andric         return LC.getSegmentName() == SegName;
33681ad6265SDimitry Andric       });
33781ad6265SDimitry Andric   if (FoundSeg == O.LoadCommands.end())
33881ad6265SDimitry Andric     return createStringError(errc::invalid_argument,
33981ad6265SDimitry Andric                              "could not find segment with name '%s'",
34081ad6265SDimitry Andric                              SegName.str().c_str());
34181ad6265SDimitry Andric   auto FoundSec = llvm::find_if(FoundSeg->Sections,
34281ad6265SDimitry Andric                                 [SecName](const std::unique_ptr<Section> &Sec) {
34381ad6265SDimitry Andric                                   return Sec->Sectname == SecName;
34481ad6265SDimitry Andric                                 });
34581ad6265SDimitry Andric   if (FoundSec == FoundSeg->Sections.end())
34681ad6265SDimitry Andric     return createStringError(errc::invalid_argument,
34781ad6265SDimitry Andric                              "could not find section with name '%s'",
34881ad6265SDimitry Andric                              SecName.str().c_str());
34981ad6265SDimitry Andric 
35081ad6265SDimitry Andric   assert(FoundSec->get()->CanonicalName == (SegName + "," + SecName).str());
351*bdd1243dSDimitry Andric   return **FoundSec;
35281ad6265SDimitry Andric }
35381ad6265SDimitry Andric 
35481ad6265SDimitry Andric static Error updateSection(const NewSectionInfo &NewSection, Object &O) {
35581ad6265SDimitry Andric   Expected<Section &> SecToUpdateOrErr = findSection(NewSection.SectionName, O);
35681ad6265SDimitry Andric 
35781ad6265SDimitry Andric   if (!SecToUpdateOrErr)
35881ad6265SDimitry Andric     return SecToUpdateOrErr.takeError();
35981ad6265SDimitry Andric   Section &Sec = *SecToUpdateOrErr;
36081ad6265SDimitry Andric 
36181ad6265SDimitry Andric   if (NewSection.SectionData->getBufferSize() > Sec.Size)
36281ad6265SDimitry Andric     return createStringError(
36381ad6265SDimitry Andric         errc::invalid_argument,
36481ad6265SDimitry Andric         "new section cannot be larger than previous section");
36581ad6265SDimitry Andric   Sec.Content = O.NewSectionsContents.save(NewSection.SectionData->getBuffer());
36681ad6265SDimitry Andric   Sec.Size = Sec.Content.size();
36781ad6265SDimitry Andric   return Error::success();
36881ad6265SDimitry Andric }
36981ad6265SDimitry Andric 
37081ad6265SDimitry Andric // isValidMachOCannonicalName returns success if Name is a MachO cannonical name
37181ad6265SDimitry Andric // ("<segment>,<section>") and lengths of both segment and section names are
37281ad6265SDimitry Andric // valid.
37381ad6265SDimitry Andric static Error isValidMachOCannonicalName(StringRef Name) {
37481ad6265SDimitry Andric   if (Name.count(',') != 1)
37581ad6265SDimitry Andric     return createStringError(errc::invalid_argument,
37681ad6265SDimitry Andric                              "invalid section name '%s' (should be formatted "
37781ad6265SDimitry Andric                              "as '<segment name>,<section name>')",
37881ad6265SDimitry Andric                              Name.str().c_str());
37981ad6265SDimitry Andric 
38081ad6265SDimitry Andric   std::pair<StringRef, StringRef> Pair = Name.split(',');
38181ad6265SDimitry Andric   if (Pair.first.size() > 16)
38281ad6265SDimitry Andric     return createStringError(errc::invalid_argument,
38381ad6265SDimitry Andric                              "too long segment name: '%s'",
38481ad6265SDimitry Andric                              Pair.first.str().c_str());
38581ad6265SDimitry Andric   if (Pair.second.size() > 16)
38681ad6265SDimitry Andric     return createStringError(errc::invalid_argument,
38781ad6265SDimitry Andric                              "too long section name: '%s'",
38881ad6265SDimitry Andric                              Pair.second.str().c_str());
38981ad6265SDimitry Andric   return Error::success();
39081ad6265SDimitry Andric }
39181ad6265SDimitry Andric 
39281ad6265SDimitry Andric static Error handleArgs(const CommonConfig &Config,
39381ad6265SDimitry Andric                         const MachOConfig &MachOConfig, Object &Obj) {
39481ad6265SDimitry Andric   // Dump sections before add/remove for compatibility with GNU objcopy.
39581ad6265SDimitry Andric   for (StringRef Flag : Config.DumpSection) {
39681ad6265SDimitry Andric     StringRef SectionName;
39781ad6265SDimitry Andric     StringRef FileName;
39881ad6265SDimitry Andric     std::tie(SectionName, FileName) = Flag.split('=');
39981ad6265SDimitry Andric     if (Error E = dumpSectionToFile(SectionName, FileName, Obj))
40081ad6265SDimitry Andric       return E;
40181ad6265SDimitry Andric   }
40281ad6265SDimitry Andric 
40381ad6265SDimitry Andric   if (Error E = removeSections(Config, Obj))
40481ad6265SDimitry Andric     return E;
40581ad6265SDimitry Andric 
40681ad6265SDimitry Andric   // Mark symbols to determine which symbols are still needed.
40781ad6265SDimitry Andric   if (Config.StripAll)
40881ad6265SDimitry Andric     markSymbols(Config, Obj);
40981ad6265SDimitry Andric 
41081ad6265SDimitry Andric   updateAndRemoveSymbols(Config, MachOConfig, Obj);
41181ad6265SDimitry Andric 
41281ad6265SDimitry Andric   if (Config.StripAll)
41381ad6265SDimitry Andric     for (LoadCommand &LC : Obj.LoadCommands)
41481ad6265SDimitry Andric       for (std::unique_ptr<Section> &Sec : LC.Sections)
41581ad6265SDimitry Andric         Sec->Relocations.clear();
41681ad6265SDimitry Andric 
41781ad6265SDimitry Andric   for (const NewSectionInfo &NewSection : Config.AddSection) {
41881ad6265SDimitry Andric     if (Error E = isValidMachOCannonicalName(NewSection.SectionName))
41981ad6265SDimitry Andric       return E;
42081ad6265SDimitry Andric     if (Error E = addSection(NewSection, Obj))
42181ad6265SDimitry Andric       return E;
42281ad6265SDimitry Andric   }
42381ad6265SDimitry Andric 
42481ad6265SDimitry Andric   for (const NewSectionInfo &NewSection : Config.UpdateSection) {
42581ad6265SDimitry Andric     if (Error E = isValidMachOCannonicalName(NewSection.SectionName))
42681ad6265SDimitry Andric       return E;
42781ad6265SDimitry Andric     if (Error E = updateSection(NewSection, Obj))
42881ad6265SDimitry Andric       return E;
42981ad6265SDimitry Andric   }
43081ad6265SDimitry Andric 
43181ad6265SDimitry Andric   if (Error E = processLoadCommands(MachOConfig, Obj))
43281ad6265SDimitry Andric     return E;
43381ad6265SDimitry Andric 
43481ad6265SDimitry Andric   return Error::success();
43581ad6265SDimitry Andric }
43681ad6265SDimitry Andric 
43781ad6265SDimitry Andric Error objcopy::macho::executeObjcopyOnBinary(const CommonConfig &Config,
43881ad6265SDimitry Andric                                              const MachOConfig &MachOConfig,
43981ad6265SDimitry Andric                                              object::MachOObjectFile &In,
44081ad6265SDimitry Andric                                              raw_ostream &Out) {
44181ad6265SDimitry Andric   MachOReader Reader(In);
44281ad6265SDimitry Andric   Expected<std::unique_ptr<Object>> O = Reader.create();
44381ad6265SDimitry Andric   if (!O)
44481ad6265SDimitry Andric     return createFileError(Config.InputFilename, O.takeError());
44581ad6265SDimitry Andric 
44681ad6265SDimitry Andric   if (O->get()->Header.FileType == MachO::HeaderFileType::MH_PRELOAD)
44781ad6265SDimitry Andric     return createStringError(std::errc::not_supported,
44881ad6265SDimitry Andric                              "%s: MH_PRELOAD files are not supported",
44981ad6265SDimitry Andric                              Config.InputFilename.str().c_str());
45081ad6265SDimitry Andric 
45181ad6265SDimitry Andric   if (Error E = handleArgs(Config, MachOConfig, **O))
45281ad6265SDimitry Andric     return createFileError(Config.InputFilename, std::move(E));
45381ad6265SDimitry Andric 
45481ad6265SDimitry Andric   // Page size used for alignment of segment sizes in Mach-O executables and
45581ad6265SDimitry Andric   // dynamic libraries.
45681ad6265SDimitry Andric   uint64_t PageSize;
45781ad6265SDimitry Andric   switch (In.getArch()) {
45881ad6265SDimitry Andric   case Triple::ArchType::arm:
45981ad6265SDimitry Andric   case Triple::ArchType::aarch64:
46081ad6265SDimitry Andric   case Triple::ArchType::aarch64_32:
46181ad6265SDimitry Andric     PageSize = 16384;
46281ad6265SDimitry Andric     break;
46381ad6265SDimitry Andric   default:
46481ad6265SDimitry Andric     PageSize = 4096;
46581ad6265SDimitry Andric   }
46681ad6265SDimitry Andric 
46781ad6265SDimitry Andric   MachOWriter Writer(**O, In.is64Bit(), In.isLittleEndian(),
46881ad6265SDimitry Andric                      sys::path::filename(Config.OutputFilename), PageSize, Out);
46981ad6265SDimitry Andric   if (auto E = Writer.finalize())
47081ad6265SDimitry Andric     return E;
47181ad6265SDimitry Andric   return Writer.write();
47281ad6265SDimitry Andric }
47381ad6265SDimitry Andric 
47481ad6265SDimitry Andric Error objcopy::macho::executeObjcopyOnMachOUniversalBinary(
47581ad6265SDimitry Andric     const MultiFormatConfig &Config, const MachOUniversalBinary &In,
47681ad6265SDimitry Andric     raw_ostream &Out) {
47781ad6265SDimitry Andric   SmallVector<OwningBinary<Binary>, 2> Binaries;
47881ad6265SDimitry Andric   SmallVector<Slice, 2> Slices;
47981ad6265SDimitry Andric   for (const auto &O : In.objects()) {
48081ad6265SDimitry Andric     Expected<std::unique_ptr<Archive>> ArOrErr = O.getAsArchive();
48181ad6265SDimitry Andric     if (ArOrErr) {
48281ad6265SDimitry Andric       Expected<std::vector<NewArchiveMember>> NewArchiveMembersOrErr =
48381ad6265SDimitry Andric           createNewArchiveMembers(Config, **ArOrErr);
48481ad6265SDimitry Andric       if (!NewArchiveMembersOrErr)
48581ad6265SDimitry Andric         return NewArchiveMembersOrErr.takeError();
48681ad6265SDimitry Andric       auto Kind = (*ArOrErr)->kind();
48781ad6265SDimitry Andric       if (Kind == object::Archive::K_BSD)
48881ad6265SDimitry Andric         Kind = object::Archive::K_DARWIN;
48981ad6265SDimitry Andric       Expected<std::unique_ptr<MemoryBuffer>> OutputBufferOrErr =
49081ad6265SDimitry Andric           writeArchiveToBuffer(*NewArchiveMembersOrErr,
49181ad6265SDimitry Andric                                (*ArOrErr)->hasSymbolTable(), Kind,
49281ad6265SDimitry Andric                                Config.getCommonConfig().DeterministicArchives,
49381ad6265SDimitry Andric                                (*ArOrErr)->isThin());
49481ad6265SDimitry Andric       if (!OutputBufferOrErr)
49581ad6265SDimitry Andric         return OutputBufferOrErr.takeError();
49681ad6265SDimitry Andric       Expected<std::unique_ptr<Binary>> BinaryOrErr =
49781ad6265SDimitry Andric           object::createBinary(**OutputBufferOrErr);
49881ad6265SDimitry Andric       if (!BinaryOrErr)
49981ad6265SDimitry Andric         return BinaryOrErr.takeError();
50081ad6265SDimitry Andric       Binaries.emplace_back(std::move(*BinaryOrErr),
50181ad6265SDimitry Andric                             std::move(*OutputBufferOrErr));
50281ad6265SDimitry Andric       Slices.emplace_back(*cast<Archive>(Binaries.back().getBinary()),
50381ad6265SDimitry Andric                           O.getCPUType(), O.getCPUSubType(),
50481ad6265SDimitry Andric                           O.getArchFlagName(), O.getAlign());
50581ad6265SDimitry Andric       continue;
50681ad6265SDimitry Andric     }
50781ad6265SDimitry Andric     // The methods getAsArchive, getAsObjectFile, getAsIRObject of the class
50881ad6265SDimitry Andric     // ObjectForArch return an Error in case of the type mismatch. We need to
50981ad6265SDimitry Andric     // check each in turn to see what kind of slice this is, so ignore errors
51081ad6265SDimitry Andric     // produced along the way.
51181ad6265SDimitry Andric     consumeError(ArOrErr.takeError());
51281ad6265SDimitry Andric 
51381ad6265SDimitry Andric     Expected<std::unique_ptr<MachOObjectFile>> ObjOrErr = O.getAsObjectFile();
51481ad6265SDimitry Andric     if (!ObjOrErr) {
51581ad6265SDimitry Andric       consumeError(ObjOrErr.takeError());
51681ad6265SDimitry Andric       return createStringError(
51781ad6265SDimitry Andric           std::errc::invalid_argument,
51881ad6265SDimitry Andric           "slice for '%s' of the universal Mach-O binary "
51981ad6265SDimitry Andric           "'%s' is not a Mach-O object or an archive",
52081ad6265SDimitry Andric           O.getArchFlagName().c_str(),
52181ad6265SDimitry Andric           Config.getCommonConfig().InputFilename.str().c_str());
52281ad6265SDimitry Andric     }
52381ad6265SDimitry Andric     std::string ArchFlagName = O.getArchFlagName();
52481ad6265SDimitry Andric 
52581ad6265SDimitry Andric     SmallVector<char, 0> Buffer;
52681ad6265SDimitry Andric     raw_svector_ostream MemStream(Buffer);
52781ad6265SDimitry Andric 
52881ad6265SDimitry Andric     Expected<const MachOConfig &> MachO = Config.getMachOConfig();
52981ad6265SDimitry Andric     if (!MachO)
53081ad6265SDimitry Andric       return MachO.takeError();
53181ad6265SDimitry Andric 
53281ad6265SDimitry Andric     if (Error E = executeObjcopyOnBinary(Config.getCommonConfig(), *MachO,
53381ad6265SDimitry Andric                                          **ObjOrErr, MemStream))
53481ad6265SDimitry Andric       return E;
53581ad6265SDimitry Andric 
53681ad6265SDimitry Andric     auto MB = std::make_unique<SmallVectorMemoryBuffer>(
53781ad6265SDimitry Andric         std::move(Buffer), ArchFlagName, /*RequiresNullTerminator=*/false);
53881ad6265SDimitry Andric     Expected<std::unique_ptr<Binary>> BinaryOrErr = object::createBinary(*MB);
53981ad6265SDimitry Andric     if (!BinaryOrErr)
54081ad6265SDimitry Andric       return BinaryOrErr.takeError();
54181ad6265SDimitry Andric     Binaries.emplace_back(std::move(*BinaryOrErr), std::move(MB));
54281ad6265SDimitry Andric     Slices.emplace_back(*cast<MachOObjectFile>(Binaries.back().getBinary()),
54381ad6265SDimitry Andric                         O.getAlign());
54481ad6265SDimitry Andric   }
54581ad6265SDimitry Andric 
54681ad6265SDimitry Andric   if (Error Err = writeUniversalBinaryToStream(Slices, Out))
54781ad6265SDimitry Andric     return Err;
54881ad6265SDimitry Andric 
54981ad6265SDimitry Andric   return Error::success();
55081ad6265SDimitry Andric }
551