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
isLoadCommandWithPayloadString(const LoadCommand & LC)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 
getPayloadString(const LoadCommand & LC)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 
removeSections(const CommonConfig & Config,Object & Obj)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 
markSymbols(const CommonConfig &,Object & Obj)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 
updateAndRemoveSymbols(const CommonConfig & Config,const MachOConfig & MachOConfig,Object & Obj)9381ad6265SDimitry Andric static void updateAndRemoveSymbols(const CommonConfig &Config,
9481ad6265SDimitry Andric                                    const MachOConfig &MachOConfig,
9581ad6265SDimitry Andric                                    Object &Obj) {
9681ad6265SDimitry Andric   for (SymbolEntry &Sym : Obj.SymTable) {
97*5f757f3fSDimitry Andric     // Weaken symbols first to match ELFObjcopy behavior.
98*5f757f3fSDimitry Andric     bool IsExportedAndDefined =
99*5f757f3fSDimitry Andric         (Sym.n_type & llvm::MachO::N_EXT) &&
100*5f757f3fSDimitry Andric         (Sym.n_type & llvm::MachO::N_TYPE) != llvm::MachO::N_UNDF;
101*5f757f3fSDimitry Andric     if (IsExportedAndDefined &&
102*5f757f3fSDimitry Andric         (Config.Weaken || Config.SymbolsToWeaken.matches(Sym.Name)))
103*5f757f3fSDimitry Andric       Sym.n_desc |= llvm::MachO::N_WEAK_DEF;
104*5f757f3fSDimitry Andric 
10581ad6265SDimitry Andric     auto I = Config.SymbolsToRename.find(Sym.Name);
10681ad6265SDimitry Andric     if (I != Config.SymbolsToRename.end())
10781ad6265SDimitry Andric       Sym.Name = std::string(I->getValue());
10881ad6265SDimitry Andric   }
10981ad6265SDimitry Andric 
11081ad6265SDimitry Andric   auto RemovePred = [&Config, &MachOConfig,
11181ad6265SDimitry Andric                      &Obj](const std::unique_ptr<SymbolEntry> &N) {
11281ad6265SDimitry Andric     if (N->Referenced)
11381ad6265SDimitry Andric       return false;
11481ad6265SDimitry Andric     if (MachOConfig.KeepUndefined && N->isUndefinedSymbol())
11581ad6265SDimitry Andric       return false;
11681ad6265SDimitry Andric     if (N->n_desc & MachO::REFERENCED_DYNAMICALLY)
11781ad6265SDimitry Andric       return false;
11881ad6265SDimitry Andric     if (Config.StripAll)
11981ad6265SDimitry Andric       return true;
12081ad6265SDimitry Andric     if (Config.DiscardMode == DiscardType::All && !(N->n_type & MachO::N_EXT))
12181ad6265SDimitry Andric       return true;
12281ad6265SDimitry Andric     // This behavior is consistent with cctools' strip.
12306c3fb27SDimitry Andric     if (Config.StripDebug && (N->n_type & MachO::N_STAB))
12406c3fb27SDimitry Andric       return true;
12506c3fb27SDimitry Andric     // This behavior is consistent with cctools' strip.
12681ad6265SDimitry Andric     if (MachOConfig.StripSwiftSymbols &&
12781ad6265SDimitry Andric         (Obj.Header.Flags & MachO::MH_DYLDLINK) && Obj.SwiftVersion &&
12881ad6265SDimitry Andric         *Obj.SwiftVersion && N->isSwiftSymbol())
12981ad6265SDimitry Andric       return true;
13081ad6265SDimitry Andric     return false;
13181ad6265SDimitry Andric   };
13281ad6265SDimitry Andric 
13381ad6265SDimitry Andric   Obj.SymTable.removeSymbols(RemovePred);
13481ad6265SDimitry Andric }
13581ad6265SDimitry Andric 
13681ad6265SDimitry Andric template <typename LCType>
updateLoadCommandPayloadString(LoadCommand & LC,StringRef S)13781ad6265SDimitry Andric static void updateLoadCommandPayloadString(LoadCommand &LC, StringRef S) {
13881ad6265SDimitry Andric   assert(isLoadCommandWithPayloadString(LC) &&
13981ad6265SDimitry Andric          "unsupported load command encountered");
14081ad6265SDimitry Andric 
14181ad6265SDimitry Andric   uint32_t NewCmdsize = alignTo(sizeof(LCType) + S.size() + 1, 8);
14281ad6265SDimitry Andric 
14381ad6265SDimitry Andric   LC.MachOLoadCommand.load_command_data.cmdsize = NewCmdsize;
14481ad6265SDimitry Andric   LC.Payload.assign(NewCmdsize - sizeof(LCType), 0);
14581ad6265SDimitry Andric   std::copy(S.begin(), S.end(), LC.Payload.begin());
14681ad6265SDimitry Andric }
14781ad6265SDimitry Andric 
buildRPathLoadCommand(StringRef Path)14881ad6265SDimitry Andric static LoadCommand buildRPathLoadCommand(StringRef Path) {
14981ad6265SDimitry Andric   LoadCommand LC;
15081ad6265SDimitry Andric   MachO::rpath_command RPathLC;
15181ad6265SDimitry Andric   RPathLC.cmd = MachO::LC_RPATH;
15281ad6265SDimitry Andric   RPathLC.path = sizeof(MachO::rpath_command);
15381ad6265SDimitry Andric   RPathLC.cmdsize = alignTo(sizeof(MachO::rpath_command) + Path.size() + 1, 8);
15481ad6265SDimitry Andric   LC.MachOLoadCommand.rpath_command_data = RPathLC;
15581ad6265SDimitry Andric   LC.Payload.assign(RPathLC.cmdsize - sizeof(MachO::rpath_command), 0);
15681ad6265SDimitry Andric   std::copy(Path.begin(), Path.end(), LC.Payload.begin());
15781ad6265SDimitry Andric   return LC;
15881ad6265SDimitry Andric }
15981ad6265SDimitry Andric 
processLoadCommands(const MachOConfig & MachOConfig,Object & Obj)16081ad6265SDimitry Andric static Error processLoadCommands(const MachOConfig &MachOConfig, Object &Obj) {
16181ad6265SDimitry Andric   // Remove RPaths.
16281ad6265SDimitry Andric   DenseSet<StringRef> RPathsToRemove(MachOConfig.RPathsToRemove.begin(),
16381ad6265SDimitry Andric                                      MachOConfig.RPathsToRemove.end());
16481ad6265SDimitry Andric 
16581ad6265SDimitry Andric   LoadCommandPred RemovePred = [&RPathsToRemove,
16681ad6265SDimitry Andric                                 &MachOConfig](const LoadCommand &LC) {
16781ad6265SDimitry Andric     if (LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_RPATH) {
16881ad6265SDimitry Andric       // When removing all RPaths we don't need to care
16981ad6265SDimitry Andric       // about what it contains
17081ad6265SDimitry Andric       if (MachOConfig.RemoveAllRpaths)
17181ad6265SDimitry Andric         return true;
17281ad6265SDimitry Andric 
17381ad6265SDimitry Andric       StringRef RPath = getPayloadString(LC);
17481ad6265SDimitry Andric       if (RPathsToRemove.count(RPath)) {
17581ad6265SDimitry Andric         RPathsToRemove.erase(RPath);
17681ad6265SDimitry Andric         return true;
17781ad6265SDimitry Andric       }
17881ad6265SDimitry Andric     }
17981ad6265SDimitry Andric     return false;
18081ad6265SDimitry Andric   };
18181ad6265SDimitry Andric 
18281ad6265SDimitry Andric   if (Error E = Obj.removeLoadCommands(RemovePred))
18381ad6265SDimitry Andric     return E;
18481ad6265SDimitry Andric 
18581ad6265SDimitry Andric   // Emit an error if the Mach-O binary does not contain an rpath path name
18681ad6265SDimitry Andric   // specified in -delete_rpath.
18781ad6265SDimitry Andric   for (StringRef RPath : MachOConfig.RPathsToRemove) {
18881ad6265SDimitry Andric     if (RPathsToRemove.count(RPath))
18981ad6265SDimitry Andric       return createStringError(errc::invalid_argument,
19081ad6265SDimitry Andric                                "no LC_RPATH load command with path: %s",
19181ad6265SDimitry Andric                                RPath.str().c_str());
19281ad6265SDimitry Andric   }
19381ad6265SDimitry Andric 
19481ad6265SDimitry Andric   DenseSet<StringRef> RPaths;
19581ad6265SDimitry Andric 
19681ad6265SDimitry Andric   // Get all existing RPaths.
19781ad6265SDimitry Andric   for (LoadCommand &LC : Obj.LoadCommands) {
19881ad6265SDimitry Andric     if (LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_RPATH)
19981ad6265SDimitry Andric       RPaths.insert(getPayloadString(LC));
20081ad6265SDimitry Andric   }
20181ad6265SDimitry Andric 
20281ad6265SDimitry Andric   // Throw errors for invalid RPaths.
20381ad6265SDimitry Andric   for (const auto &OldNew : MachOConfig.RPathsToUpdate) {
20481ad6265SDimitry Andric     StringRef Old = OldNew.getFirst();
20581ad6265SDimitry Andric     StringRef New = OldNew.getSecond();
20681ad6265SDimitry Andric     if (!RPaths.contains(Old))
20781ad6265SDimitry Andric       return createStringError(errc::invalid_argument,
20881ad6265SDimitry Andric                                "no LC_RPATH load command with path: " + Old);
20981ad6265SDimitry Andric     if (RPaths.contains(New))
21081ad6265SDimitry Andric       return createStringError(errc::invalid_argument,
21181ad6265SDimitry Andric                                "rpath '" + New +
21281ad6265SDimitry Andric                                    "' would create a duplicate load command");
21381ad6265SDimitry Andric   }
21481ad6265SDimitry Andric 
21581ad6265SDimitry Andric   // Update load commands.
21681ad6265SDimitry Andric   for (LoadCommand &LC : Obj.LoadCommands) {
21781ad6265SDimitry Andric     switch (LC.MachOLoadCommand.load_command_data.cmd) {
21881ad6265SDimitry Andric     case MachO::LC_ID_DYLIB:
21981ad6265SDimitry Andric       if (MachOConfig.SharedLibId)
22081ad6265SDimitry Andric         updateLoadCommandPayloadString<MachO::dylib_command>(
22181ad6265SDimitry Andric             LC, *MachOConfig.SharedLibId);
22281ad6265SDimitry Andric       break;
22381ad6265SDimitry Andric 
22481ad6265SDimitry Andric     case MachO::LC_RPATH: {
22581ad6265SDimitry Andric       StringRef RPath = getPayloadString(LC);
22681ad6265SDimitry Andric       StringRef NewRPath = MachOConfig.RPathsToUpdate.lookup(RPath);
22781ad6265SDimitry Andric       if (!NewRPath.empty())
22881ad6265SDimitry Andric         updateLoadCommandPayloadString<MachO::rpath_command>(LC, NewRPath);
22981ad6265SDimitry Andric       break;
23081ad6265SDimitry Andric     }
23181ad6265SDimitry Andric 
23281ad6265SDimitry Andric     // TODO: Add LC_REEXPORT_DYLIB, LC_LAZY_LOAD_DYLIB, and LC_LOAD_UPWARD_DYLIB
23381ad6265SDimitry Andric     // here once llvm-objcopy supports them.
23481ad6265SDimitry Andric     case MachO::LC_LOAD_DYLIB:
23581ad6265SDimitry Andric     case MachO::LC_LOAD_WEAK_DYLIB:
23681ad6265SDimitry Andric       StringRef InstallName = getPayloadString(LC);
23781ad6265SDimitry Andric       StringRef NewInstallName =
23881ad6265SDimitry Andric           MachOConfig.InstallNamesToUpdate.lookup(InstallName);
23981ad6265SDimitry Andric       if (!NewInstallName.empty())
24081ad6265SDimitry Andric         updateLoadCommandPayloadString<MachO::dylib_command>(LC,
24181ad6265SDimitry Andric                                                              NewInstallName);
24281ad6265SDimitry Andric       break;
24381ad6265SDimitry Andric     }
24481ad6265SDimitry Andric   }
24581ad6265SDimitry Andric 
24681ad6265SDimitry Andric   // Add new RPaths.
24781ad6265SDimitry Andric   for (StringRef RPath : MachOConfig.RPathToAdd) {
24881ad6265SDimitry Andric     if (RPaths.contains(RPath))
24981ad6265SDimitry Andric       return createStringError(errc::invalid_argument,
25081ad6265SDimitry Andric                                "rpath '" + RPath +
25181ad6265SDimitry Andric                                    "' would create a duplicate load command");
25281ad6265SDimitry Andric     RPaths.insert(RPath);
25381ad6265SDimitry Andric     Obj.LoadCommands.push_back(buildRPathLoadCommand(RPath));
25481ad6265SDimitry Andric   }
25581ad6265SDimitry Andric 
25681ad6265SDimitry Andric   for (StringRef RPath : MachOConfig.RPathToPrepend) {
25781ad6265SDimitry Andric     if (RPaths.contains(RPath))
25881ad6265SDimitry Andric       return createStringError(errc::invalid_argument,
25981ad6265SDimitry Andric                                "rpath '" + RPath +
26081ad6265SDimitry Andric                                    "' would create a duplicate load command");
26181ad6265SDimitry Andric 
26281ad6265SDimitry Andric     RPaths.insert(RPath);
26381ad6265SDimitry Andric     Obj.LoadCommands.insert(Obj.LoadCommands.begin(),
26481ad6265SDimitry Andric                             buildRPathLoadCommand(RPath));
26581ad6265SDimitry Andric   }
26681ad6265SDimitry Andric 
26781ad6265SDimitry Andric   // Unlike appending rpaths, the indexes of subsequent load commands must
26881ad6265SDimitry Andric   // be recalculated after prepending one.
26981ad6265SDimitry Andric   if (!MachOConfig.RPathToPrepend.empty())
27081ad6265SDimitry Andric     Obj.updateLoadCommandIndexes();
27181ad6265SDimitry Andric 
27281ad6265SDimitry Andric   // Remove any empty segments if required.
27381ad6265SDimitry Andric   if (!MachOConfig.EmptySegmentsToRemove.empty()) {
27481ad6265SDimitry Andric     auto RemovePred = [&MachOConfig](const LoadCommand &LC) {
27581ad6265SDimitry Andric       if (LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_SEGMENT_64 ||
27681ad6265SDimitry Andric           LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_SEGMENT) {
27781ad6265SDimitry Andric         return LC.Sections.empty() &&
27881ad6265SDimitry Andric                MachOConfig.EmptySegmentsToRemove.contains(*LC.getSegmentName());
27981ad6265SDimitry Andric       }
28081ad6265SDimitry Andric       return false;
28181ad6265SDimitry Andric     };
28281ad6265SDimitry Andric     if (Error E = Obj.removeLoadCommands(RemovePred))
28381ad6265SDimitry Andric       return E;
28481ad6265SDimitry Andric   }
28581ad6265SDimitry Andric 
28681ad6265SDimitry Andric   return Error::success();
28781ad6265SDimitry Andric }
28881ad6265SDimitry Andric 
dumpSectionToFile(StringRef SecName,StringRef Filename,Object & Obj)28981ad6265SDimitry Andric static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
29081ad6265SDimitry Andric                                Object &Obj) {
29181ad6265SDimitry Andric   for (LoadCommand &LC : Obj.LoadCommands)
29281ad6265SDimitry Andric     for (const std::unique_ptr<Section> &Sec : LC.Sections) {
29381ad6265SDimitry Andric       if (Sec->CanonicalName == SecName) {
29481ad6265SDimitry Andric         Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
29581ad6265SDimitry Andric             FileOutputBuffer::create(Filename, Sec->Content.size());
29681ad6265SDimitry Andric         if (!BufferOrErr)
29781ad6265SDimitry Andric           return BufferOrErr.takeError();
29881ad6265SDimitry Andric         std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr);
29981ad6265SDimitry Andric         llvm::copy(Sec->Content, Buf->getBufferStart());
30081ad6265SDimitry Andric 
30181ad6265SDimitry Andric         if (Error E = Buf->commit())
30281ad6265SDimitry Andric           return E;
30381ad6265SDimitry Andric         return Error::success();
30481ad6265SDimitry Andric       }
30581ad6265SDimitry Andric     }
30681ad6265SDimitry Andric 
30781ad6265SDimitry Andric   return createStringError(object_error::parse_failed, "section '%s' not found",
30881ad6265SDimitry Andric                            SecName.str().c_str());
30981ad6265SDimitry Andric }
31081ad6265SDimitry Andric 
addSection(const NewSectionInfo & NewSection,Object & Obj)31181ad6265SDimitry Andric static Error addSection(const NewSectionInfo &NewSection, Object &Obj) {
31281ad6265SDimitry Andric   std::pair<StringRef, StringRef> Pair = NewSection.SectionName.split(',');
31381ad6265SDimitry Andric   StringRef TargetSegName = Pair.first;
31481ad6265SDimitry Andric   Section Sec(TargetSegName, Pair.second);
31581ad6265SDimitry Andric   Sec.Content =
31681ad6265SDimitry Andric       Obj.NewSectionsContents.save(NewSection.SectionData->getBuffer());
31781ad6265SDimitry Andric   Sec.Size = Sec.Content.size();
31881ad6265SDimitry Andric 
31981ad6265SDimitry Andric   // Add the a section into an existing segment.
32081ad6265SDimitry Andric   for (LoadCommand &LC : Obj.LoadCommands) {
321bdd1243dSDimitry Andric     std::optional<StringRef> SegName = LC.getSegmentName();
32281ad6265SDimitry Andric     if (SegName && SegName == TargetSegName) {
32381ad6265SDimitry Andric       uint64_t Addr = *LC.getSegmentVMAddr();
32481ad6265SDimitry Andric       for (const std::unique_ptr<Section> &S : LC.Sections)
32581ad6265SDimitry Andric         Addr = std::max(Addr, S->Addr + S->Size);
32681ad6265SDimitry Andric       LC.Sections.push_back(std::make_unique<Section>(Sec));
32781ad6265SDimitry Andric       LC.Sections.back()->Addr = Addr;
32881ad6265SDimitry Andric       return Error::success();
32981ad6265SDimitry Andric     }
33081ad6265SDimitry Andric   }
33181ad6265SDimitry Andric 
33281ad6265SDimitry Andric   // There's no segment named TargetSegName. Create a new load command and
33381ad6265SDimitry Andric   // Insert a new section into it.
33481ad6265SDimitry Andric   LoadCommand &NewSegment =
33581ad6265SDimitry Andric       Obj.addSegment(TargetSegName, alignTo(Sec.Size, 16384));
33681ad6265SDimitry Andric   NewSegment.Sections.push_back(std::make_unique<Section>(Sec));
33781ad6265SDimitry Andric   NewSegment.Sections.back()->Addr = *NewSegment.getSegmentVMAddr();
33881ad6265SDimitry Andric   return Error::success();
33981ad6265SDimitry Andric }
34081ad6265SDimitry Andric 
findSection(StringRef SecName,Object & O)34181ad6265SDimitry Andric static Expected<Section &> findSection(StringRef SecName, Object &O) {
34281ad6265SDimitry Andric   StringRef SegName;
34381ad6265SDimitry Andric   std::tie(SegName, SecName) = SecName.split(",");
34481ad6265SDimitry Andric   auto FoundSeg =
34581ad6265SDimitry Andric       llvm::find_if(O.LoadCommands, [SegName](const LoadCommand &LC) {
34681ad6265SDimitry Andric         return LC.getSegmentName() == SegName;
34781ad6265SDimitry Andric       });
34881ad6265SDimitry Andric   if (FoundSeg == O.LoadCommands.end())
34981ad6265SDimitry Andric     return createStringError(errc::invalid_argument,
35081ad6265SDimitry Andric                              "could not find segment with name '%s'",
35181ad6265SDimitry Andric                              SegName.str().c_str());
35281ad6265SDimitry Andric   auto FoundSec = llvm::find_if(FoundSeg->Sections,
35381ad6265SDimitry Andric                                 [SecName](const std::unique_ptr<Section> &Sec) {
35481ad6265SDimitry Andric                                   return Sec->Sectname == SecName;
35581ad6265SDimitry Andric                                 });
35681ad6265SDimitry Andric   if (FoundSec == FoundSeg->Sections.end())
35781ad6265SDimitry Andric     return createStringError(errc::invalid_argument,
35881ad6265SDimitry Andric                              "could not find section with name '%s'",
35981ad6265SDimitry Andric                              SecName.str().c_str());
36081ad6265SDimitry Andric 
36181ad6265SDimitry Andric   assert(FoundSec->get()->CanonicalName == (SegName + "," + SecName).str());
362bdd1243dSDimitry Andric   return **FoundSec;
36381ad6265SDimitry Andric }
36481ad6265SDimitry Andric 
updateSection(const NewSectionInfo & NewSection,Object & O)36581ad6265SDimitry Andric static Error updateSection(const NewSectionInfo &NewSection, Object &O) {
36681ad6265SDimitry Andric   Expected<Section &> SecToUpdateOrErr = findSection(NewSection.SectionName, O);
36781ad6265SDimitry Andric 
36881ad6265SDimitry Andric   if (!SecToUpdateOrErr)
36981ad6265SDimitry Andric     return SecToUpdateOrErr.takeError();
37081ad6265SDimitry Andric   Section &Sec = *SecToUpdateOrErr;
37181ad6265SDimitry Andric 
37281ad6265SDimitry Andric   if (NewSection.SectionData->getBufferSize() > Sec.Size)
37381ad6265SDimitry Andric     return createStringError(
37481ad6265SDimitry Andric         errc::invalid_argument,
37581ad6265SDimitry Andric         "new section cannot be larger than previous section");
37681ad6265SDimitry Andric   Sec.Content = O.NewSectionsContents.save(NewSection.SectionData->getBuffer());
37781ad6265SDimitry Andric   Sec.Size = Sec.Content.size();
37881ad6265SDimitry Andric   return Error::success();
37981ad6265SDimitry Andric }
38081ad6265SDimitry Andric 
38181ad6265SDimitry Andric // isValidMachOCannonicalName returns success if Name is a MachO cannonical name
38281ad6265SDimitry Andric // ("<segment>,<section>") and lengths of both segment and section names are
38381ad6265SDimitry Andric // valid.
isValidMachOCannonicalName(StringRef Name)38481ad6265SDimitry Andric static Error isValidMachOCannonicalName(StringRef Name) {
38581ad6265SDimitry Andric   if (Name.count(',') != 1)
38681ad6265SDimitry Andric     return createStringError(errc::invalid_argument,
38781ad6265SDimitry Andric                              "invalid section name '%s' (should be formatted "
38881ad6265SDimitry Andric                              "as '<segment name>,<section name>')",
38981ad6265SDimitry Andric                              Name.str().c_str());
39081ad6265SDimitry Andric 
39181ad6265SDimitry Andric   std::pair<StringRef, StringRef> Pair = Name.split(',');
39281ad6265SDimitry Andric   if (Pair.first.size() > 16)
39381ad6265SDimitry Andric     return createStringError(errc::invalid_argument,
39481ad6265SDimitry Andric                              "too long segment name: '%s'",
39581ad6265SDimitry Andric                              Pair.first.str().c_str());
39681ad6265SDimitry Andric   if (Pair.second.size() > 16)
39781ad6265SDimitry Andric     return createStringError(errc::invalid_argument,
39881ad6265SDimitry Andric                              "too long section name: '%s'",
39981ad6265SDimitry Andric                              Pair.second.str().c_str());
40081ad6265SDimitry Andric   return Error::success();
40181ad6265SDimitry Andric }
40281ad6265SDimitry Andric 
handleArgs(const CommonConfig & Config,const MachOConfig & MachOConfig,Object & Obj)40381ad6265SDimitry Andric static Error handleArgs(const CommonConfig &Config,
40481ad6265SDimitry Andric                         const MachOConfig &MachOConfig, Object &Obj) {
40581ad6265SDimitry Andric   // Dump sections before add/remove for compatibility with GNU objcopy.
40681ad6265SDimitry Andric   for (StringRef Flag : Config.DumpSection) {
40781ad6265SDimitry Andric     StringRef SectionName;
40881ad6265SDimitry Andric     StringRef FileName;
40981ad6265SDimitry Andric     std::tie(SectionName, FileName) = Flag.split('=');
41081ad6265SDimitry Andric     if (Error E = dumpSectionToFile(SectionName, FileName, Obj))
41181ad6265SDimitry Andric       return E;
41281ad6265SDimitry Andric   }
41381ad6265SDimitry Andric 
41481ad6265SDimitry Andric   if (Error E = removeSections(Config, Obj))
41581ad6265SDimitry Andric     return E;
41681ad6265SDimitry Andric 
41781ad6265SDimitry Andric   // Mark symbols to determine which symbols are still needed.
41881ad6265SDimitry Andric   if (Config.StripAll)
41981ad6265SDimitry Andric     markSymbols(Config, Obj);
42081ad6265SDimitry Andric 
42181ad6265SDimitry Andric   updateAndRemoveSymbols(Config, MachOConfig, Obj);
42281ad6265SDimitry Andric 
42381ad6265SDimitry Andric   if (Config.StripAll)
42481ad6265SDimitry Andric     for (LoadCommand &LC : Obj.LoadCommands)
42581ad6265SDimitry Andric       for (std::unique_ptr<Section> &Sec : LC.Sections)
42681ad6265SDimitry Andric         Sec->Relocations.clear();
42781ad6265SDimitry Andric 
42881ad6265SDimitry Andric   for (const NewSectionInfo &NewSection : Config.AddSection) {
42981ad6265SDimitry Andric     if (Error E = isValidMachOCannonicalName(NewSection.SectionName))
43081ad6265SDimitry Andric       return E;
43181ad6265SDimitry Andric     if (Error E = addSection(NewSection, Obj))
43281ad6265SDimitry Andric       return E;
43381ad6265SDimitry Andric   }
43481ad6265SDimitry Andric 
43581ad6265SDimitry Andric   for (const NewSectionInfo &NewSection : Config.UpdateSection) {
43681ad6265SDimitry Andric     if (Error E = isValidMachOCannonicalName(NewSection.SectionName))
43781ad6265SDimitry Andric       return E;
43881ad6265SDimitry Andric     if (Error E = updateSection(NewSection, Obj))
43981ad6265SDimitry Andric       return E;
44081ad6265SDimitry Andric   }
44181ad6265SDimitry Andric 
44281ad6265SDimitry Andric   if (Error E = processLoadCommands(MachOConfig, Obj))
44381ad6265SDimitry Andric     return E;
44481ad6265SDimitry Andric 
44581ad6265SDimitry Andric   return Error::success();
44681ad6265SDimitry Andric }
44781ad6265SDimitry Andric 
executeObjcopyOnBinary(const CommonConfig & Config,const MachOConfig & MachOConfig,object::MachOObjectFile & In,raw_ostream & Out)44881ad6265SDimitry Andric Error objcopy::macho::executeObjcopyOnBinary(const CommonConfig &Config,
44981ad6265SDimitry Andric                                              const MachOConfig &MachOConfig,
45081ad6265SDimitry Andric                                              object::MachOObjectFile &In,
45181ad6265SDimitry Andric                                              raw_ostream &Out) {
45281ad6265SDimitry Andric   MachOReader Reader(In);
45381ad6265SDimitry Andric   Expected<std::unique_ptr<Object>> O = Reader.create();
45481ad6265SDimitry Andric   if (!O)
45581ad6265SDimitry Andric     return createFileError(Config.InputFilename, O.takeError());
45681ad6265SDimitry Andric 
45781ad6265SDimitry Andric   if (O->get()->Header.FileType == MachO::HeaderFileType::MH_PRELOAD)
45881ad6265SDimitry Andric     return createStringError(std::errc::not_supported,
45981ad6265SDimitry Andric                              "%s: MH_PRELOAD files are not supported",
46081ad6265SDimitry Andric                              Config.InputFilename.str().c_str());
46181ad6265SDimitry Andric 
46281ad6265SDimitry Andric   if (Error E = handleArgs(Config, MachOConfig, **O))
46381ad6265SDimitry Andric     return createFileError(Config.InputFilename, std::move(E));
46481ad6265SDimitry Andric 
46581ad6265SDimitry Andric   // Page size used for alignment of segment sizes in Mach-O executables and
46681ad6265SDimitry Andric   // dynamic libraries.
46781ad6265SDimitry Andric   uint64_t PageSize;
46881ad6265SDimitry Andric   switch (In.getArch()) {
46981ad6265SDimitry Andric   case Triple::ArchType::arm:
47081ad6265SDimitry Andric   case Triple::ArchType::aarch64:
47181ad6265SDimitry Andric   case Triple::ArchType::aarch64_32:
47281ad6265SDimitry Andric     PageSize = 16384;
47381ad6265SDimitry Andric     break;
47481ad6265SDimitry Andric   default:
47581ad6265SDimitry Andric     PageSize = 4096;
47681ad6265SDimitry Andric   }
47781ad6265SDimitry Andric 
47881ad6265SDimitry Andric   MachOWriter Writer(**O, In.is64Bit(), In.isLittleEndian(),
47981ad6265SDimitry Andric                      sys::path::filename(Config.OutputFilename), PageSize, Out);
48081ad6265SDimitry Andric   if (auto E = Writer.finalize())
48181ad6265SDimitry Andric     return E;
48281ad6265SDimitry Andric   return Writer.write();
48381ad6265SDimitry Andric }
48481ad6265SDimitry Andric 
executeObjcopyOnMachOUniversalBinary(const MultiFormatConfig & Config,const MachOUniversalBinary & In,raw_ostream & Out)48581ad6265SDimitry Andric Error objcopy::macho::executeObjcopyOnMachOUniversalBinary(
48681ad6265SDimitry Andric     const MultiFormatConfig &Config, const MachOUniversalBinary &In,
48781ad6265SDimitry Andric     raw_ostream &Out) {
48881ad6265SDimitry Andric   SmallVector<OwningBinary<Binary>, 2> Binaries;
48981ad6265SDimitry Andric   SmallVector<Slice, 2> Slices;
49081ad6265SDimitry Andric   for (const auto &O : In.objects()) {
49181ad6265SDimitry Andric     Expected<std::unique_ptr<Archive>> ArOrErr = O.getAsArchive();
49281ad6265SDimitry Andric     if (ArOrErr) {
49381ad6265SDimitry Andric       Expected<std::vector<NewArchiveMember>> NewArchiveMembersOrErr =
49481ad6265SDimitry Andric           createNewArchiveMembers(Config, **ArOrErr);
49581ad6265SDimitry Andric       if (!NewArchiveMembersOrErr)
49681ad6265SDimitry Andric         return NewArchiveMembersOrErr.takeError();
49781ad6265SDimitry Andric       auto Kind = (*ArOrErr)->kind();
49881ad6265SDimitry Andric       if (Kind == object::Archive::K_BSD)
49981ad6265SDimitry Andric         Kind = object::Archive::K_DARWIN;
50081ad6265SDimitry Andric       Expected<std::unique_ptr<MemoryBuffer>> OutputBufferOrErr =
501*5f757f3fSDimitry Andric           writeArchiveToBuffer(
502*5f757f3fSDimitry Andric               *NewArchiveMembersOrErr,
503*5f757f3fSDimitry Andric               (*ArOrErr)->hasSymbolTable() ? SymtabWritingMode::NormalSymtab
504*5f757f3fSDimitry Andric                                            : SymtabWritingMode::NoSymtab,
505*5f757f3fSDimitry Andric               Kind, Config.getCommonConfig().DeterministicArchives,
50681ad6265SDimitry Andric               (*ArOrErr)->isThin());
50781ad6265SDimitry Andric       if (!OutputBufferOrErr)
50881ad6265SDimitry Andric         return OutputBufferOrErr.takeError();
50981ad6265SDimitry Andric       Expected<std::unique_ptr<Binary>> BinaryOrErr =
51081ad6265SDimitry Andric           object::createBinary(**OutputBufferOrErr);
51181ad6265SDimitry Andric       if (!BinaryOrErr)
51281ad6265SDimitry Andric         return BinaryOrErr.takeError();
51381ad6265SDimitry Andric       Binaries.emplace_back(std::move(*BinaryOrErr),
51481ad6265SDimitry Andric                             std::move(*OutputBufferOrErr));
51581ad6265SDimitry Andric       Slices.emplace_back(*cast<Archive>(Binaries.back().getBinary()),
51681ad6265SDimitry Andric                           O.getCPUType(), O.getCPUSubType(),
51781ad6265SDimitry Andric                           O.getArchFlagName(), O.getAlign());
51881ad6265SDimitry Andric       continue;
51981ad6265SDimitry Andric     }
52081ad6265SDimitry Andric     // The methods getAsArchive, getAsObjectFile, getAsIRObject of the class
52181ad6265SDimitry Andric     // ObjectForArch return an Error in case of the type mismatch. We need to
52281ad6265SDimitry Andric     // check each in turn to see what kind of slice this is, so ignore errors
52381ad6265SDimitry Andric     // produced along the way.
52481ad6265SDimitry Andric     consumeError(ArOrErr.takeError());
52581ad6265SDimitry Andric 
52681ad6265SDimitry Andric     Expected<std::unique_ptr<MachOObjectFile>> ObjOrErr = O.getAsObjectFile();
52781ad6265SDimitry Andric     if (!ObjOrErr) {
52881ad6265SDimitry Andric       consumeError(ObjOrErr.takeError());
52981ad6265SDimitry Andric       return createStringError(
53081ad6265SDimitry Andric           std::errc::invalid_argument,
53181ad6265SDimitry Andric           "slice for '%s' of the universal Mach-O binary "
53281ad6265SDimitry Andric           "'%s' is not a Mach-O object or an archive",
53381ad6265SDimitry Andric           O.getArchFlagName().c_str(),
53481ad6265SDimitry Andric           Config.getCommonConfig().InputFilename.str().c_str());
53581ad6265SDimitry Andric     }
53681ad6265SDimitry Andric     std::string ArchFlagName = O.getArchFlagName();
53781ad6265SDimitry Andric 
53881ad6265SDimitry Andric     SmallVector<char, 0> Buffer;
53981ad6265SDimitry Andric     raw_svector_ostream MemStream(Buffer);
54081ad6265SDimitry Andric 
54181ad6265SDimitry Andric     Expected<const MachOConfig &> MachO = Config.getMachOConfig();
54281ad6265SDimitry Andric     if (!MachO)
54381ad6265SDimitry Andric       return MachO.takeError();
54481ad6265SDimitry Andric 
54581ad6265SDimitry Andric     if (Error E = executeObjcopyOnBinary(Config.getCommonConfig(), *MachO,
54681ad6265SDimitry Andric                                          **ObjOrErr, MemStream))
54781ad6265SDimitry Andric       return E;
54881ad6265SDimitry Andric 
54981ad6265SDimitry Andric     auto MB = std::make_unique<SmallVectorMemoryBuffer>(
55081ad6265SDimitry Andric         std::move(Buffer), ArchFlagName, /*RequiresNullTerminator=*/false);
55181ad6265SDimitry Andric     Expected<std::unique_ptr<Binary>> BinaryOrErr = object::createBinary(*MB);
55281ad6265SDimitry Andric     if (!BinaryOrErr)
55381ad6265SDimitry Andric       return BinaryOrErr.takeError();
55481ad6265SDimitry Andric     Binaries.emplace_back(std::move(*BinaryOrErr), std::move(MB));
55581ad6265SDimitry Andric     Slices.emplace_back(*cast<MachOObjectFile>(Binaries.back().getBinary()),
55681ad6265SDimitry Andric                         O.getAlign());
55781ad6265SDimitry Andric   }
55881ad6265SDimitry Andric 
55981ad6265SDimitry Andric   if (Error Err = writeUniversalBinaryToStream(Slices, Out))
56081ad6265SDimitry Andric     return Err;
56181ad6265SDimitry Andric 
56281ad6265SDimitry Andric   return Error::success();
56381ad6265SDimitry Andric }
564